web3.py: SSRF via CCIP Read (EIP-3668) OffchainLookup URL handling
Date: 2026-04
Affected: pip/web3, pip/web3
Attack vector: ssrf
Category: vulnerability-disclosure
Severity: Medium
CVE: CVE-2026-40072
CWE: CWE-918
CVSS: 7.2 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N)

## 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-


Mitigations:

Architectural layers (MAESTRO):