Skip to content

Reject control characters in filenames at the input boundary #265

Description

@dean0x

Assessed during #253 (CWE-150/CWE-117 hardening) and deliberately deferred as out of scope.

Context. #253 defends against hostile filenames by escaping at output: untrusted identifiers and filenames are WIRE-escaped on every surface that renders a diagnostic. That closed the reachable forgery paths, but it leaves two consequences:

  1. Every current and future output site has to remember to escape. A CI-enforced print-discipline guard (crates/mds-cli/tests/print_discipline.rs) now catches this within mds-cli, but it is a lexical check and cannot verify mds-core producers across the crate boundary — five eprint_warning sites are allowlisted on exactly that basis.
  2. It cannot cover functional path references. Source Map v3 file/sources and CompileResult.dependencies are emitted verbatim, because escaping them would point the map at a path that does not exist. fix: harden terminal-escape rendering across all MdsError variants (CWE-150) #253 documents this as a named carve-out with a normative "consumers MUST treat embedded paths as untrusted" contract (spec §7.5).

Proposal. Reject control characters in filenames at the input boundary instead — one fail-closed check at the directory walk and the @import path parser. A path that cannot carry the bytes cannot leak them through any output surface, which dissolves both consequences above, including the source-map carve-out.

Why it was deferred.

  • It is a breaking behavioural change: files that compile today would stop compiling.
  • It needs its own acceptance criteria deciding the allowed-character contract — POSIX-minimal (reject only / and NUL) versus a stricter allowlist.
  • It interacts with --out-dir output-name derivation.

Scope if taken up: the tree walk in crates/mds-cli/src/output.rs, the @import/@include path parser in mds-core, and the --out-dir name derivation. Would allow narrowing or removing the functional-path carve-out in spec §7.5.

Acceptance Criteria

  • Define the allowed-character contract (POSIX-minimal vs. stricter allowlist)
  • Reject control characters at the directory walk entry point in crates/mds-cli/src/output.rs
  • Reject control characters at the @import/@include path parser in mds-core
  • Handle --out-dir output-name derivation consistently with the new rule
  • Update or remove the functional-path carve-out in spec §7.5 accordingly
  • All existing tests pass; new tests cover the boundary rejection behaviour

Metadata

Metadata

Assignees

No one assigned

    Labels

    architectureArchitectural refactoringrustPull requests that update rust code

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions