Every CVE Search/ Get API key

CVE-2026-111171

Web3.py 7.15.0 through 7.16.0 and 8.0.0b2 through 8.0.0 CCIP-Read SSRF Bypass

6.3 Medium

Web3.py 7.15.0 through 7.16.0 and 8.0.0b2 through 8.0.0 contains a server-side request forgery vulnerability because _check_ip_blocked() does not unwrap IPv4-mapped IPv6 addresses in CCIP Read URL validation. Malicious contracts can return OffchainLookup URLs with IPv4-mapped IPv6 hosts or AAAA records, making clients with CCIP Read enabled send requests to loopback, private, or link-local services.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
High
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
Low
Integrity
Low
Availability
None

Exploit likelihood

0.34%Unchanged since Oct 16, 2026
90%50%10%1%

What each source reports

CVE List Score used 6.3

Web3.py 7.15.0 through 7.16.0 and 8.0.0b2 through 8.0.0 CCIP-Read SSRF Bypass

Web3.py 7.15.0 through 7.16.0 and 8.0.0b2 through 8.0.0 contains a server-side request forgery vulnerability because _check_ip_blocked() does not unwrap IPv4-mapped IPv6 addresses in CCIP Read URL validation. Malicious contracts can return OffchainLookup URLs with IPv4-mapped IPv6 hosts or AAAA records, making clients with CCIP Read enabled send requests to loopback, private, or link-local services.

Record
CVE-2026-111171
CVSS 4.0
6.3 MediumCVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N
Weakness
CWE-918
Updated
2026-11-02
EUVDEUVD-2026-102298 6.3

Web3.py 7.15.0 through 7.16.0 and 8.0.0b2 through 8.0.0 contains a server-side request forgery vulnerability because _check_ip_blocked() does not unwrap IPv4-mapped IPv6 addresses in CCIP Read URL validation. Malicious contracts can return OffchainLookup URLs with IPv4-mapped IPv6 hosts or AAAA records, making clients with CCIP Read enabled send requests to loopback, private, or link-local services.

Record
EUVD-2026-102298
CVSS 4.0
6.3 MediumCVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-w8h5-xcmp-474f 6.3

Web3.py 7.15.0 through 7.16.0 and 8.0.0b2 through 8.0.0 contains a server-side request forgery...

Web3.py 7.15.0 through 7.16.0 and 8.0.0b2 through 8.0.0 contains a server-side request forgery vulnerability because _check_ip_blocked() does not unwrap IPv4-mapped IPv6 addresses in CCIP Read URL validation. Malicious contracts can return OffchainLookup URLs with IPv4-mapped IPv6 hosts or AAAA records, making clients with CCIP Read enabled send requests to loopback, private, or link-local services.

Record
GHSA-w8h5-xcmp-474f
CVSS 4.0
6.3 MediumCVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N
Weakness
CWE-918
Updated
2026-11-02
NVD 6.3

Web3.py 7.15.0 through 7.16.0 and 8.0.0b2 through 8.0.0 contains a server-side request forgery vulnerability because _check_ip_blocked() does not unwrap IPv4-mapped IPv6 addresses in CCIP Read URL validation. Malicious contracts can return OffchainLookup URLs with IPv4-mapped IPv6 hosts or AAAA records, making clients with CCIP Read enabled send requests to loopback, private, or link-local services.

Record
CVE-2026-111171
CVSS 4.0
6.3 MediumCVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N
Weakness
CWE-918
Updated
2026-11-02
OSV 6.3

Web3.py 7.15.0 through 7.16.0 and 8.0.0b2 through 8.0.0 CCIP-Read SSRF Bypass

Web3.py 7.15.0 through 7.16.0 and 8.0.0b2 through 8.0.0 contains a server-side request forgery vulnerability because _check_ip_blocked() does not unwrap IPv4-mapped IPv6 addresses in CCIP Read URL validation. Malicious contracts can return OffchainLookup URLs with IPv4-mapped IPv6 hosts or AAAA records, making clients with CCIP Read enabled send requests to loopback, private, or link-local services.

Record
CVE-2026-111171
CVSS 4.0
6.3 MediumCVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N
Weakness
CWE-918
Updated
2026-11-02
OSVCVE-2026-40072 1.7

web3.py affected by SSRF via CCIP Read (EIP-3668) OffchainLookup URL handling

web3.py allows you to interact with the Ethereum blockchain using Python. From 6.0.0b3 to before 7.15.0 and 8.0.0b2, web3.py implements CCIP Read / OffchainLookup (EIP-3668) by performing HTTP requests to URLs supplied by smart contracts in offchain_lookup_payload["urls"]. The implementation uses these contract-supplied URLs directly (after {sender} / {data} template substitution) without any destination validation. CCIP Read is enabled by default (global_ccip_read_enabled = True on all providers), meaning any application using web3.py's .call() method is exposed without explicit opt-in. This results in Server-Side Request Forgery (SSRF) when web3.py is used in backend services, indexers, APIs, or any environment that performs eth_call / .call() against untrusted or user-supplied contract addresses. A malicious contract can force the web3.py process to issue HTTP requests to arbitrary destinations, including internal network services and cloud metadata endpoints. This vulnerability is fixed in 7.15.0 and 8.0.0b2.

Record
CVE-2026-40072
CVSS 4.0
1.7 LowCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:U
Weakness
CWE-918
Updated
2026-11-02
OSVGHSA-5hr4-253g-cpx2 6.9

web3.py: SSRF via CCIP Read (EIP-3668) OffchainLookup URL handling

Summary

web3.py implements CCIP Read / OffchainLookup (EIP-3668) by performing HTTP requests to URLs supplied by smart contracts in offchain_lookup_payload["urls"]. The implementation uses these contract-supplied URLs directly (after {sender} / {data} template substitution) without any destination validation:

  • No restriction to https:// (and no opt-in gate for http://)
  • No hostname or IP allowlist
  • No blocking of private/reserved IP ranges (loopback, link-local, RFC1918)
  • No redirect target validation (both requests and aiohttp follow redirects by default)

CCIP Read is enabled by default (global_ccip_read_enabled = True on all providers), meaning any application using web3.py's .call() method is exposed without explicit opt-in.

This results in Server-Side Request Forgery (SSRF) when web3.py is used in backend services, indexers, APIs, or any environment that performs eth_call / .call() against untrusted or user-supplied contract addresses. A malicious contract can force the web3.py process to issue HTTP requests to arbitrary destinations, including internal network services and cloud metadata endpoints.


Why This Is a Vulnerability

The argument is not that CCIP Read itself is invalid or that web3.py should stop supporting EIP-3668. The issue is that, in server-side deployments (backends, indexers, bots, APIs), the current implementation doesn't provide destination policy controls, such as a validation/override hook, private-range blocking, or redirect target checks, which means contract controlled CCIP URLs can be used as an SSRF primitive.

This is consistent with EIP-3668's own security considerations, which recommends that client libraries "provide clients with a hook to override CCIP read calls, either by rewriting them to use a proxy service, or by denying them entirely" and that "this mechanism or another should be written so as to easily facilitate adding domains to allowlists or blocklists." The mitigations I'm suggesting are meant to align with that guidance without breaking CCIP Read support.

  • Default-on exposure. CCIP Read is enabled by default on all web3.py providers (global_ccip_read_enabled = True). Users who never intend to use CCIP Read, and who may not even know the feature exists, are silently exposed. A feature that makes unsanitized outbound requests to attacker-controlled URLs should not be enabled by default without safety guardrails.

  • Library vs. application responsibility. web3.py is a widely-used library. Expecting every downstream application to independently implement SSRF protections around .call() is unreasonable, especially for a feature that fires automatically and invisibly on a specific revert pattern. Safe defaults at the library level are the standard expectation for any library that issues outbound HTTP requests to externally-controlled URLs.


Affected Code

Sync CCIP handler

File: web3/utils/exception_handling.py (lines 42-58)

Contract-controlled URLs are requested via requests with no destination validation:

session = requests.Session()
for url in offchain_lookup_payload["urls"]:
    formatted_url = URI(
        str(url)
        .replace("{sender}", str(formatted_sender))
        .replace("{data}", str(formatted_data))
    )

    try:
        if "{data}" in url and "{sender}" in url:
            response = session.get(formatted_url, timeout=DEFAULT_HTTP_TIMEOUT)
        else:
            response = session.post(
                formatted_url,
                json={"data": formatted_data, "sender": formatted_sender},
                timeout=DEFAULT_HTTP_TIMEOUT,
            )

(The request is issued before response validation; subsequent logic parses JSON and enforces a "data" field.)

Key observations:

  • requests follows redirects by default (allow_redirects=True).
  • No allow_redirects=False is set.
  • No validation of formatted_url before the request.
  • The placeholder check…
Record
GHSA-5hr4-253g-cpx2
CVSS 4.0
6.9 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N
CVSS 3.1
7.2 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Weakness
CWE-918
Updated
2026-11-02
OSVPYSEC-2026-3414 6.9

web3.py: SSRF via CCIP Read (EIP-3668) OffchainLookup URL handling

Summary

web3.py implements CCIP Read / OffchainLookup (EIP-3668) by performing HTTP requests to URLs supplied by smart contracts in offchain_lookup_payload["urls"]. The implementation uses these contract-supplied URLs directly (after {sender} / {data} template substitution) without any destination validation:

  • No restriction to https:// (and no opt-in gate for http://)
  • No hostname or IP allowlist
  • No blocking of private/reserved IP ranges (loopback, link-local, RFC1918)
  • No redirect target validation (both requests and aiohttp follow redirects by default)

CCIP Read is enabled by default (global_ccip_read_enabled = True on all providers), meaning any application using web3.py's .call() method is exposed without explicit opt-in.

This results in Server-Side Request Forgery (SSRF) when web3.py is used in backend services, indexers, APIs, or any environment that performs eth_call / .call() against untrusted or user-supplied contract addresses. A malicious contract can force the web3.py process to issue HTTP requests to arbitrary destinations, including internal network services and cloud metadata endpoints.


Why This Is a Vulnerability

The argument is not that CCIP Read itself is invalid or that web3.py should stop supporting EIP-3668. The issue is that, in server-side deployments (backends, indexers, bots, APIs), the current implementation doesn't provide destination policy controls, such as a validation/override hook, private-range blocking, or redirect target checks, which means contract controlled CCIP URLs can be used as an SSRF primitive.

This is consistent with EIP-3668's own security considerations, which recommends that client libraries "provide clients with a hook to override CCIP read calls, either by rewriting them to use a proxy service, or by denying them entirely" and that "this mechanism or another should be written so as to easily facilitate adding domains to allowlists or blocklists." The mitigations I'm suggesting are meant to align with that guidance without breaking CCIP Read support.

  • Default-on exposure. CCIP Read is enabled by default on all web3.py providers (global_ccip_read_enabled = True). Users who never intend to use CCIP Read, and who may not even know the feature exists, are silently exposed. A feature that makes unsanitized outbound requests to attacker-controlled URLs should not be enabled by default without safety guardrails.

  • Library vs. application responsibility. web3.py is a widely-used library. Expecting every downstream application to independently implement SSRF protections around .call() is unreasonable, especially for a feature that fires automatically and invisibly on a specific revert pattern. Safe defaults at the library level are the standard expectation for any library that issues outbound HTTP requests to externally-controlled URLs.


Affected Code

Sync CCIP handler

File: web3/utils/exception_handling.py (lines 42-58)

Contract-controlled URLs are requested via requests with no destination validation:

session = requests.Session()
for url in offchain_lookup_payload["urls"]:
    formatted_url = URI(
        str(url)
        .replace("{sender}", str(formatted_sender))
        .replace("{data}", str(formatted_data))
    )

    try:
        if "{data}" in url and "{sender}" in url:
            response = session.get(formatted_url, timeout=DEFAULT_HTTP_TIMEOUT)
        else:
            response = session.post(
                formatted_url,
                json={"data": formatted_data, "sender": formatted_sender},
                timeout=DEFAULT_HTTP_TIMEOUT,
            )

(The request is issued before response validation; subsequent logic parses JSON and enforces a "data" field.)

Key observations:

  • requests follows redirects by default (allow_redirects=True).
  • No allow_redirects=False is set.
  • No validation of formatted_url before the request.
  • The placeholder check…
Record
PYSEC-2026-3414
CVSS 4.0
6.9 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N
CVSS 3.1
7.2 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
web3
PyPI
From an advisory covering 2 CVEs
6.0.0b3 up to 7.15.0, plus listed versions
6.0.06.0.0b106.0.0b116.0.0b46.0.0b5
Show 45 moreShow less
6.0.0b66.0.0b76.0.0b86.0.0b96.1.06.10.06.11.06.11.16.11.26.11.36.11.46.12.06.13.06.14.06.15.06.15.16.16.06.17.06.17.16.17.26.18.06.19.06.2.06.20.06.20.16.20.26.20.36.20.46.3.06.4.06.5.06.6.06.6.16.7.06.8.06.9.07.0.07.0.0b17.0.0b27.0.0b37.0.0b47.0.0b57.0.0b67.0.0b77.0.0b8
7.15.0
web3
PyPI
From an advisory covering 2 CVEs
8.0.0b1 up to 8.0.0b2
8.0.0b2
web3
PyPI
From an advisory covering 2 CVEs
6.0.0b3 up to 7.15.0, 8.0.0b1 up to 8.0.0b2, plus listed versions
6.0.06.0.0b106.0.0b116.0.0b46.0.0b5
Show 45 moreShow less
6.0.0b66.0.0b76.0.0b86.0.0b96.1.06.10.06.11.06.11.16.11.26.11.36.11.46.12.06.13.06.14.06.15.06.15.16.16.06.17.06.17.16.17.26.18.06.19.06.2.06.20.06.20.16.20.26.20.36.20.46.3.06.4.06.5.06.6.06.6.16.7.06.8.06.9.07.0.07.0.0b17.0.0b27.0.0b37.0.0b47.0.0b57.0.0b67.0.0b77.0.0b8
7.15.08.0.0b2

History

History
RecordedChangedSources
affected, facts
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-111171 is a medium vulnerability (CVSS 6.3) in Ethereum Web3.py, published April 4, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.34%, the 27th percentile. No source names a fixed version.

References

Show 9 moreShow less
This page doesn't list everything

Left out here: 40 versions and the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open