crítica

CVE

CVE-2026-27771

CWE

CWE-284, CWE-862

Sistemas afectados

  • Gitea versions before 1.26.2 with the built-in OCI/container registry enabled
  • Forgejo and Gitea-derived forks sharing the affected container registry implementation
  • Self-hosted Gitea package registries where private container images may contain source code, credentials, TLS material, or deployment configuration
  • Internet-facing Gitea instances with anonymous access paths to /v2/ OCI registry endpoints

NoScope divulgó CVE-2026-27771, un fallo de autorización en el registro de contenedores integrado de Gitea que permitía a usuarios remotos no autenticados descargar imágenes de contenedores privadas de instancias autohospedadas afectadas. Gitea acreditó a NoScope en las notas de la versión 1.26.2 y publicó la corrección de seguridad relevante del registro de paquetes en esa versión.

Este es un problema de la cadena de suministro de software porque las imágenes de registro privadas son artefactos desplegables. A menudo contienen código de aplicación, grafos de dependencias, rutas internas, errores de caché de .npmrc o de gestores de paquetes, material TLS, endpoints de API y secretos incorporados accidentalmente en las capas. Descargar la imagen puede ser suficiente para reconstruir cómo se compila y despliega una aplicación.

Proyectos afectados

ProyectoEstado afectado
GiteaVersiones anteriores a 1.26.2 cuando el registro OCI/de contenedores integrado está habilitado
ForgejoReportado como afectado por NoScope cuando comparte la misma implementación de registro; los operadores deben seguir las versiones corregidas específicas de Forgejo cuando estén disponibles
Forks derivados de GiteaTratar como afectados hasta que el fork haya auditado o incorporado la corrección del registro de paquetes de Gitea

El límite operativo más seguro es “cualquier registro de Gitea o Forgejo autohospedado que almacenara imágenes de contenedores privadas antes de la corrección”. Aplicar el parche detiene las nuevas descargas no autenticadas, pero no demuestra que las capas de imágenes anteriores nunca se recuperaron.

Patrón de acceso vulnerable

Los registros OCI exponen metadatos de imágenes y contenido a través de endpoints predecibles:

GET /v2/<namespace>/<image>/manifests/<tag-or-digest>
GET /v2/<namespace>/<image>/blobs/<sha256:digest>

Para una imagen privada, la decisión de autorización debe vincular todos estos datos:

requester identity
requested package owner
package visibility: public | internal | private
token scope
repository/package ACL

Los análisis técnicos públicos describen la ruta vulnerable de Gitea como aquella que permite que un usuario anónimo o ghost alcance la API del registro sin una verificación de visibilidad del paquete. Reducido al error importante, la puerta de acceso se veía así:

func ReqContainerAccess(ctx *context.Context) {
    if ctx.Doer == nil || (setting.Service.RequireSignInViewStrict && ctx.Doer.IsGhost()) {
        apiUnauthorizedError(ctx)
        return
    }

    // Missing decision: is the requested package owner private/internal/public,
    // and is this requester allowed to pull its manifests and blobs?
}

Ese tipo de verificación pregunta “¿existe algún contexto de solicitud?” pero no responde “¿está este usuario autorizado para este paquete privado?”. Para imágenes de contenedores, eso es suficiente para filtrar el artefacto completo porque un manifiesto apunta a blobs y los blobs contienen las capas del sistema de archivos.

Por qué las imágenes filtradas se convierten en incidentes de credenciales

La privacidad de las imágenes de contenedores se trata comúnmente como un límite de código fuente y secretos. Una sola imagen puede revelar:

/app source code
package lockfiles
compiled frontend assets
runtime configuration templates
internal service hostnames
database connection strings
cloud SDK config files
private CA bundles
tokens accidentally copied during docker build
build arguments persisted in image history

Incluso cuando el sistema de archivos final no contiene un secreto visible, los metadatos de la imagen pueden revelar comandos de compilación e historial de capas:

docker history --no-trunc registry.example.internal/team/app:prod
docker save registry.example.internal/team/app:prod | tar -tf -

Para la respuesta a incidentes, asume que cada imagen privada en un registro afectado tiene el mismo nivel de exposición que un tarball filtrado. Luego verifica si la imagen también contenía credenciales que requieren rotación.

Triaje de exposición

Comienza con los hosts del registro, no solo con los repositorios de origen:

# Identify self-hosted Gitea versions.
gitea --version

# Search config for registry and anonymous view settings.
rg -n "PACKAGES|REQUIRE_SIGNIN_VIEW|container|registry" /etc/gitea /var/lib/gitea 2>/dev/null

# Inventory images that were meant to be private.
# Exact paths vary by deployment; export from Gitea's packages UI or database.

Para cada imagen privada publicada antes de la versión corregida:

  • Descarga una copia limpia desde una cuenta autenticada después de aplicar el parche.
  • Inspecciona docker history --no-trunc en busca de argumentos de compilación, comandos y archivos secretos copiados.
  • Exporta las capas y analízalas en busca de credenciales, certificados, .env, .npmrc, .pypirc, .m2/settings.xml, configuraciones de nube y material SSH.
  • Rota cualquier elemento encontrado en las capas o el historial, incluso si el archivo se eliminó en un paso posterior del Dockerfile.

Remediación

Actualiza Gitea a 1.26.2 o posterior. La versión incluye varias correcciones de seguridad, incluido el elemento del registro de paquetes acreditado a NoScope.

Si una actualización inmediata no es posible, NoScope recomienda requerir inicio de sesión para todo el contenido como medida temporal:

[service]
REQUIRE_SIGNIN_VIEW = true

Esa mitigación puede romper repositorios y registros de paquetes intencionalmente públicos, así que trátala como un control de emergencia mientras se planifica la actualización.

Después de aplicar el parche:

  • Rota los secretos encontrados dentro de las imágenes afectadas y cualquier credencial que pudiera desplegar esas imágenes.
  • Reconstruye las imágenes desde fuentes limpias después de eliminar los pasos del Dockerfile que producían secretos.
  • Elimina las versiones de imágenes privadas antiguas si contienen secretos que no se pueden acotar con confianza.
  • Revisa los registros de Gitea, del proxy inverso y del registro en busca de accesos no autenticados a /v2/ para manifiestos o blobs.
  • Prefiere identidades de carga de trabajo de corta duración en lugar de credenciales de larga duración incorporadas en imágenes o contextos de compilación.

La lección central es simple: un registro privado forma parte de la cadena de suministro de la aplicación. Si el modelo de autorización del registro falla, el artefacto de la aplicación se ha filtrado aunque el repositorio Git permanezca privado.

De la investigación a la remediación

Comprueba si este patrón existe en tu código

Convierte esta investigación en un flujo de remediación. Analiza dependencias y manifiestos para detectar riesgos similares en la cadena de suministro y prioriza las correcciones con contexto de alcanzabilidad.

Referencias