Repository navigation
Response header bytes past ASCII reach the client unchanged under Bun - #697
Merged
dannycochran merged 2 commits intoOct 12, 2026
Merged
Conversation
Bun's http.Server writes a response's head as a string with no encoding named
on a connection it is handed with emit('connection'), so the socket's default
applies. The proxy reads an upstream's headers as latin1, so as UTF-8 every
header byte from 0x80 up reached the client as two, on TLS-terminated tunnels
and through srt proxy. A socket about to be emitted gets latin1 as its
default, and a refusal's reason is written as bytes.
The rule against direct realpath calls and the one call that is made on purpose met on main.
dannycochran
deleted the
fix/response-header-bytes-past-ascii-under-bun
branch
October 12, 2026 17:13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bun's
http.Serverwrites a response's head as a string, and names no encoding, on a connection it is handed withemit('connection'). So the socket's default applies, UTF-8. The proxy reads an upstream's headers as latin1, one char per byte, so every header byte from 0x80 up reaches the client as two:e9asc3 a9, andc3 a9asc3 83 c2 a9.Locationis followed to another URL,Content-Dispositionnames another file,Set-Cookiecomes back changed.Affected, under Bun: TLS-terminated tunnels (since #665) and everything through
srt proxy(#666). Not affected: Node, plain HTTP through the full proxy, request headers, bodies. In no release.What changes (+23/-2)
The rule this makes: what the proxy itself writes to such a socket with no encoding named is bytes or ASCII. It is today. A header value with a char past 0xFF cannot be cut to a control byte: all three runtimes refuse it (
ERR_INVALID_CHAR) before anything is written.Why not otherwise
A
Bufferas a header value is refused on all three runtimes.setHeader,writeHeadand raw header arrays all double. Writing the head by hand means redoing the framing.Testing
curlin the real sandbox against a raw TLS upstream, on v0.0.79,mainand here, on Bun 1.4.2, Bun 1.4.3 and Node 22: here equals v0.0.79 on all three.mainagainst here: only the lines with high bytes differ.Also here
Three comment lines in
windows-sandbox-utils.ts:npx eslint .fails onmain, where a lint rule (#683) and a call made on purpose (#686) met. #688 and #689 carry the same lines, so any of the three can merge first.Not covered, seen on the way
ERR_HTTP_SOCKET_ASSIGNED). 1.4.3 is right.101from the upstream leaves the client unanswered, as in v0.0.79.