flawopen.com/path-traversal/Kotlin
How unvalidated file paths in Kotlin/Ktor allow directory breakouts, and how to verify boundaries using Path.normalize and Path.startsWith.
Stellen Sie sich ein Hotelschloss vor, das eigentlich nur Zimmer im zweiten Stock öffnen soll. Wenn ein Gast am Tastenfeld '../../master-safe' eingibt, verlässt das Schloss den Flur und öffnet den Haupttresor des Hotelmanagers.
Web Application SecurityCWE-918 betroffen ist.CWE-918Defense-in-DepthEin Endpunkt akzeptiert Dateinamen oder Ressourcenbezeichner direkt über einen HTTP-Anfrageparameter.
Der Angreifer schleust relative Pfadsequenzen wie '../', '..%2f' oder absolute Pfadüberschreibungen ein.
Das Backend verbindet die Eingabe mit dem Basispfad, ohne kanonische Pfade aufzulösen oder Grenzen zu prüfen.
Das System öffnet und übermittelt vertrauliche Systemdateien (z. B. /etc/passwd oder Konfigurationsgeheimnisse).
// VULNERABLE: Direct File instantiation with user parameter
import java.io.File;
import javax.servlet.http.*;
public class FileServlet extends HttpServlet {
private static final File BASE_DIR = new File("/var/app/public/files");
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
String filename = req.getParameter("file");
// Attacker sends: ../../../../etc/passwd
File target = new File(BASE_DIR, filename);
// Directly serves arbitrary system file!
serveFile(target, resp);
}
}
// HARDENED: Canonicalize file and enforce directory prefix check
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import javax.servlet.http.*;
public class FileServlet extends HttpServlet {
private static final File BASE_DIR = new File("/var/app/public/files");
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String filename = req.getParameter("file");
if (filename == null || filename.isBlank()) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
// 1. Resolve canonical path (resolves .. and all symlinks)
File target = new File(BASE_DIR, filename).getCanonicalFile();
File canonicalBase = BASE_DIR.getCanonicalFile();
// 2. Strict boundary check using Java NIO Path
if (!target.toPath().startsWith(canonicalBase.toPath())) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Path traversal detected");
return;
}
if (!target.isFile()) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
serveFile(target, resp);
}
}
getCanonicalFile() on both target and base directory.target.toPath().startsWith(base.toPath()).target.isFile() to prevent reading device nodes or directories.ZipEntry.getName() before writing.