security(import): reject path-traversal filenames from ODS in MassImportService.processRows #530
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type: Security hardening (defense-in-depth)
Priority: P2-medium — current code accidentally safe; codify the constraint so a future refactor doesn't silently break it
Source: review of #526 by Nora "NullX" Steiner — comment #8648, finding 6
Parent PR: #526 (mass-import bind mount → first prod-reachable use)
Summary
Reject ODS-supplied filenames that contain path separators,
..segments, or absolute paths beforefindFileRecursiveruns. Today the impact is bounded by an implementation detail; this issue makes the constraint explicit and tested.Context
The ODS spreadsheet contains filenames in cells.
MassImportService.processRows(MassImportService.java:121) maps those cells to files viafindFileRecursive(filename)which walks/importand matches onp.getFileName().toString().equals(filename). Currently no validation that the spreadsheet-supplied filename is a plain name without separators or traversal segments.Today the impact is limited because
findFileRecursivematches ongetFileName().equals(...), so a cell value like../etc/passwdwould not match anything under/import(no file with that exact basename exists). But if anyone later refactorsfindFileRecursiveto use a path-join (which is the natural-looking thing to do), the protection silently disappears.With #526 making this prod-reachable, codifying the constraint now prevents that refactor from being a silent vulnerability.
Required
validateImportFilename(String)guard at the top ofprocessRows(or wherever the cell value is first read).nullor blank/or\(no path components)..segments.or..Paths.get(name).isAbsolute())skippedcounter introduced by #529 and log with sanitized SLF4J pattern.Acceptance criteria
findFileRecursive, not inside it (cheaper, more explicit)skippedcounter with #529 — no duplicate fieldLinked NFRs
Dependencies
ImportStatus.skippedfield with #529 — pick whichever lands first; the second reuses it.Definition of Ready
processRows, beforefindFileRecursive)🤖 Generated with Claude Code during /implement on #526