Skip to content
Back to evidence wall

guzzlehttp/psr7 / CVE-2022-24775

Header values not checked for CR/LF

Historical vulnerabilityDetection match (historical test)Packagist

Header values are only trimmed and never rejected for \r or \n, so untrusted values can smuggle extra headers.

Evidence chain

Follow each source in order. Missing material is explicit; an advisory or fix link does not stand in for a product test.

  1. Product observation

    An L0 scan (no hints) of the released archive produced a finding that meets the location and CWE criteria registered before the scan. This is detection of a known issue, not an original discovery or a successful exploit.

    Release-archive scan result
  2. Human / upstream attribution

    Original report and fix credits belong to the guzzle/psr7 advisory. Vettalon performed detection of a known issue only.

    Upstream advisory
  3. Fixed-version comparison

    The upstream fixed release was scanned with the same parameters to see whether the patched code is still flagged. This is a scan control, not an exploit or differential test.

    Fixed-release scan control
  4. Unverified scope

    The models may have seen this advisory or its fix during training, so a match does not show that they reasoned it out from the code. Candidates and needs_human results are not automatic confirmation, and no PoC or exploit was run. This was a single run and model output is nondeterministic. Five hand-picked known issues cannot support a recall or false-positive rate. Other output is published as counts only and was not reviewed. The raw report.json and trace are not public; only their SHA-256 is listed. The run status in the table is what the product reported: incomplete means some unit was deferred, truncated, failed or could not be cross-checked, with the reason shown, but the target file was sent for review in every arm. On the fixed release, "not flagged" only means no unrefuted output in the corresponding range carried a listed CWE; the other output in that arm was not reviewed and says nothing about the fixed release being free of other issues. The Packagist dist is a GitHub zipball generated from a commit, and its bytes can change with GitHub archiving; the SHA-256 pinned here is the one downloaded on 2026-10-20.

    Read limits

What this evidence supports

The 2.1.0 archive scan raised a CWE-113 candidate at src/MessageTrait.php:208 (trimHeaderValues); grok judged it plausible and it ended as needs_human, meeting the registered location and CWE list. The fixed 2.1.1 scan with the same parameters produced nothing in the corresponding range with a listed CWE.

Test method

Official release archives of the vulnerable and fixed versions were downloaded from the package registry, checked against SHA-256 and scanned as whole trees without git history. Both arms used the same parameters: deep profile, claude as finder, grok and agy (GPT-OSS) as cross-family verifiers, at most 8 audit units, one verifier run per candidate, PoC off. Model input contained no CVE id, advisory text or fix diff, and changelog files were removed from both arms. Match criteria (file, line ranges, CWE list) were committed publicly at 12:51 UTC on 2026-10-20; the first scan started 29 seconds later. The registeredAt field inside the file says 12:55; it was a hand-typed estimate made before the commit and is wrong. The commit time is authoritative, and the file was left unchanged so its digest still matches.

Mode
release-archive
Finding status
needs_human
Location
src/MessageTrait.php:208
Download public record (JSON)

Public detection evidence snapshot

Header values are never checked for CR/LF, so attackers can inject headers or split requests.

grok: plausible. The verifier did not refute the candidate; it remains needs_human and is not a confirmation.

Finder
claude-opus-5-5 (Anthropic)
Verifier and verdict
grok-4.7 (xAI): plausible
Tool version
vettalon 0.3.0 (built from source on 2026-10-20)
Model versions
Finder claude-opus-5-5 (claude CLI 2.1.300); verifiers grok-4.7 (grok CLI 1.0.62) and gpt-oss-120b-medium (agy 1.4.3)
Historical scope
Whole release archive, no git history; up to 8 audit units; changelog files removed from both arms; L0 (no CWE, location or advisory hint)

Rerun detection

Install the Vettalon CLI and configure your models and credentials in config.toml. These steps download the official release archive, check its SHA-256 and scan the whole tree; the pre-registration lists excluded files. Model and rule versions may differ; identical results are not guaranteed. Deep mode sends source to configured models. This is detection only; it does not run the upstream project or verify exploitation.

curl -sSfLo release-archive https://api.github.com/repos/guzzle/psr7/zipball/089edd38f5b8abba6cb01567c2a8aaa47cec4c72
shasum -a 256 release-archive   # expect 2b0b4998cf069344114189d7ad994960e86131b96c31c19716c86581ba7a49cc
mkdir release-tree && bsdtar -xf release-archive --strip-components 1 -C release-tree
# remove the files listed under "excluded" in the pre-registration, then:
vettalon scan ./release-tree --profile deep --config ./config.toml --finders claude --verifiers grok,agy --max-modules 8 --refuter-runs 1 --no-prior --time-budget 2400 --report ./result.json

Pre-registered release-archive scan

Both arms scan the official release archive (no git history) with the same parameters. Model input contains no CVE id, advisory text or fix diff. A match is judged against the file, line ranges and CWE registered publicly before the first scan; other output is listed as counts only and was not reviewed. "Not flagged" on the fixed release only means nothing in the corresponding range met the criteria. The models may have seen this advisory during training, and a candidate is not an automatic confirmation.

ArmVersionResultModel callsRun statusTarget file reviewed
Vulnerable2.1.0Found11incomplete (scope_not_fully_reviewed)yes
Fixed2.1.1Not flagged9incomplete (scope_not_fully_reviewed)yes
Download case scan summary (JSON)
Summary artifact SHA-25633b0e37f2761def83e42c7a1af25ac672b053671fe4b01aec7e013bb41135f59

Match criteria were registered publicly before the first scan: Pre-registration (JSON)

Pre-registration SHA-2566c7ef71cffa3729de787444c67823b01afcda71d61b42f2a005fda892a07db91

Limits and prerequisites

The models may have seen this advisory or its fix during training, so a match does not show that they reasoned it out from the code. Candidates and needs_human results are not automatic confirmation, and no PoC or exploit was run. This was a single run and model output is nondeterministic. Five hand-picked known issues cannot support a recall or false-positive rate. Other output is published as counts only and was not reviewed. The raw report.json and trace are not public; only their SHA-256 is listed. The run status in the table is what the product reported: incomplete means some unit was deferred, truncated, failed or could not be cross-checked, with the reason shown, but the target file was sent for review in every arm. On the fixed release, "not flagged" only means no unrefuted output in the corresponding range carried a listed CWE; the other output in that arm was not reviewed and says nothing about the fixed release being free of other issues. The Packagist dist is a GitHub zipball generated from a commit, and its bytes can change with GitHub archiving; the SHA-256 pinned here is the one downloaded on 2026-10-20.

Sources and attribution

Original report and fix credits belong to the guzzle/psr7 advisory. Vettalon performed detection of a known issue only.

Original detection report SHA-256

For comparison by holders of the original report. The download is a curated record, not the raw scan report.

f9e27d8a28fbf48edebe0cfe1236d6b8fe00dd4234d685fa17a22da9b9625715