Introducción
Hace solo 13 días, un equipo de investigación en seguridad detectó los primeros intentos de explotación in-the-wild de CVE-2026-20896, una vulnerabilidad crítica (CVSS 9.8) en las imágenes oficiales de Gitea Docker. El problema no es un fallo en Gitea en sí, sino en la configuración predeterminada de su archivo app.ini dentro de los contenedores oficiales. Esa configuración insegura convierte a cualquier cliente con acceso al puerto HTTP del contenedor en un superusuario, sin necesidad de credenciales ni tokens. El vector de ataque es directo: enviar un header HTTP X-WEBAUTH-USER manipulado a un servidor Gitea expuesto, incluso cuando está detrás de un proxy inverso que debería validar usuarios.
El riesgo no es teórico. Según Sysdig, se detectó actividad desde una IP asociada a ProtonVPN (159.26.98[.]241) en menos de dos semanas tras la publicación del CVE. Aunque aún no se observó explotación completa, el potencial de takeover de cuentas administrativas es inmediato. Peor aún: alrededor de 6.200 instancias de Gitea están expuestas en Internet, según datos de escaneo público.
Qué ocurrió
El 30 de junio de 2026, Gitea lanzó la versión 1.26.3 de sus imágenes Docker, que corrige CVE-2026-20896. Pero durante los 13 días posteriores a la disclosure pública, actores maliciosos ya estaban escaneando instancias vulnerables. La vulnerabilidad surge de dos decisiones de diseño problemáticas en las imágenes oficiales:
- Configuración predeterminada insegura: Las imágenes Docker de Gitea incluían un template de
app.inique establecíaREVERSE_PROXY_TRUSTED_PROXIES = *sin sobrescribirlo. Eso permite que cualquier IP con acceso al puerto 3000 (o el que use el contenedor) envíe headers HTTP personalizados, incluyendoX-WEBAUTH-USER.
- Autenticación inversa mal configurada: Cuando un administrador activa el modo
ENABLE_REVERSE_PROXY_AUTHENTICATION = truepara poner Gitea detrás de un proxy inverso (como NGINX, Traefik o Cloudflare), el sistema confía ciegamente en el headerX-WEBAUTH-USERsi el origen está en la lista de IPs permitidas. Pero como la lista predeterminada es*, todos los orígenes están permitidos.
El resultado es que un atacante puede:
- Enviar una petición HTTP con
GET / HTTP/1.1y el headerX-WEBAUTH-USER: admin, obteniendo acceso de administrador sin contraseña. - Crear cuentas con nombres de usuario conocidos (ej: «gitea_admin») y luego usarlas para takeover de repositorios o ejecución de código.
- Si el registro automático (
DISABLE_REGISTRATION = false) está habilitado, un atacante puede registrarse como admin directamente.
El investigador Ali Mustafa (@rz1027), quien reportó el fallo, aclaró en declaraciones a The Hacker News: «Con el wildcard *, cualquier proceso que pueda llegar al puerto HTTP de Gitea —no necesariamente a través del proxy inverso— puede suplantar cualquier usuario cuyo nombre de login sea conocido o adivinable».
Impacto para DevOps / Infraestructura / Cloud / Seguridad
Para equipos de DevOps e Infraestructura
- Alcance del ataque: Cualquier entorno que use las imágenes oficiales de Gitea Docker versiones ≤ 1.26.2 está potencialmente afectado, incluso si el servicio no está expuesto públicamente. Si el contenedor tiene un puerto mapeado a la red (ej:
3000:3000), cualquier host en la misma red —incluyendo contenedores vecinos— puede enviar headers manipulados.
- Impacto en CI/CD: Si Gitea se usa como backend de autenticación para pipelines (ej: con Jenkins o GitLab Runner), un atacante podría modificar los headers de autenticación y ejecutar pipelines arbitrarias. Ejemplo:
curl -H "X-WEBAUTH-USER: jenkins-admin" http://gitea-container:3000/api/v1/user
Esto devolvería los datos del usuario jenkins-admin, incluso si ese usuario no existe.
- Exposición en cloud: En entornos como Kubernetes o ECS, si el Service o Task Definition expone el puerto 3000 sin NetworkPolicy restrictiva, cualquier pod o task en el mismo namespace puede atacar Gitea. En AWS, por ejemplo, un Security Group que permita tráfico TCP 3000 desde
0.0.0.0/0(o incluso desde la VPC) es suficiente para explotar el fallo.
Para equipos de Seguridad
- Vector de ataque real: Aunque la explotación requiere acceso al puerto HTTP del contenedor, en entornos mal configurados ese puerto suele estar expuesto a redes internas o incluso públicas. Según datos de Shodan, al 10 de julio de 2026 había 6.200 instancias de Gitea accesibles desde Internet, muchas de ellas en proveedores cloud sin restricciones de red adecuadas.
- CVSS 9.8: La severidad es máxima porque permite ejecución de código arbitrario (si el usuario admin ejecuta comandos en el repo) y toma de control total del sistema. No hay necesidad de explotar una RCE; basta con enviar un header HTTP.
- Actividad temprana detectada: Sysdig reportó actividad desde una IP vinculada a ProtonVPN (159.26.98[.]241) el 5 de julio de 2026, solo 13 días después de la disclosure. Aunque aún no se observó explotación activa, el patrón sugiere reconocimiento previo para explotación futura.
Detalles técnicos
Componente afectado
- Producto: Gitea Docker (imágenes oficiales).
- Versiones afectadas: Todas las etiquetas de Docker ≤ 1.26.2 (incluyendo
latest,1,1.26,1.26.2). - Arquitecturas afectadas: Multi-arquitectura (amd64, arm64, arm/v7) porque el fallo está en el template de configuración, no en el binario de Gitea.
- Lenguaje: Rust (Gitea está escrito en Go, pero el problema es de configuración en el contenedor).
Vector de ataque
El ataque se basa en tres condiciones previas:
- Gitea está configurado para autenticación inversa:
ENABLE_REVERSE_PROXY_AUTHENTICATION = true. - El proxy inverso está mal configurado: En lugar de restringir
REVERSE_PROXY_TRUSTED_PROXIESa las IPs del proxy (ej:127.0.0.0/8,::1/128), usa el wildcard*. - El puerto HTTP del contenedor es accesible: Ya sea desde Internet, una VPC o incluso la red local.
El payload es trivial:
GET / HTTP/1.1
Host: gitea-container
X-WEBAUTH-USER: adminSi el contenedor responde con un estado 200 o redirige a /user/login, el ataque fue exitoso.
¿Por qué ocurrió?
El archivo app.ini en las imágenes Docker oficiales incluía esta línea por defecto:
[auth]
REVERSE_PROXY_TRUSTED_PROXIES = *Mientras que la documentación oficial de Gitea recomienda:
REVERSE_PROXY_TRUSTED_PROXIES = 127.0.0.0/8,::1/128La diferencia es crítica: el wildcard * permite cualquier IP como proxy de confianza, mientras que la lista segura solo permite localhost.
Ejemplo de explotación en un entorno vulnerable
Supongamos un cluster Kubernetes con Gitea expuesto así:
apiVersion: v1
kind: Service
metadata:
name: gitea
spec:
selector:
app: gitea
ports:
- protocol: TCP
port: 3000
targetPort: 3000
type: LoadBalancerSi un atacante descubre la IP del LoadBalancer (digamos 203.0.113.45:3000), puede enviar:
curl -H "X-WEBAUTH-USER: admin" http://203.0.113.45:3000/Y recibirá una respuesta con privilegios de administrador.
Qué deberían hacer los administradores y equipos técnicos
1. Actualizar las imágenes Docker inmediatamente
Todos los entornos que usen Gitea en contenedores deben actualizarse a versión 1.26.3 o superior. Las imágenes afectadas incluyen tags como gitea/gitea:1.26, gitea/gitea:latest, y todas las versiones ≤ 1.26.2.
- Docker Compose:
services:
gitea:
image: gitea/gitea:1.26.3
# ... resto de la configuración ...
Luego:
docker compose pull && docker compose up -d
- Kubernetes (Deployment):
spec:
containers:
- name: gitea
image: gitea/gitea:1.26.3
Aplicar con:
kubectl apply -f gitea-deployment.yaml
kubectl rollout status deployment/gitea
- Terraform (AWS ECS):
resource "aws_ecs_task_definition" "gitea" {
container_definitions = jsonencode([{
image = "gitea/gitea:1.26.3"
# ... resto ...
}])
}
2. Revisar y corregir la configuración de REVERSE_PROXY_TRUSTED_PROXIES
Tras actualizar, verificar que la configuración en app.ini (o en variables de entorno) sea:
[auth]
REVERSE_PROXY_TRUSTED_PROXIES = 127.0.0.0/8,::1/128
ENABLE_REVERSE_PROXY_AUTHENTICATION = trueO, si usás variables de entorno:
export GITEA__AUTH__REVERSE_PROXY_TRUSTED_PROXIES="127.0.0.0/8,::1/128"
export GITEA__AUTH__ENABLE_REVERSE_PROXY_AUTHENTICATION="true"3. Restringir el acceso al puerto HTTP del contenedor
Si Gitea está en un entorno cloud o Kubernetes:
- En Kubernetes: Crear un
NetworkPolicyque solo permita tráfico desde el proxy inverso (ej: Traefik, NGINX Ingress):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: gitea-allow-proxy-only
spec:
podSelector:
matchLabels:
app: gitea
ingress:
- from:
- podSelector:
matchLabels:
app: traefik
ports:
- protocol: TCP
port: 3000
- En AWS/EKS: Modificar el Security Group del LoadBalancer o EC2 para que solo acepte tráfico desde el proxy inverso (ej: desde la IP del balanceador de NGINX).
4. Verificar la exposición de instancias
Usar herramientas como shodan o censys para buscar instancias públicas de Gitea:
shodan search 'gitea' --fields ip_str,portSi encontrás instancias expuestas, priorizá su actualización o aislamiento.
5. Auditar logs y configuraciones post-actualización
Revisar logs de Gitea en busca de intentos de explotación:
docker logs gitea 2>&1 | grep -i "X-WEBAUTH-USER"Si hay registros con este header, investigá posibles ataques.
Conclusión
CVE-2026-20896 es un recordatorio de que los fallos de seguridad no siempre están en el código, sino en su configuración por defecto. Las imágenes oficiales de Gitea Docker distribuyeron durante meses un template de app.ini que convertía la autenticación inversa en una puerta abierta para cualquier atacante con acceso al puerto HTTP. La corrección fue simple (remover el wildcard *), pero el daño potencial —takeover de cuentas admin, ejecución de pipelines arbitrarias, robo de datos— es enorme.
La explotación in-the-wild ya comenzó, con actividad detectada a solo 13 días de la disclosure. Equipos de DevOps y Seguridad deben actuar ya: actualizar imágenes, corregir configuraciones, restringir accesos y auditar entornos. Ignorar este CVE es equivalente a dejar una llave maestra en la puerta de entrada de tu infraestructura.
