fix(path): reject Windows reserved basenames in sanitizeUntrustedFileName - #67
fix(path): reject Windows reserved basenames in sanitizeUntrustedFileName#67SebTardif wants to merge 1 commit into
Conversation
…Name Reuse the device-path reserved-name set so untrusted names like CON, NUL.txt, and COM1 fall back instead of staging as Windows devices. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
|
Codex review: needs maintainer review before merge. Reviewed July 30, 2026, 7:51 AM ET / 11:51 UTC. ClawSweeper reviewWhat this changesThe PR makes Merge readinessThis PR still addresses a distinct missing hardening step and has credible after-fix runtime proof. It is not safe to close as implemented because the supplied context does not establish that current Priority: P2 Review scores
Verification
How this fits together
flowchart LR
A[Untrusted filename] --> B[Basename extraction]
B --> C[Portable filename sanitizer]
C --> D{Reserved Windows device name?}
D -->|Yes| E[Caller fallback filename]
D -->|No| F[Sanitized safe basename]
E --> G[Staging and output helpers]
F --> G
Before merge
Agent review detailsSecurityNone. Review metrics
Root-cause clusterRelationship: Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge-risk optionsMaintainer options:
Copy recommended automerge instructionTechnical reviewBest possible solution: Refresh the focused guard against current Do we have a high-confidence way to reproduce the issue? Yes, at source level: the supplied regression test defines the failing reserved-basename path and the PR includes built-package terminal output showing the corrected behavior. Independent local execution was not available because the sandbox command runner failed before it launched a shell. Is this the best way to solve the issue? Yes: reusing the existing reserved-device normalization is narrower and less likely to drift than maintaining another reserved-name list in the filename sanitizer. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against ab933820c089. LabelsLabel justifications:
EvidenceWhat I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (1 earlier review cycle)
|
What Problem This Solves
Fixes an issue where consumers using
sanitizeUntrustedFileName()(via staging, external output, and sibling-temp helpers) would accept Windows reserved device basenames such asCON,NUL.txt, orCOM1from untrusted input. On Windows those names open devices rather than ordinary files, which breaks portable name sanitization already used for C0/C1 and Windows-invalid characters on every host.Why This Change Was Made
Reuse the reserved-name set and normalization already used by the device-path read guards (
isWindowsReservedDeviceBaseName) insidesanitizeUntrustedFileName(). Reserved basenames (including extensions and trailing spaces/dots) return the caller-supplied fallback. Non-goals: changing path resolution or read guards; only the untrusted basename sanitizer.User Impact
Callers that pass reserved basenames now receive the same fallback they already get for empty,
., or..names. Valid names such asconsole.txtandnull.pdfare unchanged. No public API signature changes.Evidence
Red / green
pnpm exec vitest run test/filename.test.tsfailed withexpected 'CON' to be 'fallback.bin'before the production change.pnpm check(598 passed, 22 skipped).Runtime sample (built
dist/)Checklist
CHANGELOG.mdupdated when release-relevantRelated
Real behavior proof
Behavior or issue addressed: Untrusted basenames that are Windows reserved devices must not pass through
sanitizeUntrustedFileName; they must fall back.Real environment tested: macOS arm64, Node from repo toolchain,
@openclaw/fs-safebranchfix/windows-reserved-basenamesafterpnpm build.Exact steps or command run after this patch:
Evidence after fix: reserved cases map to
fallback.bin; non-reservedconsole.txtkept; full check green.Observed result after fix:
sanitizeUntrustedFileName('CON', 'fallback.bin') === 'fallback.bin'and siblings; staging helpers inherit the safer basename policy.What was not tested: Live Windows NTFS create of reserved names (behavior is documented OS semantics; this PR blocks the name before open).