Application Security

Safe Filenames Across Path Traversal, Unicode, and Downloads

Separate display names from storage keys, normalize Unicode, remove path semantics, bound length, and generate Content-Disposition safely to prevent overwrite and UI deception.

The dangerous implementation is not one that never works. It is one that works in a demo and loses its boundaries under real networks and real data volume. A filename is user content, not a path. Servers use random object keys and retain display names only as metadata; operating systems disagree on separators, reserved names, and Unicode.

Security review starts with assets, attacker capability, and trust boundaries, then reauthorizes every state transition. Validation, rate limits, and audit complement rather than replace authorization.

Engineering boundaries and tradeoffs

This capability crosses clients, networks, and servers, so a local optimization can create a system failure. Decisions must constrain both endpoints, persisted truth, and operating budgets together.

  • Take a basename, remove controls and bidi overrides, normalize NFC, cap UTF-8 bytes while preserving extension, and emit an ASCII fallback plus RFC 5987 filename*.
  • Define success, degraded, cancelled, and failed terminal states before UI, storage, and metrics consume the same state.
  • Use explicit capability negotiation so older clients receive an explained fallback instead of a half-working state.

The delivery standard for Safe Filenames Across Path Traversal, Unicode, and Downloads is a usable normal path, convergent failures, bounded resources, and a state users can understand. The result is a production capability that can be explained, degraded safely, and rolled back—not a demo that works once.

How it fails in production

Production failures often appear when two individually valid actions overlap. Inspect stale messages, duplicate effects, exhausted resources, and mixed versions instead of patching only the current stack frame.

  • Joining names into upload paths enables traversal, canonically equivalent names bypass duplicate checks, and RTL controls disguise executable extensions.
  • Fixing only the UI leaves queues, locks, or expired credentials for the next operation to inherit and fail again.
  • User or task IDs in metric labels create high-cardinality cost and leak unnecessary identity into diagnostics.

Turn testing into a closed loop

A release gate combines deterministic regression, randomized timing, and real browser pairs. Preserve the seed and state trace from every failure as a permanent replay case.

  1. Test Windows reserved names, dot paths, mixed separators, NFD/NFC, long emoji, CRLF, and RTL names; storage stays isolated and headers cannot be injected.
  2. Run one hundred start, fail, retry, and cancel cycles; handles, listeners, queues, and temporary data must return to baseline.
  3. Use fault injection to prove alerts precede user reports and operators can locate the failing phase from bounded evidence.

The release standard is practical: the normal path is fast, abnormal paths converge, recovery never overrides an explicit user decision, and operators can diagnose faults from limited, privacy-safe evidence.

Put the guide to work

Open uCopy and connect two devices securely from the browser.

Start for free