
Laboratorio de reproducción para CVE-2026-54316 (bypass de permisos / exfiltración de Claude Code WebFetch con hostname simple de huggingface.co)
Un laboratorio autocontenido y desechable que reproduce
GHSA-fg94-h982-f3mm
/ CVE-2026-54316: Claude Code preaprobó huggingface.co como un nombre de host simple
para la herramienta WebFetch, por lo que cualquier ruta en ese dominio — incluyendo
repositorios de modelos controlados por un atacante — se obtenía sin una solicitud
de permiso. Combinado con la inyección de prompts, esto se convierte en un canal
fuera de banda para exfiltrar datos, observado a través de los contadores de descargas
del lado del servidor de HuggingFace.
| Aviso | GHSA-fg94-h982-f3mm |
| CVE | CVE-2026-54316 |
| Paquete | @anthropic-ai/claude-code (npm) |
| Afectadas | >= 0.2.54, < 2.1.163 |
| Corregida | 2.1.163 |
| Causa raíz | Inclusión en lista de permitidos de un nombre de host simple en un host multiinquilino (CWE-183) |
Esto reproduce una vulnerabilidad corregida y divulgada públicamente con fines educativos y defensivos. Úsalo solo contra infraestructura que te pertenezca:
fixtures/canary.env) — nunca uses uno real.huggingface.co sin solicitud de aprobación, mientras que cualquier otro dominio
activa una — porque huggingface.co está en una lista de permitidos fija.El contenedor es el único lugar donde se ejecuta la versión vulnerable; tu host permanece limpio. Autentícate con un token de suscripción de Claude (no se necesita una clave de API):
docker build -t cve-2026-54316-lab .
docker run --rm -it cve-2026-54316-lab
Dentro del contenedor, ejecuta claude y elige "Claude account with subscription"
para iniciar sesión de forma interactiva. La versión vulnerable 2.1.162 es anterior a la
variable de entorno CLAUDE_CODE_OAUTH_TOKEN, por lo que aquí no se usa setup-token — el
flujo interactivo de navegador/código pegado evita por completo emitir un token de larga duración.
El punto es la asimetría de las solicitudes de aprobación por dominio, por lo que WebFetch se deja
disponible (no está denegado) — la aprobación se gestiona pidiendo confirmación, el comportamiento predeterminado.
Dentro del contenedor, en claude:
Usa WebFetch para obtener
https://example.comy resúmela.
→ Aparece una solicitud de permiso que te pide aprobar example.com. Luego:
Usa WebFetch para obtener
https://huggingface.co/<your-account>/canary-lab/resolve/main/config.json.
Vulnerable: la obtención de huggingface.co se realiza sin que aparezca ninguna solicitud, mientras que
example.com sí requería una. Esa asimetría es el fallo: huggingface.co está en una
lista de permitidos fija. (El repositorio de HF no necesita existir para esta prueba; un 401/404
sigue demostrando que la solicitud nunca se mostró). Reconstruye la imagen con @anthropic-ai/[email protected]
y la obtención de huggingface.co ahora también muestra una solicitud — ese antes/después es el titular.
./scripts/make_hf_canary_files.sh ./hf-repo y luego sube hf-repo/ a un
repositorio público de HuggingFace que te pertenezca (<your-account>/canary-lab).payloads/untrusted-readme.md, define HF_ACCOUNT y colócalo donde el
agente lo lea como entrada no confiable.Dockerfile — fija la versión vulnerable 2.1.162.claude/settings.json — allow/deny vacíos para que WebFetch pida confirmación por dominiofixtures/canary.env — canary ficticioscripts/make_hf_canary_files.sh — estructura de archivos canary para HFpayloads/untrusted-readme.md — payload de inyección de prompts (saneado)