Una clave de API se filtró en tu bundle de JavaScript

Una credencial llegó a un bundle desplegado. Cómo saber qué expone tu sitio en producción ahora mismo, qué cambia el siguiente build para ese valor y por qué la rotación es el paso que lo cierra.

Una credencial, un token o una URL interna que nunca debía salir de tu código llegó a un bundle que desplegaste. Necesitas saber qué está expuesto ahora mismo y qué hacer al respecto.

A una credencial publicada la encuentran los escáneres, no las personas

Una credencial filtrada es un incidente activo desde el momento en que se sirve. El descubrimiento está automatizado: un escáner de secretos, un scraper de bundles o el script de un investigador encuentran una clave en texto plano en un archivo JavaScript mucho antes de que una persona se siente a leer tu código. El reloj de la exposición empezó con el despliegue, muestren lo que muestren tus paneles.

El coste depende del alcance de la credencial. Una clave con permisos amplios sobre una cuenta compartida es un incidente peor que una con un alcance limitado. Ambas son incidentes desde el momento en que son accesibles por la red.

Averigua qué expone tu sitio en producción

Ejecuta audit contra el sitio desplegado antes de cambiar nada:

$ npx afterpack@latest audit https://yoursite.com

Informa de los secretos expuestos, los source maps accesibles y el grado de protección del JavaScript publicado, para el bundle que recibe ahora mismo el navegador de un visitante. Lee primero los secretos y los source maps. Un informe sin hallazgos significa que este escaneo no encontró nada en esas URL, y no es una prueba de que no se filtrara nada.

Qué cambia el siguiente build para el valor

El preset por defecto codifica tus literales de cadena en tiempo de build, así que el endpoint interno, el nombre del flag y la credencial dejan de estar en texto plano en el archivo que sirves. Un grep del nuevo artefacto buscando la clave, o el texto que la rodea, no la encuentra, y los scrapers automáticos que descubren la mayoría de las claves filtradas se van sin nada. Algunos literales siguen siendo legibles con cualquier preset, y el Protection Map enumera cuáles.

Eso te da tiempo para completar bien una rotación. No deshace la filtración. El build antiguo ya se publicó, y el valor sigue presente en el nuevo. La codificación cambia lo que un lector encuentra en el archivo, pero el código sigue conteniendo el valor y usándolo.

Mantén los source maps y las copias de seguridad fuera del pipeline

Comprueba que nada en tu pipeline active las salidas que devuelven tu código fuente original:

{
  "sourceMap": { "enabled": false, "emitUrl": false, "sourcesContent": false },
  "build": { "backup": false },
  "protectionMap": { "enabled": true }
}

Un source map relaciona el archivo ofuscado con tu código fuente legible, y sourceMap.sourcesContent incrusta ese código fuente dentro del mapa. Los mapas están desactivados por defecto en producción, y un pipeline que los activa para depurar es la forma habitual en que uno acaba en un servidor; compila con el mapa y mantenlo privado cuando necesites trazas de producción.

La copia de build.backup es tu código fuente tal cual. La CLI la guarda en .afterpack/backup/, ignorado por git, en la raíz del proyecto, fuera de lo que despliegues. Ponlo en false cuando un plugin de framework escriba la copia junto a la salida y tu despliegue publique ese directorio entero. protectionMap.enabled escribe el Protection Map en .afterpack/ en la máquina de build, y la CLI se niega a escribirlo en una ruta servida.

Confirma que el hallazgo ha desaparecido

Vuelve a ejecutar la auditoría después de rotar y volver a desplegar, y confirma que el hallazgo anterior ha desaparecido. Añade --diagnostics.format=json para leer el resultado desde un script. Si el build informa de DIAG_SURVIVING_READABLE_LITERAL, todavía queda un literal legible en la salida, y strings.leaks.max hace fallar el build cuando quedan más de los que hayas fijado. Ese diagnóstico cuenta literales en general y no te dice cuál es la credencial.

Lo que la ofuscación no puede deshacer

La codificación se aplica a cada build a partir de ahora, así que el valor en texto plano desaparece del artefacto que lee un escáner, y la auditoría te dice qué expone hoy el sitio en producción. Lo que no puede hacer es alcanzar el build que ya se publicó: rotar la credencial es el paso que cierra el incidente, y volver a desplegar es lo que impide que se siga sirviendo el bundle legible antiguo.

Siguiente