Skip to content

fix: prevent Content-Type header from being set to 'false'#7035

Open
veeceey wants to merge 2 commits intoexpressjs:masterfrom
veeceey:fix/content-type-false-value
Open

fix: prevent Content-Type header from being set to 'false'#7035
veeceey wants to merge 2 commits intoexpressjs:masterfrom
veeceey:fix/content-type-false-value

Conversation

@veeceey
Copy link

@veeceey veeceey commented Feb 14, 2026

Fixes #7034

When res.set('Content-Type', value) is called with a value that mime.contentType() can't resolve (returns false), the header ends up being set to the literal string "false".

This happens because mime.contentType() returns false for unrecognized types, and that false gets passed straight to setHeader(), which coerces it to a string.

// before this fix:
res.set('Content-Type', 'custom-type');
// => Content-Type: false

The fix is a one-liner — fall back to the original value when mime.contentType() returns false. This is consistent with how res.type() already handles the same case (it falls back to 'application/octet-stream').

// after:
res.set('Content-Type', 'custom-type');
// => Content-Type: custom-type

Added a test to cover this edge case. Full test suite passes (1247 tests).

When res.set('Content-Type', value) is called with a value that
mime.contentType() cannot resolve, it returns false. This false
value was being passed directly to setHeader(), resulting in the
Content-Type header being set to the literal string "false".

Fall back to the original value when mime.contentType() returns
false, consistent with how res.type() already handles this case.

Fixes expressjs#7034
Copy link

@erdinccurebal erdinccurebal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean fix. The core issue is that mime.contentType() returns false for unrecognized types, which then gets set as the literal string "false" via setHeader.

The || value fallback is a good approach — it preserves the developer's original value when the MIME lookup fails, which is backwards-compatible.

One edge case to consider: mime.contentType('') returns false, so res.set('Content-Type', '') would set an empty string header instead of "false". This is arguably better behavior, but worth noting.

Also see #7036 which tackles the same issue with a stricter approach (throws TypeError). Both are valid — this one is safer for a patch release since it doesn't change the function's contract from "always sets a value" to "may throw".

Copy link
Member

@GroophyLifefor GroophyLifefor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, clean smart fix

.get('/')
.expect('Content-Type', 'custom-type')
.expect(200, done);
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
})
})
it('should preserve Content-Type value when mime lookup fails even has slash', function (done) {
var app = express();
app.use(function (req, res) {
res.set('Content-Type', 'custom-type/subtype');
res.end();
});
request(app)
.get('/')
.expect('Content-Type', 'custom-type/subtype')
.expect(200, done);
})

Since MIME types are closely related to slash based formats, adding a test case that includes a slash helps catch potential production issues before release.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the string passed to mime.contentType() contains a /, then it is treated as a mime type and returned as is (ref).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, that makes my additional test is unnecessary, thank you.

Copy link
Member

@GroophyLifefor GroophyLifefor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

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.

res.set('Content-Type') silently sets header to literal string 'false' for unknown types

5 participants