Repository navigation
The requests>=2.32.2 floor admits the .netrc credential leak (CVE-2024-47081); the default IP-pinned path neutralises it, but the webhook allow_private_destinations path sends ano… (CR-A16-081) #528
Description
Wave 2 · theme D2-7: Next-release technology updates · highest severity Low · 2 finding(s) · effort trivial
Summary
pyproject.toml:62 sets requests>=2.32.2. datasets 4.7.0 imposes the same floor (Requires-Dist requests>=2.32.2), and the K-3 lower venv installs 2.32.2. requests before 2.32.4 picks the .netrc entry by netloc.split(':')[0] (get_netrc_auth in 2.32.2). A URL such as https://victim.example:@attacker.example/ therefore gets victim.example's credentials while connecting to attacker.example. In forgelm/_http.py the default path (allow_private=False) resolves the host, rebuilds the URL with a public IP literal and drops the userinfo (_http.py:302-327, 563-578). The pinned Session then looks .netrc up by the IP, so no foreign credential is attached. When allow_private=True, safe_post and safe_get call module-level requests.post / requests.request with the raw URL (_http.py:583-597, 722-730), whose Session has trust_env on, and the leak happens. The only caller that passes allow_private=True is the webhook notifier (webhook.py:154,167), driven by WebhookConfig.allow_private_destinations (config.py:1488-1491, default False). judge.py:248, synthetic.py:240 and _doctor.py:500,541 always use the pinned path. The URL is operator config or url_env (TC-T; TC-U only in the CI-PR case of IN-01), an…
Primary finding
CR-A16-081 — The requests>=2.32.2 floor admits the .netrc credential leak (CVE-2024-47081); the default IP-pinned path neutralises it, but the webhook allow_private_destinations path sends another host's .netrc c…
severity Low · reachability documented-opt-in · intent intended-but-harmful · confidence likely · independently confirmed · reproduced end to end
What happens. pyproject.toml:62 sets requests>=2.32.2. datasets 4.7.0 imposes the same floor (Requires-Dist requests>=2.32.2), and the K-3 lower venv installs 2.32.2. requests before 2.32.4 picks the .netrc entry by netloc.split(':')[0] (get_netrc_auth in 2.32.2). A URL such as https://victim.example:@attacker.example/ therefore gets victim.example's credentials while connecting to attacker.example. In forgelm/_http.py the default path (allow_private=False) resolves the host, rebuilds the URL with a public IP literal and drops the userinfo (_http.py:302-327, 563-578). The pinned Session then looks .netrc up by the IP, so no foreign credential is attached. When allow_private=True, safe_post and safe_get call module-level requests.post / requests.request with the raw URL (_http.py:583-597, 722-730), whose Session has trust_env on, and the leak happens. The only caller that passes allow_private=True is the webhook notifier (webhook.py:154,167), driven by WebhookConfig.allow_private_destinations (config.py:1488-1491, default False). judge.py:248, synthetic.py:240 and _doctor.py:500,541 always use the pinned path. The URL is operator config or url_env (TC-T; TC-U only in the CI-PR case of IN-01), and the path needs a documented opt-in. So this is a footgun or hardening gap, not a vulnerability. The second floor advisory, CVE-2026-25645 (extract_zipped_paths, fixed 2.33.0), needs a local attacker, and the advisory itself says standard usage is not affected. requests 2.33.0 requires Python >=3.10, the same as ForgeLM, so raising the floor costs nothing.
Where.
pyproject.toml:62forgelm/_http.py:583forgelm/_http.py:722forgelm/webhook.py:154forgelm/config.py:1488
Evidence.
- Lower venv requests 2.32.2, NETRC set to a file with 'machine victim.example login svc password NETRC-SECRET'. For url https://victim.example:@attacker.example/hook: safe_post allow_private=False sent to https://93.184.215.14/hook with no Authorization header; safe_post and safe_get with allow_private=True sent to the raw URL with Authorization 'Basic c3ZjOk5FVFJDLVNFQ1JFVA==' (svc:NETRC-SECRET). Latest venv requests 2.34.2: get_netrc_auth(raw url) returned None, and the header carried only the…
Recommended fix. Raise the floor to requests>=2.33.0, which clears both advisories. Optionally route the allow_private branch through a Session too and strip userinfo there. Setting trust_env=False would also drop env proxies, so prefer raising the floor.
Other findings with the same root cause
These close with the same fix; update them in the same pull request.
TECH-T12-008 — Supply-chain tooling, network dependencies and vulnerability scanning: requests>=2.32.2,<3.0.0 (core dependency floor) (range-unsound)
severity Next release
Item. requests>=2.32.2,<3.0.0 (core dependency floor) · verdict: range-unsound · urgency: Next release
State in ForgeLM. pyproject.toml:62 requests>=2.32.2,<3.0.0; the K-3 lower venv resolves 2.32.2; forgelm/_http.py is the SSRF-guarded HTTP chokepoint; the orphan requirements.txt:11 says requests>=2.31.0.
State of the ecosystem on 2026-10-01. Latest is 2.34.2 (2026-05-14), with no advisories. 2.32.2 is affected by PYSEC-2026-1872 / GHSA-9hjg-9r4m-mvj7 / CVE-2024-47081 (.netrc credentials can leak for crafted URLs; fixed 2.32.4) and PYSEC-2026-2275 / GHSA-gc5v-m9x4-r6x2 / CVE-2026-25645 (fixed 2.33.0); 2.31.0 additionally has CVE-2024-35195 (fixed 2.32.0).
Impact. A minimum-version install of the HTTP chokepoint (webhook, judge, teacher) carries a known credential-leak bug; exploitation needs a .netrc plus a crafted URL (IN-01 config: TC-T, TC-U in CI-PR). The lower-bound CI venv actually tests the vulnerable version.
Recommendation. Raise the floor to requests>=2.33.0 (no Python cost: both need >= 3.10); delete or regenerate requirements.txt.
Sources.
- OSV PYSEC-2026-1872 (requests .netrc leak, CVE-2024-47081) (2026-07-07)
- OSV PYSEC-2026-2275 (requests extract_zipped_paths, CVE-2026-25645) (2026-03-25)
- PyPI requests 2.32.2 vulnerabilities (2026-10-01 (live vulnerability data))
- PyPI requests (2.34.2) (2026-05-14)
- PyPI requests 2.34.2 (vulnerabilities field) (2026-10-01 (live vulnerability data))
- PyPI requests 2.31.0 vulnerabilities (2026-10-01 (live vulnerability data))
Acceptance criteria
- A regression test reproduces the failure scenario and asserts the corrected behaviour.
- Documentation listed above is corrected in English and in its Turkish mirror in the same PR.
- Every finding in this issue is resolved or explicitly closed with a reason.
Found by the October 2026 ForgeLM code and documentation review against commit cab2947. Code links point at that commit; line numbers may have moved since. Finding IDs (CR-…, DOC-…, TECH-…) are stable references for this backlog.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity