Skip to content

fix: decode WHATWG-escaped characters in file originalname (#836)#1421

Open
webdevelopersrinu wants to merge 1 commit into
expressjs:mainfrom
webdevelopersrinu:fix/originalname-decoding
Open

fix: decode WHATWG-escaped characters in file originalname (#836)#1421
webdevelopersrinu wants to merge 1 commit into
expressjs:mainfrom
webdevelopersrinu:fix/originalname-decoding

Conversation

@webdevelopersrinu

Copy link
Copy Markdown

What & why

Fixes #836.

Browsers escape the bytes 0x0A (LF), 0x0D (CR) and 0x22 (") as
%0A, %0D and %22 when serialising a filename in a
multipart/form-data body, per the WHATWG HTML spec. Busboy leaves
them escaped, so a file uploaded as file".ext was exposed on
req.file.originalname as file%22.ext.

Change

  • Decode exactly those three sequences when building the file object in
    lib/make-middleware.js.
  • Only these three are decoded on purpose — a bare % is never escaped
    by the spec, so a full decodeURIComponent would corrupt legitimate names
    like 50%off.pdf. A dedicated test guards this.

Reproduction (before)

Uploading a file named file".ext

req.file.originalname === 'file%22.ext' // ❌ before
req.file.originalname === 'file".ext' // ✅ after

Tests

Adds test/filename-decoding.js covering:

  • escaped double quote (%22)
  • escaped CR + LF (%0D, %0A)
  • an unescaped filename (unchanged)
  • preservation of a literal percent sign (50%off.ext)

All pass; standard lint is clean. Targeting the 2.x line as discussed on
the issue.

Browsers escape the bytes 0x0A (LF), 0x0D (CR) and 0x22 (") as %0A, %0D
and %22 when serialising filenames in a multipart/form-data body, per the
WHATWG HTML spec. Busboy leaves them escaped, so a file named `file".ext`
was exposed as `file%22.ext` on `req.file.originalname`.

Reverse exactly those three sequences when building the file object. Only
these are decoded on purpose: a bare `%` is never escaped by the spec, so
a full decodeURIComponent would corrupt legitimate names like `50%.pdf`.

Adds regression tests covering the escaped quote, CR/LF, an unescaped
name, and preservation of a literal percent sign.

Fixes expressjs#836
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

originalname is not properly decoded

1 participant