# Carpeta .git pública: una fuga de datos subestimada

> ¿Es pública su carpeta .git? Cómo comprobarlo, bloquear el acceso, cambiar el despliegue y tratar las credenciales que quedan en el historial.

Fuente: https://phpsos.de/es/blog/git-ordner-oeffentlich/  
Actualizado: 25/10/2026  
Proveedor: PHP SOS, Ayuda de emergencia para PHP y seguridad de servidores. Ayuda inmediata por WhatsApp: https://wa.me/491736494914?text=Hola%20PHP%20SOS%2C%20necesitamos%20ayuda%20con%20nuestro%20servidor%20PHP.%20Empresa%3A%20%E2%80%A6%20Sitio%20web%3A%20%E2%80%A6

**En resumen:** una carpeta .git pública surge cuando un sitio web se despliega con `git clone` o `git pull` directamente en el webroot y el servidor web no bloquea las carpetas ocultas. Entonces puede descargarse todo el código fuente con su historial, incluidas credenciales incluidas en commits antiguos. Compruebe sus dominios con una sencilla llamada, bloquee el acceso de inmediato, cambie el despliegue a paquetes sin `.git` y sustituya las credenciales del historial.

## El código fuente para llevárselo

Git es la herramienta estándar de control de versiones y, para equipos pequeños, resulta natural usarla también para desplegar: conectarse al servidor, `git pull`, listo. Funciona con fiabilidad y es rápido. Pero tiene un efecto secundario que a menudo nadie advierte.

En la carpeta del proyecto hay una carpeta oculta `.git`. No contiene solo el estado actual, sino cada archivo en cada versión que se haya incluido alguna vez, además de mensajes de commit, nombres y direcciones de correo de los desarrolladores y referencias a servidores. Si esta carpeta está en el webroot y el servidor web la sirve, cualquiera puede descargarla.

Para los atacantes es un regalo. Con el código fuente pueden buscarse vulnerabilidades de forma dirigida, en lugar de adivinarlas desde fuera. Y en el historial se encuentran a menudo cosas que parecían borradas hace tiempo: una contraseña de base de datos de los comienzos, una clave de API, un archivo de prueba con datos de clientes.

## ¿Es pública su carpeta .git? Cómo comprobarlo

La comprobación lleva segundos y no modifica nada. Para cada dominio y subdominio, llame a un archivo que existe en todo repositorio Git:

```bash
# Esperado: 403 o 404
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/HEAD
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/config
# En el servidor: ¿hay carpetas .git por debajo de los webroots?
find /var/www /srv/www -maxdepth 4 -type d -name ".git" 2>/dev/null
```

Un estado 200 significa que la carpeta es accesible. Preste atención también a los subdirectorios. A veces el repositorio no está en el propio webroot, sino en una carpeta de plugin o de tema que se mantiene por separado con Git.

Revise además los entornos de staging y de pruebas. Se actualizan con Git más a menudo que la producción y con frecuencia son accesibles en subdominios fáciles de adivinar.

## De inmediato: bloquear el acceso

Hasta que se cambie el despliegue, una regla en el servidor web bloquea el acceso a las carpetas del control de versiones. Un bloqueo general de archivos ocultos, como se describe en [Proteger correctamente las credenciales y los archivos .env](https://phpsos.de/es/blog/env-dateien-schuetzen/), lo cubre también. Quien quiera bloquear solo el control de versiones usa una regla más específica:

```nginx
location ~ /\.(git|svn|hg)(/|$) {
    return 404;
}
```

```apache
RedirectMatch 404 /\.(git|svn|hg)(/|$)
```

Después, repita la comprobación de arriba, y hágalo con una llamada real desde fuera: una prueba de configuración correcta solo dice que la sintaxis es válida, no que la regla actúe antes que otras reglas para archivos estáticos. En paneles como Plesk o cPanel, introduzca la regla en las directivas adicionales previstas para ello, para que no se pierda en la siguiente generación de la configuración.

> **Actuar de inmediato:**
> Si la carpeta era accesible, trate como conocidas todas las credenciales que alguna vez estuvieron en el repositorio. Bloquear no basta entonces: hay que sustituir los valores.

## De forma permanente: desplegar sin .git en el webroot

El bloqueo es una protección, no una solución. De forma permanente, el control de versiones no pertenece al servidor de producción. Caminos acreditados, según su entorno:

| Procedimiento | Cómo funciona | Adecuado para |
|---|---|---|
| Paquete de build desde la CI | La pipeline genera un archivo sin `.git`; el servidor lo descomprime en un nuevo directorio de release | Equipos con CI/CD |
| `git archive` | Genera un archivo de un estado sin datos de versiones | Proyectos pequeños sin pipeline |
| `rsync` con exclusiones | Transfiere solo los archivos necesarios | Servidores clásicos |
| Imagen de contenedor | El código se copia a la imagen en la construcción, `.git` se excluye mediante `.dockerignore` | Operación con contenedores |

Un directorio de release por versión, con un enlace simbólico al estado actual, tiene otra ventaja: ante problemas puede volver atrás de inmediato. Para configuraciones con contenedores, [CI/CD: reconstruir automáticamente las imágenes de PHP](https://phpsos.de/es/blog/php-images-in-ci-neu-bauen/) describe cómo hacer reproducibles los builds. Allí debería comprobarse también que `.git` no llega a la imagen.

```bash
# Ejemplo: generar un paquete de un estado sin datos de versiones
git archive --format=tar.gz -o release.tar.gz HEAD
```

## Otros archivos del proyecto que no pertenecen al webroot

La carpeta `.git` es el ejemplo más conocido, pero no el único. Quien despliega directorios de proyecto enteros lleva al webroot otros archivos que no tienen nada que hacer allí:

- Carpetas de entornos de desarrollo como `.idea` o `.vscode`, en las que las extensiones para la subida de archivos guardan a veces direcciones de servidores y credenciales.
- `composer.json` y `composer.lock`, que revelan las versiones exactas de todas las bibliotecas y facilitan con ello la búsqueda de vulnerabilidades conocidas.
- Configuraciones para pruebas, herramientas de build y pipelines, que revelan nombres de host y procesos internos.
- Restos de sistemas operativos como `.DS_Store`, que contienen listados de archivos de directorios enteros.

La solución es la misma que con la carpeta `.git`: servir solo lo que deba ser público, idealmente mediante una subcarpeta propia como webroot. Quien de todos modos cambia el despliegue a paquetes, fija de paso una lista de archivos excluidos y la revisa con cada nueva herramienta del proyecto.

## Si la carpeta estaba abierta: revisar el historial y los logs

Si resulta que la carpeta `.git` era accesible, proceda en este orden:

1. **Bloquear el acceso** y repetir la comprobación.
2. **Examinar el historial** para ver qué secretos se incluyeron alguna vez: archivos de configuración, `.env`, claves, volcados de bases de datos.
3. **Sustituir las credenciales**, todas las que se hayan encontrado en el paso 2, aunque hoy ya no estén en el código.
4. **Analizar los logs de acceso** para ver si se descargaron archivos bajo `/.git/` con estado 200 y desde qué direcciones. Cómo hacerlo lo muestra [Analizar los logs del servidor web tras un ataque](https://phpsos.de/es/ratgeber/logfiles-auswerten/).
5. **Revisar de forma dirigida el código fuente**, porque los atacantes lo conocen ahora. Las debilidades conocidas deberían corregirse con prioridad.
6. **Aclarar la protección de datos**, si en el historial había datos personales, por ejemplo exportaciones de prueba. La valoración corresponde a su delegado de protección de datos.

Las herramientas para buscar secretos en repositorios deben pasar después a formar parte permanente de la pipeline. OWASP recomienda expresamente estas comprobaciones, como hook antes del commit y en la CI.

## ¿Cómo ayuda PHP SOS en concreto?

- Comprobamos todos sus dominios y subdominios en busca de carpetas de control de versiones accesibles.
- Bloqueamos el acceso de inmediato y cambiamos el despliegue a paquetes sin datos de versiones.
- Examinamos el historial en busca de secretos y acompañamos la sustitución de los accesos afectados.
- Analizamos los logs de acceso y documentamos si se descargaron datos y cuándo.

Estas medidas forman parte de nuestro [refuerzo de servidores web PHP](https://phpsos.de/es/leistungen/server-haertung/).


## Preguntas frecuentes

**¿Cómo surge una carpeta .git pública?**  
Casi siempre por un despliegue con git clone o git pull directamente en el webroot. La carpeta .git, con todo el historial de versiones, queda entonces junto a index.php y, sin bloqueo, el servidor web sirve sus archivos.

**¿Basta con borrar la carpeta .git?**  
Para el futuro, sí; para el pasado, no. Si la carpeta era accesible, su contenido puede haberse copiado ya. Por eso debería sustituir las credenciales que alguna vez estuvieron en el repositorio.

**¿Ayuda eliminar a posteriori las credenciales del historial de Git?**  
Evita que las nuevas copias las contengan. Quien ya haya descargado el repositorio conserva los estados antiguos. Lo decisivo es, por tanto, la sustitución de las credenciales, no solo reescribir el historial.

**¿Afecta también a otros sistemas de control de versiones?**  
Sí. También las carpetas como .svn o .hg contienen datos del proyecto y nunca deberían ser accesibles en el webroot. Un bloqueo general de archivos y carpetas que empiezan por punto cubre todos estos casos.

## Fuentes

- [OWASP Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html)
- [Documentación de Nginx](https://nginx.org/en/docs/)
- [Apache HTTP Server: documentación](https://httpd.apache.org/docs/)
