Skip to content

fix(cadente): reject invalid request methods and targets, answer 431 on oversized headers - #52

Merged
CypherPotato merged 3 commits into
mainfrom
fix/cadente-request-validation
Oct 16, 2026
Merged

CypherPotato merged 3 commits into
mainfrom
fix/cadente-request-validation

Conversation

@CypherPotato

Copy link
Copy Markdown
Member

What

Three fixes in the Cadente HTTP/1.1 request parser:

  • Request target: any byte outside %x21-7E is now rejected (RFC 9112 §3.2). Previously bytes >= 0x80 and control characters were accepted and decoded with Encoding.ASCII, so GET /admin\x80x was served by the /admin route, and a LF inside the target forged extra lines in the error log. HttpListener answers 400 to these.
  • Request method: the method must be a token (RFC 9110 §5.6.2). Previously G\x01T, G@T or GET\x80 reached the core, where new HttpMethod(...) threw FormatException, producing a 500, an [unavailable request] log entry and an OnException call.
  • Header block larger than the 8 KB read buffer: Cadente now writes 431 Request Header Fields Too Large with Connection: close before closing, instead of dropping the connection silently.

Invalid methods and targets keep the existing failure semantics (parse failure, connection closed), consistent with the other parse errors in ParseHttpRequest.

Tests

Added to CadenteSecurityTests:

  • InvalidRequestLineBytes_AreRejectedBeforeHandler (8 cases: 0x80, ESC, LF, NUL, 0x7F in the target; 0x01, @, 0x80 in the method)
  • ValidRequestLine_StillReachesHandler (/a?b=c%20d, lowercase get, M-SEARCH)
  • OversizedHeaderBlock_RespondsWith431

Before the fix, the 8 invalid cases and the 431 test fail; after it they pass.

Full tests/Sisk.Core suite, run locally:

Engine Result
SISK_TEST_ENGINE=Cadente 280 passed, 6 skipped, 0 failed
SISK_TEST_ENGINE=Default 219 passed, 67 skipped, 0 failed

Notes

  • The 431 response is written directly to the stream as a fixed string. It is only reached when the buffer is full without a complete header block, so no request object exists yet.
  • Not changed, to keep this PR focused: control characters inside header names/values and bare LF handling.

…on oversized headers

Validate the request method as an RFC 9110 token and the request target
as %x21-7E (RFC 9112 section 3.2) before the request reaches the core.
Previously bytes such as 0x80, control characters and LF in the target
were accepted, and invalid method tokens caused a FormatException in the
core. Header blocks that exceed the read buffer now receive
431 Request Header Fields Too Large instead of a silent connection close.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T03:13:39.552083Z 02d1fb1 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11fc26cff8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


if (totalRead >= bufferLength) {
Logger.LogInformation ( $"failed to parse HTTP request: headers too large" );
await stream.WriteAsync ( "HTTP/1.1 431 Request Header Fields Too Large\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"u8.ToArray (), cancellationToken ).ConfigureAwait ( false );

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Prevent a second response after an oversized redirect request

When plain HTTP is sent to an HTTPS-configured listener, HttpHost.WritePlainHttpRedirectAsync calls this reader and treats every null result as a reason to call WriteHandshakeErrorAsync. An oversized header therefore writes this new 431 here and then immediately appends a complete 400 response on the same connection, despite the 431 declaring Content-Length: 0 and Connection: close. Clients that receive the first response can observe malformed extra response bytes; distinguish the oversized-header result or move the response decision to the caller.

Useful? React with 👍 / 👎.

@CypherPotato
CypherPotato merged commit 5feef98 into main Oct 16, 2026
5 checks passed
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.

1 participant