Http4s Ember and Traefik parser, header, and route authority boundaries (19 GHSAs)¶
Source: hourly offensive-security scan of GitHub Security Advisories on 2026-09-15 (waves published 2026-09-10T20:25Z–2026-09-15T20:01Z).
Two reviewed-parser clusters landed the same week and share one operator rule: a front-end security decision is only as strong as the framing, header-grammar, and path-normalization agreement between the proxy layer and the backend parser. Both Http4s Ember (Scala HTTP server/client) and Traefik published advisories where the security-relevant view of a request diverges from what the backend actually receives.
Advisory table¶
Http4s Ember (org.http4s, fixed 0.23.35 / 1.0.0-M47):
| GHSA | CVE | Sev. | Boundary |
|---|---|---|---|
| GHSA-8h4c-x2wg-6xp8 | CVE-2026-69204 | critical | CL.TE: Transfer-Encoding + Content-Length accepted instead of framed as an error (RFC 9112 §6.1) → smuggling behind CL-strip-and-forward intermediaries |
| GHSA-9998-894r-fwvr | CVE-2026-69205 | high | TE.CL/TE.0: Transfer-Encoding value matched by case-sensitive substring (contains("chunked")) — Transfer-Encoding: Chunked frames by Content-Length while a compliant intermediary frames by chunked |
| GHSA-jrpm-956j-96jg | CVE-2026-69216 | medium | TE.TE: chunk-size token accepts whitespace and +/- sign outside RFC 9112 1*HEXDIG grammar |
| GHSA-crq5-92j2-j7wv | CVE-2026-69201 | medium | ResourceService/WebjarService reject exact ./.. segments only after per-segment decode — %2F..%2F smuggles traversal past the filter (and %5C on Windows) |
| GHSA-grh8-3p95-f9rr | CVE-2026-69215 | medium | Client CookieJar attaches cookies by unanchored substring host test — cookie for example.com sent to evilexample.com |
| GHSA-wv64-j4fq-5f9x | CVE-2026-69214 | medium | CookieJar trusts server-supplied Domain verbatim (no domain-match, no public-suffix check) → cross-domain cookie plant/fixation |
| GHSA-9xww-74xv-gjfp | CVE-2026-69206 | medium | DigestAuth stores lastNc + 1 instead of the accepted nc — captured Authorization headers replay multiple times |
| GHSA-fm4g-76c9-7w69 | CVE-2026-69208 | high | DigestAuth nonce map grows unbounded (tracked, availability) |
| GHSA-gq9p-f254-h286 | CVE-2026-88975 | high | HTTP/2 buffers a frame's declared payload before checking SETTINGS_MAX_FRAME_SIZE (tracked) |
| GHSA-cp4q-fqw9-4hf6 | CVE-2026-69218 | high | HTTP/2 unbounded continuation-frame accumulation (tracked) |
| GHSA-6m4x-pp6q-5jmm | CVE-2026-69202 | high | HTTP/2 unbounded inbound body buffering (tracked) |
| GHSA-8f3q-3jmv-7prw | CVE-2026-69213 | high | HTTP/2 unbounded outbound frame queue driven by cheap control frames (tracked) |
| GHSA-9vwc-pc8p-253q | CVE-2026-69203 | high | HTTP/2 SETTINGS_MAX_CONCURRENT_STREAMS not enforced (tracked) |
Traefik (fixed 3.7.12/3.7.13 and 2.11.56/2.11.57) — follow-up records on the existing Traefik route, transport, and namespace authority boundaries page:
| GHSA | CVE | Sev. | Boundary |
|---|---|---|---|
| GHSA-f52w-8j3h-j724 | CVE-2026-88009 | high | Rootless (opaque) HTTP/1 request-target: Go parses GET http:http://internal/admin into URL.Opaque with empty Path; router, path sanitization, forwardAuth path scoping, and access logs all see /, while the proxy forwards the original target byte-for-byte to the backend |
| GHSA-w4v4-9rw7-5326 | CVE-2026-88008 | high | Client Upgrade: h2c + HTTP2-Settings forwarded; a backend that answers 101 puts Traefik into a raw byte tunnel that bypasses routers and the entire middleware chain |
| GHSA-v67p-phpq-fc8x | CVE-2026-88004 | high | Entrypoint header sanitization (aliasHeadersStrategy, underscoreHeadersStrategy, forwardedHeaders stripping) scans req.Header only, never req.Trailer — spoofed trusted headers smuggled as chunked/HTTP2 trailers |
| GHSA-qqjf-53cj-pwvv | CVE-2026-88007 | critical | HTTP/3 path never initializes the connection-scoped backend transport holder, so Kerberos/NTLM backends share one connection-bound transport across frontend connections → cross-user credential binding reuse |
| GHSA-rf44-j88r-hh8c | CVE-2026-88011 | medium | ForwardAuth identity spoofing via dot-form header alias (X.Auth.User vs X-Auth-User): Go canonicalizes dashes only, CGI/WSGI/PHP/NGINX backends collapse all spellings to one variable |
Adjacent (tracked, no operator page): GHSA-5hq8-qhww-jm7q libp2p-quic remote panic via certificate-expiry race during QUIC handshake.
Why this is worth an operator page¶
- These are the exact primitive grammars every smuggling engagement re-derives from scratch. Ember documents three independent framing divergences (CL.TE, TE.CL via case-sensitivity, TE.TE via chunk-size lenience) and Traefik adds two request-grammar divergences (opaque request-target, trailer-sourced headers) that are rarely in standard wordlists.
- The rootless request-target is the highest-value single record: routing and path-scoped authz evaluated against a normalized
/while the backend receives the raw target is a router/authz bypass channel, not just a cache-poisoning curiosity. - Trailer-sourced trusted headers are an under-tested surface on any proxy — the sanitizer iterates the header map, the backend (or a framework that merges trailers) sees them as fields.
- Header-name alias collapsing (dot/underscore/dash) is the same parser-differential axis as the August 5 Traefik underscore-alias records; backends that derive variables from names collapse spellings the proxy treats as distinct.
Validation workflow (authorized scope only)¶
Lab backends and single-connection canaries only
Test only against owned stacks in authorized scope. Use single-connection, self-contained canaries (one request, one response marker), never cross-user desync, cache poisoning of shared entries, or auth-boundary mutation on production. Record raw bytes on both sides of the proxy.
- Framing differential harness. For each origin behind each intermediary, send one connection with:
Transfer-Encoding: chunked+Content-Length(CL.TE);Transfer-Encoding: Chunked(case),chUnKeD, obfuscating whitespace variants (TE.CL);+5,5, signed chunk sizes (TE.TE); and the opaque-form request-targetGET http:http://<owned-vhost>/admin HTTP/1.1. Compare the two views: what the front normalizes/routes vs the raw target/body the backend echoes from an owned no-op route. - Trailer smuggle probe. Send a chunked request whose final chunk carries
X-Forwarded-Prefix/X_Auth_User/X.Auth.Usertrailers; confirm whether the backend framework surfaces them as request headers or variables. Evidence is the echoed field name/value, not a privilege change. - Static-route decode check. Request
/%2F..%2F..%2F<canary>and%5Cvariants against static handlers; prove only with synthetic classpath/resource canaries outside the configured base — never config files or key material. - Client-side cookie jar audit (for Scala services acting as SSRF-capable fetchers): verify domain-match anchoring with two owned hosts (
owned-a.examplevsxowned-a.example) and a server that answersSet-Cookie: ...; Domain=owned-b.example. - Report only framing/decision mismatch evidence with raw-byte captures; stop at the boundary.
September 16 follow-up: Traefik HTTP/3 silently drops response timeouts (GHSA-7ghq-v6jf-g56c)¶
respondingTimeouts.readTimeout (default 60s, documented as bounding the time to read the full request including body) is not applied to HTTP/3 entry points. The deadline is enforced on the TCP connection, which cannot reach a QUIC stream, and Traefik's HTTP/3 server was constructed with no timeout at all. An unauthenticated client trickling a request body at negligible cost holds one request — and one upstream connection per request — open indefinitely; backends with bounded connection pools are the pressure point. Regression window: v2.8.2 onward (a quic-go API change removed the embedded http.Server that carried the timeouts); affected lines v2.8.2–v2.10.x and v3.0–v3.6 are unpatched on-line, fixes land in v2.11.56 / v3.7.12.
Operator value:
- Timeout-config parity across transports is a testable invariant. On any proxy in scope, send one slow-drip body canary on HTTP/1.1, HTTP/2, and HTTP/3 to an owned no-op route and compare when the proxy gives up. A timeout configured and echoed in config but unenforced on one protocol is the finding — the same "validated on one path, enforced on none" axis as the header/framing items above.
- Version fingerprinting beats config assumptions: v2.8.2+ through the fix releases all silently ignore the documented behavior, and most maintained lines carried it for years. Capture protocol negotiation, config excerpt, and both transports' deadline behavior in the evidence set.
- Keep any slow-body check to a single self-contained connection against an owned route; the DoS class is real but the durable report is the enforcement gap, not resource exhaustion on a shared front-end.
September 17 follow-up: Sanic chunked-trailer smuggling and oRPC reflected Vary (2 GHSAs)¶
GHSA-wmj6-g64g-j7q5 / CVE-2026-85078: Sanic's HTTP/1.1 chunked handling does not fully consume the trailer-part after the terminating 0\r\n chunk, so attacker bytes left in the connection buffer are parsed as the start of a new request on the keep-alive connection. The verified PoC produces two responses from one TCP send: the expected 405 for the outer POST / plus a 200 OK for a GET / hidden in the trailer area; changing the leftover GET to :GET shifts the second response accordingly, proving trailer-consumption error rather than legitimate pipelining.
Operator value: this extends the framing battery above with a fourth primitive grammar — post-terminal-chunk leftover bytes (0\r\na:GET /admin ...). It is distinct from CL.TE/TE.CL/TE.TE: the outer request frames correctly, so validators and intermediaries that only reconcile Content-Length vs Transfer-Encoding see nothing anomalous. Test one self-contained connection per origin: chunked body terminated by 0\r\n followed by a short trailer-name-prefixed request line, and count response blocks on the socket. Evidence is two response blocks from one send against an owned route — never cross-user desync or cache mutation.
GHSA-j9v4-rhgr-4m5f / CVE-2026-77360: the oRPC CORS plugin copied the request's Vary header onto the response instead of treating Vary as response-only, letting a client inject arbitrary cache-key directives into shared caches/CDNs in front of the server and skew CORS enforcement for other clients (fixed @orpc/server 1.14.8). Validation stays lab-only and passive: send one request with an inert Vary: X-Owned-Canary to an owned endpoint behind an owned caching layer and record whether the value survives into the cached response's header map — header-survival evidence only, no poisoning of shared entries. Reusable axis: response headers that steer cache keys (Vary, cache-control passthroughs) must never be sourced from the request — same request-to-response reflection family as the header-alias items above.
September 17 follow-up: RabbitMQ amqp091-go frame desync and URI re-parse confusion (2 GHSAs)¶
The 2026-09-17T17:04Z amqp091-go publication batch adds two protocol-grammar records that extend the framing-divergence battery to AMQP wire parsing:
- GHSA-c5pq-fr2g-9jpf:
readLongstraccepts a length field above0x7FFFFFFFand takes a silent-error path that returns("", nil)without consuming the declared bytes. The reader cursor never advances, soreadTablekeeps iterating with broken alignment — subsequent attacker payload bytes are reinterpreted as AMQP frame headers. This is a server-to-client desync: a malicious AMQP server (or MitM on a non-TLS amqp:// leg) riding a client into parsing attacker-chosen frames; the durable test is that error paths in length-prefixed parsers must consume-or-abort, never return success with unconsumed input. Audit rule for any length-prefixed codec you consume: send a maximal/negative/overflow length and check whether the connection terminates or continues with a shifted cursor — frame-injection state is the positive, not a crash. - GHSA-465g-fh3v-9jw4: TLS cert/key paths are appended to the connection URI query string by string concatenation without
url.QueryEscape; a path containing&/=(e.g. from an env-sourced or workflow-sourced filename) injects additional query parameters that overwrite legitimate settings when the URI is re-parsed viaParseURI— later-wins lets an attacker-controlled value replacekeyfile/other config. Same serialize→re-parse round-trip family as the rclone archive-join and Netty delimiter items: values must be escaped for the container they are embedded in, and any build-string-then-reparse pipeline is an injection surface. Proof pattern: a lab URI whose cert-path segment carries a¶m=canaryfragment, evidence is the parsed struct's overwritten field.
Tracked from the same batch without promotion: PLAIN credentials retained in exported PlainAuth struct fields (log/APM leak hygiene, no remote boundary), QoS signed-to-unsigned casting, missing TLS minimum version, sub-spec frame-size DoS, unbounded body allocation DoS, malformed field-length DoS.
September 21 follow-up: Quarkus security-matcher vs dispatcher path-normalization split (GHSA-pw2v-hfg7-72m6)¶
GHSA-pw2v-hfg7-72m6 / CVE-2026-87743 (CVSS 7.5, Quarkus HTTP security, published 2026-09-18, surfaced via the updated feed 2026-09-21): the security annotation matcher and the JAX-RS/request dispatcher normalize paths differently — craft a URL the security matcher classifies as public that the dispatcher then routes to a protected endpoint → authorization bypass.
- This is the Quarkus instance of this page's standing rule: the security decision and the routing decision are two parsers over the same path string, and any divergence in percent-decoding count, trailing-slash, double-slash, matrix-parameter (
;jsessionid=-style), or case handling between them is the bypass. - Replayable battery on any framework where authz matching ≠ dispatch (already proven on Sanic, Traefik StripPrefix, Keycloak versioned route families, Airflow alternate mounts): for each protected route, request the same handler via
%2e,%252e,//,/;/,/., trailing/, mixed-case segment, and suffix-extension forms; the positive is matcher-verdict(public) × dispatcher-route(protected handler response). Capture both verdicts — a 401/403 on every variant is only a negative if the protected handler is proven reachable by the baseline path in the same session. - Framework-fingerprint first: Quarkus reveals itself via
/q/health,/q/metrics,/q/openapi(unauthenticated by default on many builds) — those endpoints double as the version/recon probe before the normalization battery.
September 22 follow-up: Traefik BasicAuth singleflight reintroduces a concurrency-only timing oracle + Tinyauth case-mismatch ACL (2 GHSAs)¶
- Traefik v3.6.11–3.7.12 BasicAuth username-enumeration oracle (CVE-2026-88010, GHSA-8fcf-v89g-xpg6, fixed 3.7.13): the middleware coalesces concurrent credential checks via a
singleflight.Group, and since v3.6.11 the dedup key was built from the submitted password plus the stored secret — so a nonexistent username collapses onto one shared key while each real username gets its own. Fire a leader request plus probe requests inside the in-flight window: probes for existing usernames compute their own bcrypt (slow), probes for non-existent ones get served the leader's coalesced result (fast). Unauthenticated username enumeration — only under concurrency; the earlier sequential-probe oracle (GHSA-g3hg-j4jv-cwfr) was already hardened. Two operator rules: (1) when a prior timing fix exists, retest the same control under concurrency — cache/dedup/coalescing layers re-open the oracle the fix closed, and the dedup key's composition is the leak; (2) for enumeration against Traefik-fronted apps on 3.6/3.7, the battery is concurrent-burst probes (leader + followers on the same password), not sequential latency diffs. Positive evidence class: bimodal response-time distribution keyed on candidate usernames, captured against a lab Traefik with a known secret — no credentials needed beyond arbitrary submitted pairs. - Tinyauth forward-auth per-app ACL case mismatch (CVE-2026-77560, GHSA-328g-jx67-v94g, fixed 5.1.2): the per-app allowlist (
users/groups/ip) matches the app hostname case-sensitively while hostnames resolve case-insensitively — request the app via a mixed-case host and the ACL lookup misses and fails open. Joins the case-sensitivity pair-sweep rule (Caddyhidevs APFS/NTFS, Sept 18): every case-sensitive string matcher over a case-insensitive namespace (hostnames, file paths, SQL identifiers) gets a mixed-case probe, and the ACL/allowlist family specifically needs the misses-and-defaults-allow test — a failed lookup that permits is worse than one that denies.
October 2 follow-up: Anubis bot-protection bypass via client-supplied X-Original-URI (GHSA-6wcg-mqvh-fcvg / CVE-2026-62314)¶
Anubis (the challenge-based bot/proxy-protection middleware) v1.22.0–v1.25.0 lets any HTTP client skip the challenge entirely with one request header: the policy PathChecker reads X-Original-URI from the request, and if that header value matches a path-only ALLOW rule, the request is forwarded upstream with no challenge and no JWT check. The default policy ships path-only ALLOW rules (^/\.well-known/.*$ in keep-internet-working.yaml), so the bypass works on the default configuration — the advisory's own PoC is curl -H "X-Original-URI: /.well-known/x" https://target/ returning the real site title instead of the challenge page. The middleware chain never strips the header, and in reverse-proxy mode the attacker fully controls it (fixed 1.26.0 by stripping inbound).
Operator value for bug hunters and proxy-behind assessments:
- This is the forged internal-routing header family (X-Original-URL, X-Rewrite-URL, X-Forwarded-Path, X-Original-URI) applied to a policy engine instead of a router: any middleware that trusts a header naming "the original request" lets the client choose which policy bucket it is evaluated in. Standing sweep on every challenge/WAF/authz middleware: replay the same request with each known original-URI header variant set to an allowlisted path (
/.well-known/,/health,/robots.txt); the positive is real upstream content with no challenge cookie issued — a one-line test with byte-evidence (challenge page title vs origin title). - Fingerprint Anubis itself before testing: challenge-page interstitial,
/chipfavicon mutation,status: 451on block. Default-config ALLOW rules are enumerable from the public repo — the bypass regex list is public, so test all of them. - Same request-to-policy decoupling as the Sept 21 Quarkus matcher-vs-dispatcher and Oct 1 APISIX non-canonical-path items: the policy parser and the routing decision must judge the same normalized target; a header that re-labels the target for only one of them is the bypass.
October 5 follow-up: Fiddler Classic as a smuggling victim — the connection pool is the cross-user channel (2 GHSAs)¶
The Telerik Fiddler Classic <6.0.20262.10021 advisories are the desktop-debug-proxy instance of this page's framing-differential class, with one genuinely new channel: the attacker and the victim share a local intercepting proxy instance, and the proxy's own pooled upstream connections carry the smuggled state between them.
- CL.TE desync with response-pool poisoning (GHSA-p3gc-87rm-gmjp / CVE-2026-77802, medium): Fiddler forwards duplicate conflicting
Content-Lengthheaders verbatim to the origin while framing the request body with only the first value. Against a non-RFC-9110-compliant keep-alive origin that parses the secondContent-Length, this smuggles an additional request. The durable part is the readback leg: Fiddler returns the server connection to its pipe pool after reading only the first response, so the unread smuggled response stays buffered on the socket and is served to the next session that reuses that connection — response poisoning and cross-user response disclosure through the pool, not through the origin cache. - Front-end TE+CL desync, no vulnerable server needed (GHSA-xq67-hr2w-mm32 / CVE-2026-77803, low): a request carrying both
Content-LengthandTransfer-Encodingis forwarded with both headers present while Fiddler frames the body viaTransfer-Encodingonly — the leftoverContent-Length-framed bytes are parsed as a second pipelined request on the reused client connection. One malformed request becomes two forwarded requests entirely inside the client→proxy edge; the origin never sees the anomaly as one request.
Operator value:
- Audit every proxy/interceptor you run or encounter for header-forwarding vs framing parity: does it forward ambiguous
Content-Length/Transfer-Encodingcombinations verbatim while resolving the framing itself with first-value or TE-only rules? The mismatch (forward-verbatim, frame-locally) is the reusable vulnerability shape, present here in both legs. - Connection-pool readback is a distinct desync impact channel. On shared proxies (corporate boxes, shared dev workstations, CI egress proxies), one attacker's smuggled response survives into another user's session because the pool returns the connection before draining it. When testing an authorized shared proxy, evidence class = one self-contained canary connection producing a response that a second lab session receives; never weaponize against real co-users.
- Debug proxies are in-scope parser targets, not trusted infrastructure: run the page's existing CL.TE/TE.CL/TE.TE/post-terminal-chunk battery against the proxy itself (loopback-owned origin) as part of toolchain assessments; the two-response-blocks-from-one-send positive applies at the client→proxy edge exactly as at the proxy→origin edge.
October 6 follow-up: identity-parser differentials — proxy-addr trust-subnet math, PyMongo decode-before-split, Werkzeug device names (3 GHSAs)¶
- proxy-addr treats
::ffff:10.0.0.0/8as match-everything (GHSA-jqcg-44mw-7w3h / CVE-2026-90711, 9.1): writing an IPv4 trust subnet in IPv4-mapped IPv6 notation with a short prefix (::ffff:10.0.0.0/8instead of the correct/104) compiles with all-zero leading bits and matches every IPv4 address — every client is then a trusted proxy at hop 0, so Expressreq.ip/req.ipsreturn attacker-chosenX-Forwarded-Forvalues. No error at boot; the same block written in plain IPv4 behaves correctly, so the misconfiguration is invisible from the config file. Operator value: XFF-spoofability probe belongs on every Express/Node app behind IP-based authz, rate limits, or geo-gates — sendX-Forwarded-For: 10.0.0.1from a public host and diff the access-control decision; a flipped decision means the trust subnet compiled wrong (or the app trusts the proxy list transitively). This is the header-trust sibling of the page's Anubis X-Original-URI leg: the client steers which policy bucket it is evaluated in — here by forging hop 0 itself. Also a config-audit grep for engagements with repo access:::ffff:prefixes with/[0-9]{1,3}\bprefix lengths under 96. - PyMongo percent-decodes the host section before splitting on
,/:(GHSA-vp6j-j7w5-5xjj / CVE-2026-96748, 6.5):%2C/%3Ainside a hostname fragment survive app-layer URL-safety checks and become real seed-list delimiters inside the driver's parser — one app-visible hostname becomes two hosts, and the second can be attacker-infrastructure (topology discovery + auth against it = credential exposure). Decode-order split rule: anywhere untrusted input is interpolated into a connection string, test encoded delimiters — the parser that decodes-then-splits sees a different grammar than the validator that splits-then-decodes. Same dependency-vs-handler parse split as the Airflowint()-vs-pydantic leg, moved into the URI layer. - Werkzeug
safe_joinpasses Windows device names with empty-ADS markers (GHSA-g6x2-hccm-hh4m / CVE-2026-102598): the prior device-name filter missedNUL:-style empty-ADS spellings on NTFS —send_from_directoryopens the device and reads hang indefinitely. Incomplete-fix instance of the Windows-special-name class (LaraDashboard..%5C, Angular SSR sibling-directory, uv wheel traversal, Mako drive-letterTemplateLookupGHSA-5639 all landed the same week): path-confinement helpers need a Windows parser-parity battery — device names, ADS markers, drive-letter URIs, backslash separators — reproduced on actual NTFS, not Linux CI. Mako's drive-letter URI traversal inTemplateLookupis the template-loader twin of the same Windows path-parser gap. - PyMongo CSFLE KMS endpoint
.sock→ forced AF_UNIX connection (GHSA-qx36-8mw2-4r3x / CVE-2026-96747, medium, pymongo ≥3.9 ≤4.18.1): the driver passedmasterKey.endpointfrom a key-vault document verbatim intoparse_host(), which returns any.sock-suffixed string unchanged instead of validating host:port — the connection layer then treats it as a Unix socket path and dials it withAF_UNIX. Anyone who can write to the key vault collection redirects the application's next KMS request (key-cache TTL ~60s) to an arbitrary local socket: the app delivers its KMS credentials/request to an attacker-chosen local endpoint, and the same "scheme selected by suffix, not validated as network address" shape has appeared in Redis, SMTP, and webhook libraries. Operator rule: when any stored field reaches a connection-string parser, test the parser's alternate-address-family branches — feed a.sock-suffixed value,unix://forms, and numeric-family variants and log which socket family actually dials (a patchedAF_INETvalidator with an unpatchedAF_UNIXreturn path is the fingerprint; the fix added explicit.sockrejection). Sibling of this page's decode-before-split leg: the validator and the dialer disagree about the grammar, and here about the family. - Punk (Perl) routes HTTP/2/3 Extended CONNECT as GET, escaping the WebSocket Origin gate (GHSA-cmh9-2wr3-4x64 / CVE-2026-104380, 0.48–<0.55): on HTTP/2 and HTTP/3 a WebSocket handshake is an Extended CONNECT request, which Punk's router matches as a GET — so it reaches every GET route, API operation, and mount. The Origin check runs only when a websocket route matches, so it never fires on this transport; the handler's normal 2xx response is accepted as the handshake response. A cross-origin page can then open a WebSocket to any path and learn from the open/error event whether that path returns 2xx — an unauthenticated, browser-driven route-status oracle across the whole GET surface. Operator rules: (1) transport spelling is another enum-gated control axis — when a security check is wired to a specific request-shape match (method,
:protocolvalue, route class), test the alternate spellings that normalize onto the same handler: Extended CONNECT with:protocol: websocketvs a plainwebsocket-route upgrade vs HTTP/1.1 Upgrade; this is the sibling of the Oct 3 OpenAM PKCEresponse_typespelling leg, moved from OAuth params to HTTP transport. (2) Cross-origin WebSocket-open oracles are a path-enumeration primitive worth probing on any HTTP/2 or HTTP/3 framework: a 2xx-vs-non2xx open/error differential from the victim's browser defeats same-origin path-discovery assumptions. Framework-fingerprint rule from the Jetty page applies: if the stack parses HTTP/2/3, the pseudo-header/transport-shape battery is in scope, not just the HTTP/1.1 one.
October 6 15:3xZ follow-up: i18next-http-backend turns a colon into a scheme via {{lng}} interpolation (GHSA-xvq9-wjp8-hwqf / CVE-2026-105800, 3.7)¶
Low CVSS, clean reusable shape: i18next-http-backend builds translation-file URLs from a loadPath template ({{lng}}/{{ns}}.json) interpolating the language (and namespace) value, which is attacker-settable via ?lng=/?ns= query params or persisted user prefs. A colon-only scheme trick — lng=http:127.0.0.1:PORT — produces a URL whose scheme the URL parser resolves to an unintended origin, bypassing the "no scheme in template" expectation; the backend fetches the attacker's origin server-side. The shipped PoC is a loopback-listener VULNERABLE/SAFE probe — a template worth copying for any interpolation-into-URL audit.
- Durable rule: template-interpolated URL components need scheme-slot testing, not just path testing — when user input lands where a scheme or authority could parse, feed
scheme:,//host/,\/host, and backslash variants into each template placeholder ({{lng}},{{ns}},{{regExp}}-style slots) and observe which listener receives the request. Sibling of this page's Punk Extended-CONNECT leg (transport spelling) and the PyMongo decode-before-split leg (delimiter order): here the placeholder position is the parser differential — what looks like a path segment to the developer is a scheme+authority tonew URL(). - Bug-hunter angle: i18n backends ship on a large share of SSRF-free-looking Next/Express apps; a single
?lng=canary ofhttp:your-callback:80is a five-second probe with a clean owned-listener proof. SSRF-adjacent severity here depends entirely on app network position — report origin-selection, not blast radius, unless a second sink is proven.
October 7 21:3xZ follow-up: Cyrus SASL DIGEST-MD5 sizes the challenge buffer before quoting, then strcat()s the longer quoted value (CVE-2026-107161 / GHSA-4jhc-cc62-fwcm, 7.5)¶
Client-side heap overflow in the DIGEST-MD5 plugin: add_to_challenge() computes the buffer size for a challenge field before DIGEST-MD5 quoting is applied, does not recompute when quoting (escaping "/\) lengthens the value, and hands the under-sized buffer to strcat() — an attacker-controlled-size heap OOB write. Trigger: a malicious or on-path DIGEST-MD5/HTTP-Digest server sends a crafted realm/nonce to a connecting client; most likely client crash.
- Durable axis: this page's parser-differential family moves into the auth-challenge direction. Everyone tests client→server request encoding; the server→client challenge is equally attacker input whenever an attacker can be on-path or run the service (rogue SMTP/IMAP/LDAP/HTTP digest endpoints, evil-proxy downgrades). Sweep rule: for any digest/auth protocol you use as a client, fuzz the server's challenge fields with quoting-triggering payloads — strings full of
"and\whose escaped length exceeds their raw length — and watch for crashes in your own client stack. Length-computed-before-transformation is the fingerprint shape (strlenat entry, escape/encode later). - Tooling note:
libsasl2sits under Postfix, curl-ldap, Dovecot, OpenLDAP, and countless enterprise connectors — a client-side overflow here is a pivot surface when a pentest host's mail/LDAP tooling is coerced toward an attacker-controlled server (coerced-authentication posture, same genealogy as the coercion classes already on the wiki).
October 8 follow-up: Apache Directory LDAP API — a rogue LDAP server deserializes Java objects into the client's loadSchema() (CVE-2026-103877 / GHSA-v496-rffp-c5q7, 9.8; + CVE-2026-103885 crafted-telephone-number CPU loop, fixed 2.1.9)¶
The client-side-deserialization-from-server-response class, promoted with the Cyrus SASL leg above to the same page: Apache Directory LDAP API 2.1.0–2.1.8 lets a rogue or on-path (pre-TLS/StartTLS-MITM) LDAP server answer a client's loadSchema() subschema search with a schema object containing a serialized Java class → potential RCE in the connecting client. CVSS 9.8. The sibling advisory (CVE-2026-103885) is the resource-exhaustion twin: a server using the API (ApacheDS) pins a CPU core forever on crafted telephoneNumber values — parser-state DoS, tracked.
- Server→client deserialization is the same trust inversion as the Cyrus challenge overflow, and it is more common than teams believe. Any protocol library that fetches "metadata" objects from a server (LDAP schema, printer IPP attributes, discovery documents, capability blobs) and materializes them with a general-purpose deserializer gives whoever answers the request code-exec in the client process. Sweep rule for your own client stack: grep the dependency tree for
ObjectInputStream/readObject/XSTREAM-style generic deserialization reachable from protocol response parsers; gadget chains decide final severity, but the reachable-parser-deserialization fact alone is the reportable primitive. - StartTLS before bind is the mitigation boundary — so downgrade/strip is the actual attack trigger. On engagement LANs where you can answer LDAP (spoofed DC hostname, evil-ldap posture), the posture is: force plaintext or stall StartTLS, serve a crafted subschema reply to any connecting Java service using the affected API (Apache DS tooling, NiFi, Hive, Kafka Connect sinks, enterprise SSO connectors built on the Apache LDAP API), and the pivot lands in the service process, not a browser. Same coerced-authentication genealogy as the Cyrus/libsasl2 note above — now with a 9.8 client-side RCE anchor instead of a crash.
- Fingerprint before attack:
LDAP-SDK-Javastrings in jars/classload dumps, or/usr/share/javascans on lab targets; the fixed artifact is 2.1.9, so version bands are checkable from shipped jar names. Lab-only proof: your own disposable LDAP listener serving a marker serialized object to your own test client; never point third-party connectors at it.
October 14 follow-up: BusyBox httpd reverse proxy rewrites only the first request on a connection — pipelined second request reaches the backend verbatim (89f7/CVE-2026-88829, 7.2)¶
BusyBox httpd's -c/proxy-prefix feature rewrites the URL path only for the first HTTP request on a TCP connection. A pipelined second request on the same socket is relayed to the backend verbatim, bypassing the configured path restrictions — an unauthenticated attacker opens one connection, sends an allowed-path request followed by any path, and the backend answers the hidden path. The proxy that looked like a path allowlist was only an allowlist for request #1.
- Durable rule: per-connection state in a proxy is a differential, test request 2..N on every proxied connection. The whole page's framing-differential family (Fiddler CL/TE legs, Punk Extended-CONNECT, Spring pre-flight) is about spelling alternatives; this leg is the position alternative — rewrite, auth, rate-limit, WAF, or header-injection decisions that run once per connection instead of once per message. Battery on any embedded/edge proxy you're authorized to test: single keep-alive connection, request 1 = allowlisted prefix, request 2 = previously-blocked path (pipelined, no waiting); diff the backend response vs request 2 sent on a fresh connection. Positive = different content, and it's reportable even when request 1 was fully compliant.
- Embedded-device control-plane fingerprint: BusyBox httpd fronts router/IoT/appliance admin panels in enormous volume; where banner or behavior says BusyBox, the proxy-config reachability question ("is any prefix proxied to an internal service?") is worth one pipelined canary before deeper testing. Small embedded stacks routinely implement "first message" fast paths — same shape appears in modems' mini-httpd family and in the wiki's Go
net/httpsmuggling leg (parser disagreement across a shared connection). - Same wave tracked: BusyBox
dpkgwrite_status_filefield-cursor reset (9p9q/CVE-2026-88842, low) anddpkg-debar-handler flush bug (68qr/CVE-2026-90954, high) — parser-state leaves of the known extraction family; unbound anchorsTXT/HIP/SVCB-ECH/SVCB-keyless RDATA bounds quintet (22wp/v69q/r5wh/w2rq + 101301 chain) memory-safety class; GStreamer H.266/ASF memory-safety pair.