Pyload ng: pyLoad: SSRF guard bypass via IPv6 6to4/NAT64 transition wrappers of internal IPs (CVE-2026-48737)
## Summary `is_global_address` in [`src/pyload/core/utils/web/check.py`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/utils/web/check.py) is the central guard against SSRF-style outbound connections in pyload-ng. It tests whether a given IP is "globally routable" via Python's `ipaddress.ip_address(value).is_global`, and callers treat `not is_global` as "deny": ```python def is_global_address(value): try: return ipaddress.ip_address(value).is_global except ValueError: return False def is_global_host(value): ips = host_to_ip(value) return ips and all((is_global_address(ip) for ip in ips)) ``` Python's `ipaddress.IPv6Address.is_global` classifies the NAT64 well-known prefix as **globally routable** on every supported Python version (3.9 through 3.14 confirmed), and on older Pythons (3.9-3.11) the 6to4 prefix as well: | address | `is_global` on Py 3.9-3.11 | `is_global` on Py 3.12+ | wrapped IPv4 | |----------------------------------|---------------------------|--------------------------|----------------------| | `2002:7f00:0001::` (6to4) | True | False | 127.0.0.1 | | `2002:0a00:0001::` (6to4) | True | False | 10.0.0.1 | | `2002:a9fe:a9fe::` (6to4) | True | False | 169.254.169.254 (IMDS)| | `64:ff9b::a9fe:a9fe` (NAT64) | True | True | 169.254.169.254 | | `64:ff9b::7f00:1` (NAT64) | True | True | 127.0.0.1 | pyload-ng declares `python_requires = >=3.9` (`setup.cfg`), so deployments on Python 3.9-3.11 see the 6to4 path too. The NAT64 path is universal. `is_global` returns True for these wrappers, so `is_global_address` returns True and the deny check passes. The pycurl `PREREQFUNC` at [`src/pyload/core/network/http/http_request.py:680`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/network/http/http_request.py#L680) consults the same helper just before TCP-connect: ```python if not self.allow_private_ip: is_proxy_ip = self.http_proxy_host and self.http_proxy_host == (conn_primary_ip, conn_primary_port) if not is_global_address(conn_primary_ip) and not is_proxy_ip: return pycurl.PREREQFUNC_ABORT return pycurl.PREREQFUNC_OK ``` On a host with 6to4 routing (legacy operator tunnels; `2002::/16` still configurable) or NAT64 (cloud IPv6-only subnets with NAT64 gateway), the encoded form routes to the embedded IPv4 and the curl connection terminates at the internal endpoint, defeating the deny. `is_global_host` (the helper that callers like `parse_urls` use against a URL hostname) feeds through `host_to_ip` which pins `family=AF_INET`, so hostname-based reach to these forms relies on the attacker supplying an IPv6 literal in the URL — but the curl PREREQFUNC sees the actual resolved IP (the AAAA returned for the hostname), so a hostname with an AAAA record set to one of the bypass forms reaches the same gap. Cross-reference: this is the same incomplete-coverage class as pydantic-ai's [GHSA-cqp8-fcvh-x7r3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-cqp8-fcvh-x7r3) / CVE-2026-46678. pyload-ng's prior SSRF advisories [GHSA-7gvf-3w72-p2pg](https://github.com/pyload/pyload/security/advisories/GHSA-7gvf-3w72-p2pg) and [GHSA-8rp3-xc6w-5qp5](https://github.com/pyload/pyload/security/advisories/GHSA-8rp3-xc6w-5qp5) both went through `is_global_host` / `is_global_address`; the IPv6 transition gap is orthogonal to those redirect-bypass classes. ## Severity **MEDIUM** — `CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:N/A:L` = **4.7** - `AC:H` — exploitation requires the host network to route 6to4 (`2002::/16` traffic), have a NAT64 gateway, or otherwise resolve the IPv6 transition form to an internal IPv4 endpoint at the TCP layer. - `PR:L` — `parse_urls` ([`src/pyload/core/api/__init__.py:582`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/api/__init__.py#L582)) requires `Perms.ADD`, which any account capable of adding links holds. The curl PREREQFUNC at [`http_request.py:680`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/http_request.py#L680) is reached by every downloader plugin that runs after `is_global_host` passed. - `C:L/A:L` — internal-network recon and timing-based confirmation; cloud-metadata exfiltration on networks where the transition form actually routes. **CWE-918**: Server-Side Request Forgery (SSRF). ## Affected versions `pyload-ng` from the introduction of `is_global_address` / `is_global_host` in [`src/pyload/core/utils/web/check.py`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/utils/web/check.py) up to an
AI Analysis
Technical Summary
The SSRF guard in pyload-ng uses the is_global_address function to block non-globally routable IPs, relying on Python's ipaddress.ip_address(value).is_global property. However, this property incorrectly returns True for IPv6 6to4 (2002::/16) and NAT64 (64:ff9b::/96) transition prefixes, which encapsulate internal IPv4 addresses. As a result, pyload-ng's SSRF protections can be bypassed by supplying IPv6 literals or AAAA DNS records that map to internal IPv4 addresses via these transition mechanisms. This leads to potential internal network reconnaissance and limited data exfiltration, such as cloud metadata access. The vulnerability affects pyload-ng versions from the introduction of is_global_address/is_global_host up to an unspecified fixed version. Exploitation requires the host network to route 6to4 or NAT64 traffic and privileges to add links (Perms.ADD).
Potential Impact
An attacker with limited privileges (Perms.ADD) can bypass SSRF protections in pyload-ng by exploiting the incorrect classification of IPv6 6to4 and NAT64 transition addresses as globally routable. This enables internal network reconnaissance and timing-based confirmation of internal endpoints, including potential exfiltration of cloud metadata services. The impact is limited to confidentiality and availability with no direct integrity impact. Exploitation requires specific network routing conditions (6to4 or NAT64) and is rated medium severity (CVSS 4.7).
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. Until a fix is available, users should be aware that SSRF protections relying on is_global_address may be bypassed via IPv6 transition addresses. Restricting or monitoring the use of IPv6 6to4 and NAT64 prefixes in network configurations and DNS records may reduce risk. Avoid running pyload-ng on Python versions 3.9 through 3.11 where 6to4 is classified as global. Follow vendor updates for official fixes.
Pyload ng: pyLoad: SSRF guard bypass via IPv6 6to4/NAT64 transition wrappers of internal IPs (CVE-2026-48737)
Description
## Summary `is_global_address` in [`src/pyload/core/utils/web/check.py`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/utils/web/check.py) is the central guard against SSRF-style outbound connections in pyload-ng. It tests whether a given IP is "globally routable" via Python's `ipaddress.ip_address(value).is_global`, and callers treat `not is_global` as "deny": ```python def is_global_address(value): try: return ipaddress.ip_address(value).is_global except ValueError: return False def is_global_host(value): ips = host_to_ip(value) return ips and all((is_global_address(ip) for ip in ips)) ``` Python's `ipaddress.IPv6Address.is_global` classifies the NAT64 well-known prefix as **globally routable** on every supported Python version (3.9 through 3.14 confirmed), and on older Pythons (3.9-3.11) the 6to4 prefix as well: | address | `is_global` on Py 3.9-3.11 | `is_global` on Py 3.12+ | wrapped IPv4 | |----------------------------------|---------------------------|--------------------------|----------------------| | `2002:7f00:0001::` (6to4) | True | False | 127.0.0.1 | | `2002:0a00:0001::` (6to4) | True | False | 10.0.0.1 | | `2002:a9fe:a9fe::` (6to4) | True | False | 169.254.169.254 (IMDS)| | `64:ff9b::a9fe:a9fe` (NAT64) | True | True | 169.254.169.254 | | `64:ff9b::7f00:1` (NAT64) | True | True | 127.0.0.1 | pyload-ng declares `python_requires = >=3.9` (`setup.cfg`), so deployments on Python 3.9-3.11 see the 6to4 path too. The NAT64 path is universal. `is_global` returns True for these wrappers, so `is_global_address` returns True and the deny check passes. The pycurl `PREREQFUNC` at [`src/pyload/core/network/http/http_request.py:680`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/network/http/http_request.py#L680) consults the same helper just before TCP-connect: ```python if not self.allow_private_ip: is_proxy_ip = self.http_proxy_host and self.http_proxy_host == (conn_primary_ip, conn_primary_port) if not is_global_address(conn_primary_ip) and not is_proxy_ip: return pycurl.PREREQFUNC_ABORT return pycurl.PREREQFUNC_OK ``` On a host with 6to4 routing (legacy operator tunnels; `2002::/16` still configurable) or NAT64 (cloud IPv6-only subnets with NAT64 gateway), the encoded form routes to the embedded IPv4 and the curl connection terminates at the internal endpoint, defeating the deny. `is_global_host` (the helper that callers like `parse_urls` use against a URL hostname) feeds through `host_to_ip` which pins `family=AF_INET`, so hostname-based reach to these forms relies on the attacker supplying an IPv6 literal in the URL — but the curl PREREQFUNC sees the actual resolved IP (the AAAA returned for the hostname), so a hostname with an AAAA record set to one of the bypass forms reaches the same gap. Cross-reference: this is the same incomplete-coverage class as pydantic-ai's [GHSA-cqp8-fcvh-x7r3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-cqp8-fcvh-x7r3) / CVE-2026-46678. pyload-ng's prior SSRF advisories [GHSA-7gvf-3w72-p2pg](https://github.com/pyload/pyload/security/advisories/GHSA-7gvf-3w72-p2pg) and [GHSA-8rp3-xc6w-5qp5](https://github.com/pyload/pyload/security/advisories/GHSA-8rp3-xc6w-5qp5) both went through `is_global_host` / `is_global_address`; the IPv6 transition gap is orthogonal to those redirect-bypass classes. ## Severity **MEDIUM** — `CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:N/A:L` = **4.7** - `AC:H` — exploitation requires the host network to route 6to4 (`2002::/16` traffic), have a NAT64 gateway, or otherwise resolve the IPv6 transition form to an internal IPv4 endpoint at the TCP layer. - `PR:L` — `parse_urls` ([`src/pyload/core/api/__init__.py:582`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/api/__init__.py#L582)) requires `Perms.ADD`, which any account capable of adding links holds. The curl PREREQFUNC at [`http_request.py:680`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/http_request.py#L680) is reached by every downloader plugin that runs after `is_global_host` passed. - `C:L/A:L` — internal-network recon and timing-based confirmation; cloud-metadata exfiltration on networks where the transition form actually routes. **CWE-918**: Server-Side Request Forgery (SSRF). ## Affected versions `pyload-ng` from the introduction of `is_global_address` / `is_global_host` in [`src/pyload/core/utils/web/check.py`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/utils/web/check.py) up to an
CVSS v3.1
Score 4.9medium
Affected software
Run on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.
Weaknesses
AI-Powered Analysis
Machine-generated threat intelligence
Technical Analysis
The SSRF guard in pyload-ng uses the is_global_address function to block non-globally routable IPs, relying on Python's ipaddress.ip_address(value).is_global property. However, this property incorrectly returns True for IPv6 6to4 (2002::/16) and NAT64 (64:ff9b::/96) transition prefixes, which encapsulate internal IPv4 addresses. As a result, pyload-ng's SSRF protections can be bypassed by supplying IPv6 literals or AAAA DNS records that map to internal IPv4 addresses via these transition mechanisms. This leads to potential internal network reconnaissance and limited data exfiltration, such as cloud metadata access. The vulnerability affects pyload-ng versions from the introduction of is_global_address/is_global_host up to an unspecified fixed version. Exploitation requires the host network to route 6to4 or NAT64 traffic and privileges to add links (Perms.ADD).
Potential Impact
An attacker with limited privileges (Perms.ADD) can bypass SSRF protections in pyload-ng by exploiting the incorrect classification of IPv6 6to4 and NAT64 transition addresses as globally routable. This enables internal network reconnaissance and timing-based confirmation of internal endpoints, including potential exfiltration of cloud metadata services. The impact is limited to confidentiality and availability with no direct integrity impact. Exploitation requires specific network routing conditions (6to4 or NAT64) and is rated medium severity (CVSS 4.7).
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. Until a fix is available, users should be aware that SSRF protections relying on is_global_address may be bypassed via IPv6 transition addresses. Restricting or monitoring the use of IPv6 6to4 and NAT64 prefixes in network configurations and DNS records may reduce risk. Avoid running pyload-ng on Python versions 3.9 through 3.11 where 6to4 is classified as global. Follow vendor updates for official fixes.
Technical Details
- Gcve Source
- db.gcve.eu
- Osv Id
- GHSA-m5x5-28jr-gpjj
- Osv Schema Version
- 1.4.0
- Aliases
- ["CVE-2026-48737"]
- Ecosystems
- ["PyPI"]
- Database Specific Severity
- MODERATE
- Cvss Version
- 3.1
Threat ID: 6a4fa9a168715ace437d3e27
Added to database: 07/09/2026, 14:01:05 UTC
Last enriched: 07/09/2026, 14:03:08 UTC
Last updated: 07/31/2026, 12:27:13 UTC
Views: 75
Community Reviews
0 reviewsCrowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.
Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.
Actions
Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.
Need more coverage?
Upgrade to Pro Console for AI refresh and higher limits.
For incident response and remediation, OffSeq services can help resolve threats faster.
Latest Threats
Check if your credentials are on the dark web
Instant breach scanning across billions of leaked records. Free tier available.