A multipart original filename is caller-controlled metadata, not a safe path component.
Spring file uploads: discard the supplied filename before writing
The test sends traversal text
The accepted fixture upload declares ../../outside.csv. The controller never joins that value to the storage directory. It calls Files.createTempFile within a JUnit temporary root, returns only the generated basename and verifies the bytes exist at that resolved path. The test proves one path boundary in local storage. It does not prove a mounted production volume's permissions, symlink policy or cleanup schedule.
Ignore content type as an authority signal too. A second test labels HTML bytes text/csv; header validation rejects it before a file is created. A filename extension and a MIME declaration can both be chosen by the uploader. The format lesson describes the deliberately narrow byte check; the entrypoint stages only accepted bytes.
Separate public labels from storage keys
If users need to see their original filename, store a sanitized display label in a separate field with length and character bounds. Do not let it determine filesystem placement. Generate an opaque key for storage and keep an ownership record. On failure after creating a temporary file, delete it or mark it for cleanup; the fixture deletes its file on a write error but does not simulate disk failure.
Checked source
Path stored = Files.createTempFile(storage, "receipt-import-", ".csv");
try { Files.write(stored, content); }
catch (IOException failure) {
Files.deleteIfExists(stored);
throw failure;
}Verification boundary
MultipartReceiptImportTest.storesValidatedBytesUnderGeneratedName and MultipartReceiptImportTest.rejectsFakeCsvMediaTypeWhenBytesHaveWrongHeader in the downloadable Spring source kit. The excerpt is shortened; the kit contains the complete test.
Costs and limits
The path test runs in a temporary directory and uses a generated local file. It does not audit filesystem ACLs, symbolic links, object-store policies, malware scanning or file retention. Staging bytes costs disk space and must have a quota outside this fixture.
Common Mistakes
- Do not join getOriginalFilename() to a storage root.
- Do not accept a file because its extension says CSV.
- Do not expose an internal absolute path as the public upload identifier.
Read next
Spring MVC multipart receipt import: validate before storing, Spring CSV uploads: reject malformed UTF-8 and an unknown header, Spring MockMvc multipart tests: what the fixture proves.
