CVE-2026-39376: Fastfeedparser Denial of Service Vulnerability
HIGHCVE-2026-39376 is a HIGH (CVSS 7.5) denial of service vulnerability (CWE-400: Uncontrolled Resource Consumption) affecting Fastfeedparser libraries in the PyPI ecosystem. The issue involves fastfeedparser has an infinite redirect loop dos via meta-refresh chain. Remediation is available by upgrading affected packages to version 0.5.10.
CVE-2026-39376 at a Glance
Security Impact
CVSS: 7.5
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H).
How to Fix CVE-2026-39376
To remediate this vulnerability, upgrade all affected Fastfeedparser dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
pip install fastfeedparser>=0.5.10
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
pip show fastfeedparser
How to Check if You Are Affected
To determine whether your Python environment is affected by CVE-2026-39376, inspect your installed packages using pip:
pip show fastfeedparser
Analyze the terminal output to locate any version of Fastfeedparser in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.5.10), your application is affected.
Note: The pip show fastfeedparser command checks currently installed packages in your active Python environment.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-400: Uncontrolled Resource Consumption, where the product does not properly control the allocation and maintenance of a limited resource. In Fastfeedparser, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-39376 Affected Fastfeedparser Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
fastfeedparser
|
PyPI |
< 0.5.10
|
0.5.10
|
References
Frequently Asked Questions
What is CVE-2026-39376?
Which Fastfeedparser versions are affected?
What version fixes CVE-2026-39376?
Is fastfeedparser affected?
What is the CVSS score of CVE-2026-39376?
What CWE is associated with CVE-2026-39376?
How can I check PyPI dependencies for CVE-2026-39376?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-4gx2-pc4f-wq37",
"modified" : "2026-06-06T00:24:06Z",
"published" : "2026-04-08T00:12:26Z",
"aliases" : [ "CVE-2026-39376" ],
"summary" : "FastFeedParser has an infinite redirect loop DoS via meta-refresh chain",
"details" : "### Summary\nWhen `parse()` fetches a URL that returns an HTML page containing a `<meta http-equiv=\"refresh\">` tag, it recursively calls itself with the redirect URL — with no depth limit, no visited-URL deduplication, and no redirect count cap. An attacker-controlled server that returns an infinite chain of HTML meta-refresh responses causes unbounded recursion, exhausting the Python call stack and crashing the process. This vulnerability can also be chained with the companion SSRF issue to reach internal network targets after bypassing the initial URL check.\n\n\n### Details\n`parse()` catches `ValueError` on XML parse failure, extracts a meta-refresh URL from the HTML response via `_extract_meta_refresh_url()`, and tail-calls itself with that URL. The recursive call is unconditional — there is no maximum redirect depth, no set of already-visited URLs, and no guard against self-referential or looping redirects.\n\n**`fastfeedparser/main.py` — `parse()` (recursive sink):**\n```python\ndef parse(source: str | bytes, ...) -> FastFeedParserDict:\n is_url = isinstance(source, str) and source.startswith((\"http://\", \"https://\"))\n if is_url:\n content = _fetch_url_content(source)\n try:\n return _parse_content(content, ...)\n except ValueError as e:\n ...\n redirect_url = _extract_meta_refresh_url(content, source)\n if redirect_url is None:\n raise\n return parse(redirect_url, ...) # ← unconditional recursion, no depth limit\n```\n\n`_extract_meta_refresh_url()` uses `urljoin(base_url, match.group(1))` so relative, protocol-relative (`//host/path`), and absolute URLs in the `content=` attribute are all followed.\n\n### PoC\nNo live server required. The following monkeypatches `_fetch_url_content` to return an infinite HTML meta-refresh chain and confirms unbounded recursion:\n\n```python\nimport fastfeedparser.main as m\n\ncall_count = 0\n_orig = m._fetch_url_content\n\ndef mock_fetch(url):\n global call_count\n call_count += 1\n if call_count > 10:\n raise RuntimeError(f\"Stopped at call {call_count}\")\n next_url = f\"http://169.254.169.254/step{call_count}/\"\n return f\"\"\"<html><head>\n<meta http-equiv=\"refresh\" content=\"0; url={next_url}\">\n</head><body>not a feed</body></html>\"\"\".encode()\n\nm._fetch_url_content = mock_fetch\n\ntry:\n m.parse(\"http://attacker.com/loop\")\nexcept RuntimeError as e:\n print(f\"CONFIRMED infinite loop: {e}\")\nfinally:\n m._fetch_url_content = _orig\n print(f\"Total fetches before stop: {call_count}\")\n\n# Output:\n# CONFIRMED infinite loop: Stopped at call 11\n# Total fetches before stop: 11\n```\n\nEach recursive call performs a real HTTP request (30 s timeout), HTML parsing, and a Python stack frame allocation. With Python's default recursion limit of 1000 and a 30 s per-request timeout, a single attacker request can hold a server thread busy for up to ~8 hours before a `RecursionError` is raised.\n\n**SSRF chain variant:** The first response can be legitimate HTML redirecting to an internal address (`http://192.168.1.1/`), letting the redirect loop also serve as an SSRF bypass for targets that would otherwise be blocked by application-level URL validation applied only to the initial URL.\n\n\n\n### Impact\nThis is a denial-of-service vulnerability with a secondary SSRF-chaining impact. Any application that accepts user-supplied feed URLs and calls `fastfeedparser.parse()` is affected — including RSS aggregators, feed preview services, and \"subscribe by URL\" features. An attacker with no authentication can:\n\n- Hold a server worker thread indefinitely (one request per attacker connection)\n- Crash the worker process via `RecursionError` after ~1000 redirects\n- Use the redirect chain to pivot SSRF requests to internal network targets",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "PyPI",
"name" : "fastfeedparser"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "0.5.10"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 0.5.9"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/kagisearch/fastfeedparser/security/advisories/GHSA-4gx2-pc4f-wq37"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-39376"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/kagisearch/fastfeedparser"
}, {
"type" : "WEB",
"url" : "https://github.com/pypa/advisory-database/tree/main/vulns/fastfeedparser/PYSEC-2026-60.yaml"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-400", "CWE-674" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-04-08T00:12:26Z",
"nvd_published_at" : "2026-04-07T20:16:32Z"
}
}