CVE-2026-72784
The critical thing to understand about CVE-2026-72784 is that the SSRF guard in this Craft CMS GraphQL mutation executes after the HTTP request has already been issued. The anti-SSRF check doesn't prevent the outbound connection—it audits the IP after the server has already opened a socket to the target. This temporal inversion is the architectural failure that matters. A security control that runs after the dangerous operation it claims to prevent isn't a control; it's logging with extra steps. The missing CGNAT range (100.64.0.0/10) and NAT64 prefix (64:ff9b::/96) are real gaps that need closing, but they emerged from the same design moment as the timing flaw. Someone wired up the fetch operation, then bolted on IP validation afterward because they remembered SSRF was a concern. Both defects shipped together from the same incomplete implementation. Fixing the timing without fixing the blocklist still leaves NAT64-routed internal services exposed. Fixing the blocklist without fixing the timing still leaves a post-hoc check that will accumulate new gaps as network topologies evolve. This timing inversion pattern is not unique to this CVE. It appears in path traversal checks performed after path construction, in command injection sanitization after string concatenation, in SQL injection validation after query assembly. The underlying issue is structural: development workflows handle side-effectful operations by thinking about what the operation does, then retrofitting whether it should be allowed. Validation gets placed at the resolution layer rather than the construction layer, and the same pattern reproduces across vulnerability classes. The NAT64 gap is specifically dangerous in containerized and cloud environments where NAT64 translation gateways map IPv4-only internal services to IPv6. An attacker enumerating NAT64 prefixes can route requests through these gateways to hit internal APIs that aren't RFC1918-addressable but are reachable via carrier infrastructure. A compromised Craft CMS instance behind a NAT64 gateway becomes a pivoting platform for that infrastructure, which the CVSS 5.4 rating doesn't capture—it measures how hard it is to pull the trigger, not how far the bullet travels. The existence of a validateIp() function makes this worse, not better. It creates the illusion of protection, which suppresses investigation. Nobody audits code that already has an SSRF check. That's the trap: deprecated or forgotten security controls calcify into assumptions, and they don't degrade gracefully—they persist because they look like intentional design rather than technical debt. The real remediation isn't just adding CIDR ranges to a blocklist; it's decoupling HTTP client initialization from the mutation resolver so validation happens at client configuration, not after the request fires. That architectural work has a longer disclosure-to-fix window than a one-line blocklist addition, but it's the only fix that prevents this pattern from recurring with whatever the next missing range turns out to be.
Reviewed through automated stages and approved by a human before publication.