{"record":{"id":"e45bf5d8e4863a03","repo":"perwendel/spark","slug":"external","errorCode":null,"errorMessage":"external","messagePattern":"external","errorType":"http","errorClass":"DirectoryTraversalDetection","httpStatus":400,"severity":"error","filePath":"src/main/java/spark/staticfiles/DirectoryTraversal.java","lineNumber":22,"sourceCode":"\nimport static spark.utils.StringUtils.removeLeadingAndTrailingSlashesFrom;\n\n/**\n * Protecting against Directory traversal\n */\npublic class DirectoryTraversal {\n\n    public static void protectAgainstInClassPath(String path, String localFolder) {\n        if (!isPathWithinFolder(path, localFolder)) {\n            throw new DirectoryTraversalDetection(\"classpath\");\n        }\n    }\n\n    public static void protectAgainstForExternal(String path, String externalFolder) {\n    \tString unixLikeFolder = unixifyPath(externalFolder);\n        String nixLikePath = unixifyPath(path);\n        if (!isPathWithinFolder(nixLikePath, unixLikeFolder)) {\n            throw new DirectoryTraversalDetection(\"external\");\n        }\n    }\n    \n    private static String unixifyPath(String path) {\n    \treturn Paths.get(path).toAbsolutePath().toString().replace(\"\\\\\", \"/\");\n    }\n    \n    private static boolean isPathWithinFolder(String path, String folder) {\n    \tString rlatsPath = removeLeadingAndTrailingSlashesFrom(path);\n    \tString rlatsFolder = removeLeadingAndTrailingSlashesFrom(folder);\n    \treturn rlatsPath.startsWith(rlatsFolder);\n    }\n\n    public static final class DirectoryTraversalDetection extends RuntimeException {\n        private static final long serialVersionUID = 1L;\n\n        public DirectoryTraversalDetection(String msg) {\n            super(msg);","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/perwendel/spark/blob/1973e402f5d4c1442ad34a1d38ed0758079f7773/src/main/java/spark/staticfiles/DirectoryTraversal.java#L4-L40","documentation":"DirectoryTraversal.protectAgainstForExternal guards Spark's external static-file folder: after unixifying both the requested path and the external folder to absolute paths, it checks the path stays within the folder. If it does not, Spark throws DirectoryTraversalDetection with the message \"external\", signaling a blocked attempt to escape the external directory.","triggerScenarios":"A request for an external static file whose resolved path (after normalization via Paths.get(...).toAbsolutePath()) lies outside the configured external static files folder, e.g. ../ traversal sequences against staticFiles.externalLocation(\"/var/www/static\").","commonSituations":"Attackers or scanners probing external static endpoints with ../../ sequences; misconfigured client links using absolute or upward-relative paths; platform-specific separators (\\\\) that resolve unexpectedly.","solutions":["Find and fix the request/link that references paths outside the external folder.","Ensure all served content physically resides under the configured external location (no symlinks escaping it).","Treat repeated occurrences as attack traffic: add rate limiting or WAF rules for traversal patterns."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"Path root = Paths.get(externalFolder).toAbsolutePath().normalize();\nPath candidate = Paths.get(path).toAbsolutePath().normalize();\nboolean safe = candidate.startsWith(root);","typeGuard":null,"tryCatchPattern":"try {\n    DirectoryTraversal.protectAgainstForExternal(path, externalFolder);\n} catch (DirectoryTraversalDetection e) {\n    respond(403, \"Forbidden\");\n}","preventionTips":["Serve only files physically located under the external folder.","Normalize incoming paths client-side; reject absolute or upward-relative paths.","Add WAF rules for encoded traversal sequences (%2e%2e, ..%2f)."],"tags":["security","directory-traversal","static-files","spark"],"backgroundTag":"path-traversal-blocked","analyzedSha":"1973e402f5d4c1442ad34a1d38ed0758079f7773","analyzedAt":"2026-09-10T14:38:22.866Z","contentChangedAt":"2026-09-10T14:38:22.866Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}