spring-projects/spring-boot · critical · ReportableException
Entry '{}' would be written to '{}'. This is outside the out
Error message
Entry '{}' would be written to '{}'. This is outside the output location of '{}'. Verify your target server configuration. What it means
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.
Source
Thrown at cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java:119
byte[] content = entity.getContent();
Assert.state(content != null, "'content' must not be null");
try (ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(content))) {
extractFromStream(zipStream, overwrite, outputDirectory);
fixExecutableFlag(outputDirectory, "mvnw");
fixExecutableFlag(outputDirectory, "gradlew");
Log.info("Project extracted to '" + outputDirectory.getAbsolutePath() + "'");
}
}
private void extractFromStream(ZipInputStream zipStream, boolean overwrite, File outputDirectory)
throws IOException {
ZipEntry entry = zipStream.getNextEntry();
String canonicalOutputPath = outputDirectory.getCanonicalPath() + File.separator;
while (entry != null) {
File file = new File(outputDirectory, entry.getName());
String canonicalEntryPath = file.getCanonicalPath();
if (!canonicalEntryPath.startsWith(canonicalOutputPath)) {
throw new ReportableException("Entry '" + entry.getName() + "' would be written to '"
+ canonicalEntryPath + "'. This is outside the output location of '" + canonicalOutputPath
+ "'. Verify your target server configuration.");
}
if (file.exists() && !overwrite) {
throw new ReportableException((file.isDirectory() ? "Directory" : "File") + " '" + file.getName()
+ "' already exists. Use --force if you want to overwrite or "
+ "specify an alternate location.");
}
if (!entry.isDirectory()) {
FileCopyUtils.copy(StreamUtils.nonClosing(zipStream), new FileOutputStream(file));
}
else {
file.mkdir();
}
zipStream.closeEntry();
entry = zipStream.getNextEntry();
}
}View on GitHub (pinned to 270dfe353f)
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)
Defensive patterns
Strategy: try-catch
Validate before calling
// The guard is internal; callers cannot cheaply pre-check archive contents.
// Mitigate by trusting the source: pin --target to a known-good Initializr.
// If you handle the archive yourself, pre-scan entries:
java.nio.file.Path out = outputDirectory.toPath().normalize();
for (java.util.zip.ZipEntry e : Collections.list(zip.entries())) {
java.nio.file.Path resolved = out.resolve(e.getName()).normalize();
if (!resolved.startsWith(out)) {
throw new SecurityException("Refusing path-traversal entry: " + e.getName());
}
} Try / catch
try {
generator.generateProject(request, force);
} catch (ReportableException ex) {
if (ex.getMessage().startsWith("Entry '") && ex.getMessage().contains("outside the output location")) {
// Do NOT retry with --force; the archive is unsafe.
Log.error("Server returned an unsafe archive (zip slip). Use a trusted Initializr.");
}
throw ex;
} Prevention
- 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
When it happens
Trigger: The downloaded project archive contains an entry name with path-traversal sequences (e.g. ../../etc/foo) that resolves outside the output directory.
Common situations: 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.
Related errors
- Invalid content received from server ({})
- No content received from server '{}'
- Failed to {} from service at '{}' ({})
- Initializr service call failed using '{}' - service returned
- Invalid service URL ({})
AI-assisted analysis of spring-projects/spring-boot@270dfe353f (2026-08-11).
Data as JSON: /api/errors/fa02e024b98767fe.
Report an issue: GitHub.