Repository navigation
httpv2: the frame guard tests the declared length, not the buffer, so a 4-octet frame can report length=16777215 #799
Description
Activity
- addedbugIssues reporting a defect (set by the bug report template; a default, not an assessment)Issues reporting a defect (set by the bug report template; a default, not an assessment)fixPull requests that fix a defect (fix: subject prefix)Pull requests that fix a defect (fix: subject prefix)
on Sep 25, 2026 Labelling
blockedso it does not read as unheld work.Checkable blocker: #789 merged. This issue's fix lets
_guess_versiondrop thestruct.errorsuppression that #789 introduced — so the two changes touch the same reasoning inpcapkit/protocols/application/http.py, and #789 (11bb7693a,review: good-to-go, awaiting the maintainer) holds that file now. Doing this first would mean writing the guard against a_guess_versionthat is about to change, then re-deriving it.gh pr view 789 -R JarryShaw/PyPCAPKit --json state,mergedAtSequence once clear, because the order is the point: fix the guard here so the whole sub-9 class becomes a uniform
ProtocolError, then narrowsuppress(ProtocolError, struct.error)back tosuppress(ProtocolError)on the last arm and delete the residual paragraph #789's comment now carries. That paragraph is an honest admission of a cost this issue removes — so the follow-up should retire the comment, not leave it describing a compromise that no longer exists.Note the line numbers above are pinned to
0419c1c97andhttpv2.pyis untouched by #789, so:223and:292should still be right when this starts — but re-derive rather than trust, since that has bitten three times today.- addedblockedDeferred pending another issue or decision; see the last comment for what unblocks itDeferred pending another issue or decision; see the last comment for what unblocks itwipWork in flight - a covering PR is open or an agent is actively on itWork in flight - a covering PR is open or an agent is actively on itand removedblockedDeferred pending another issue or decision; see the last comment for what unblocks itDeferred pending another issue or decision; see the last comment for what unblocks it
on Sep 25, 2026 - removedwipWork in flight - a covering PR is open or an agent is actively on itWork in flight - a covering PR is open or an agent is actively on it
on Sep 25, 2026
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
Describe the bug
pcapkit/protocols/application/httpv2.py:223guards onif schema.length < 9:— the declared length read off the wire, neverlen(buffer). So a truncated frame whose declared length happens to be ≥ 9 parses, and the parsed object reports a length the capture does not contain. Measured on0419c1c97, a 4-octet buffer sweeping the declared length:A 4-octet buffer yields
length=16777215. The value is attacker-controlled, and anything downstream that trustslengthfor framing or offsets is handed a number the capture cannot support.Note the result is non-monotone — 9 parses, 10 refuses, 15 parses. A guard testing the intended quantity could not produce that shape; it is the signature of an accident rather than a design.
Expected behavior
The sub-9 class should be uniformly refused. Adding a buffer-length condition alongside the declared-length one — so both must hold — makes every truncated frame a
ProtocolError.Why this is worth more than it looks
It is the root cause of the only compromise #789 had to accept. That PR made
_guess_version's HTTP/2 arm reachable and had to widen the last arm's suppression to(ProtocolError, struct.error), admitting in a code comment that a genuinehttpv2schema defect on well-formed HTTP/2 bytes would now surface asunknown HTTP versionrather than crashing loudly.That residual exists only because this guard tests the wrong quantity. Make the sub-9 class uniformly
ProtocolErrorand_guess_versioncan drop thestruct.errorsuppression entirely — so this is a follow-up that shrinks #789's surface rather than merely noting it.It also became reachable from ordinary extraction at #789's head: on base the guess path died in arm 1, so via UDP/80 a truncated HTTP/2 frame became
Raw; now it parses as a confidentHTTP/2.Additional context
Found by the cross-review on #789, which ranked it above the related residual that
HTTPv2constructed directly still raises a barestruct.errorunder 9 octets — the same defect from a less consequential angle. Both routes measured:HTTPv2direct andHTTP(..., version=2)parse a 4-octet buffer declaring 15;HTTP()refused it on base and parses it at11bb7693a.Also related, and worth checking in the same pass:
httpv2.py:292'smake()emits_make_http_length(...) + 9, treatingLengthas the total frame size where RFC 9113 §4.1 says it is the payload size, header excluded. That is tracked separately as the round-trip asymmetry noted on #682's investigation; whoever fixes the guard should confirm the two are consistent afterwards.Related: #789, #787, #682.