{"record":{"id":"fa02e024b98767fe","repo":"spring-projects/spring-boot","slug":"entry-would-be-written-to-this-is-outsi","errorCode":null,"errorMessage":"Entry '{}' would be written to '{}'. This is outside the output location of '{}'. Verify your target server configuration.","messagePattern":"Entry '(.+?)' would be written to '(.+?)'\\. This is outside the output location of '(.+?)'\\. Verify your target server configuration\\.","errorType":"exception","errorClass":"ReportableException","httpStatus":null,"severity":"critical","filePath":"cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java","lineNumber":119,"sourceCode":"\t\tbyte[] content = entity.getContent();\n\t\tAssert.state(content != null, \"'content' must not be null\");\n\t\ttry (ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(content))) {\n\t\t\textractFromStream(zipStream, overwrite, outputDirectory);\n\t\t\tfixExecutableFlag(outputDirectory, \"mvnw\");\n\t\t\tfixExecutableFlag(outputDirectory, \"gradlew\");\n\t\t\tLog.info(\"Project extracted to '\" + outputDirectory.getAbsolutePath() + \"'\");\n\t\t}\n\t}\n\n\tprivate void extractFromStream(ZipInputStream zipStream, boolean overwrite, File outputDirectory)\n\t\t\tthrows IOException {\n\t\tZipEntry entry = zipStream.getNextEntry();\n\t\tString canonicalOutputPath = outputDirectory.getCanonicalPath() + File.separator;\n\t\twhile (entry != null) {\n\t\t\tFile file = new File(outputDirectory, entry.getName());\n\t\t\tString canonicalEntryPath = file.getCanonicalPath();\n\t\t\tif (!canonicalEntryPath.startsWith(canonicalOutputPath)) {\n\t\t\t\tthrow new ReportableException(\"Entry '\" + entry.getName() + \"' would be written to '\"\n\t\t\t\t\t\t+ canonicalEntryPath + \"'. This is outside the output location of '\" + canonicalOutputPath\n\t\t\t\t\t\t+ \"'. Verify your target server configuration.\");\n\t\t\t}\n\t\t\tif (file.exists() && !overwrite) {\n\t\t\t\tthrow new ReportableException((file.isDirectory() ? \"Directory\" : \"File\") + \" '\" + file.getName()\n\t\t\t\t\t\t+ \"' already exists. Use --force if you want to overwrite or \"\n\t\t\t\t\t\t+ \"specify an alternate location.\");\n\t\t\t}\n\t\t\tif (!entry.isDirectory()) {\n\t\t\t\tFileCopyUtils.copy(StreamUtils.nonClosing(zipStream), new FileOutputStream(file));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfile.mkdir();\n\t\t\t}\n\t\t\tzipStream.closeEntry();\n\t\t\tentry = zipStream.getNextEntry();\n\t\t}\n\t}","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/spring-projects/spring-boot/blob/270dfe353fb830fd69b823a8a859287ff103854b/cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java#L101-L137","documentation":"Thrown by ProjectGenerator.extractFromStream as a Zip-Slip guard: a zip entry's resolved canonical path does not start with the output directory's canonical path, meaning the entry would escape the target directory. This is a security check against path traversal; the CLI refuses to write the entry.","triggerScenarios":"The downloaded project archive contains an entry name with path-traversal sequences (e.g. ../../etc/foo) that resolves outside the output directory.","commonSituations":"A compromised or misconfigured Initializr server serving a malicious archive; a server bug producing bad entry paths; an archive that uses absolute paths the guard correctly rejects.","solutions":["Do NOT bypass this check - it protects against path traversal","Verify the integrity and trustworthiness of the target Initializr service","Report the issue to the service operator","Use a different, trusted Initializr endpoint (e.g. https://start.spring.io)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// The guard is internal; callers cannot cheaply pre-check archive contents.\n// Mitigate by trusting the source: pin --target to a known-good Initializr.\n// If you handle the archive yourself, pre-scan entries:\njava.nio.file.Path out = outputDirectory.toPath().normalize();\nfor (java.util.zip.ZipEntry e : Collections.list(zip.entries())) {\n    java.nio.file.Path resolved = out.resolve(e.getName()).normalize();\n    if (!resolved.startsWith(out)) {\n        throw new SecurityException(\"Refusing path-traversal entry: \" + e.getName());\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    generator.generateProject(request, force);\n} catch (ReportableException ex) {\n    if (ex.getMessage().startsWith(\"Entry '\") && ex.getMessage().contains(\"outside the output location\")) {\n        // Do NOT retry with --force; the archive is unsafe.\n        Log.error(\"Server returned an unsafe archive (zip slip). Use a trusted Initializr.\");\n    }\n    throw ex;\n}","preventionTips":["Never disable or work around the zip-slip check","Only use trusted Initializr endpoints","Report repeated triggers to the service operator - it may be compromised"],"tags":["security","zip-slip","path-traversal","initializr","spring-boot-cli"],"backgroundTag":null,"analyzedSha":"270dfe353fb830fd69b823a8a859287ff103854b","analyzedAt":"2026-08-11T19:42:06.541Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}