ciguard: SCA HTTP client reads response body without size capGHSA-xw8c-rrvx-f7xq
LOWGHSA-xw8c-rrvx-f7xq is a low-severity (CVSS 3.7) CWE-770 vulnerability in ciguard. A fix is available for ciguard — see the affected versions and patch details below.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
Where this sits among everything scored
Real-World Exposure
ciguardReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Summary
Both SCA HTTP clients (src/ciguard/analyzer/sca/osv.py and src/ciguard/analyzer/sca/endoflife.py) call payload = json.loads(resp.read().decode('utf-8')) without a maximum-bytes cap. A hostile or compromised endoflife.date / OSV.dev (or a successful TLS MITM) could return a multi-GB response, exhausting the ciguard process's memory.
Threat scenario
ciguard process memory exhaustion → OOM kill or system swap thrash. Realistic when ciguard runs in CI with a limited memory budget (typical: 4-8 GB). No data integrity or confidentiality impact.
Realism caveat: both URLs are hardcoded HTTPS, so this is a low-realism threat (HTTPS prevents MITM unless the attacker controls a trusted CA or hijacks DNS in a way that doesn't trigger cert validation). The unbounded read is structural defence-in-depth, not a directly exploitable bug today.
Patch
- New
MAX_RESPONSE_BYTES = 5 * 1024 * 1024(5 MB) constant in both modules. body = resp.read(MAX_RESPONSE_BYTES + 1)with overflow check returnsNone(caller falls back to stale cache).- 3 regression tests in
tests/test_sca_rules.py::TestSCAResponseSizeCap.
Discovery
Found during ciguard's first self-conducted pentest cycle, 2026-04-26.
CVSS Scoring
- CVSS v3.1:
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L— 3.7 (Low) - CVSS v4.0:
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N— first.org calc 3.1 (Low); GitHub's calc 6.3 (Medium). Vector is correct — choosing v3.1 as the structured score keeps the consistent Low rating across consumers.
Reproduction
Monkey-patch urllib.request.urlopen to return a fake 50 MB response; observe memory growth before/after the call. Pre-fix: process memory grows by ~50 MB. Post-fix: _fetch returns None, memory growth bounded to MAX_RESPONSE_BYTES.
References
- Fix released in v0.8.2
- CI regression gate added in v0.8.3
- https://www.cve.org/CVERecord?id=CVE-2026-44219
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | ciguard | ≥ 0.6.0&&< 0.8.2 | 0.8.2pip install --upgrade 'ciguard==0.8.2' |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for ciguard, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update ciguard to 0.8.2 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-xw8c-rrvx-f7xq is resolved across your whole dependency graph.
Workarounds
Stop feeding it untrusted input: reject or quarantine files and payloads from unverified sources until you can upgrade, restrict accepted formats to the ones you actually need, and run the parsing or decoding step in a least-privileged sandbox or short-lived worker so a crash or corrupted read cannot reach the rest of the process.
Frequently Asked Questions
Is GHSA-xw8c-rrvx-f7xq in your dependencies?
Find it across PyPI, including transitive dependencies.