Skip to content

sanitizeHeader helper function for writeHeader echoes #1299

Description

@nigrosimone

res.writeHeader(key, value) writes key: value\r\n without looking at the value. A CR or an LF inside the value ends the header early, and everything after it is read by the client as more headers, or as a second response.

Node's http refuses the same value from setHeader with ERR_INVALID_CHAR, so a server that echoes a request value into a header is safe on node and split here.

Repro on v20.69.0, Node 26, nothing else involved:

uWS.App().get('/*', (res, req) => {
    res.writeHeader('x-echo', decodeURIComponent(req.getQuery('v') || ''));
    res.end('ok');
}).listen(9001, () => {});

Ask for /?v= with this value percent encoded:

a\r\nx-injected: yes\r\n\r\nHTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 25\r\n\r\n<script>alert(1)</script>

The wire answers two responses:

HTTP/1.1 200 OK
x-echo: a
x-injected: yes

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 25

<script>alert(1)</script>
Date: Sat, 15 Aug 2026 06:28:10 GMT
uWebSockets: 20
Content-Length: 2

ok

The header name is not checked either, so writeHeader(userInput, 'v') splits the same way. A lone LF also passes, and node's own client then rejects the whole response with HPE_CR_EXPECTED.

The request side is fine: uWS answers 400 to a CR or an LF in an incoming header, so this only happens with values the application puts there itself.

I know this is a low level API and a check per header costs something on a hot path. My point is that every framework built on uWS inherits this unless it validates on its own, and it is not written anywhere. Would you accept a check in writeHeader, or would a note in the README be better?

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions