
Ejemplo de Seal Security — aplicación Maven vulnerable (SnakeYAML CVE-2022-1471) remediada a versiones selladas; integración con GitHub Actions + Jenkins
Una aplicación Spring Boot mínima e intencionadamente vulnerable utilizada para demostrar, de extremo a extremo, cómo Seal Security remedia un CVE conocido reemplazando una dependencia vulnerable por una versión sellada (con backport, reemplazo directo) — sin cambiar las coordenadas declaradas ni tu código.
Está diseñada como una prueba de humo completa para la CLI de Seal en CI/CD: ejecuta la aplicación, activa un exploit real, ejecuta Seal y observa cómo se bloquea el mismo exploit.
| Ecosistema | Java / Maven |
| Paquete vulnerable | org.yaml:snakeyaml:1.33 |
| CVE | CVE‑2022‑1471 — Deserialización del Constructor de SnakeYAML → Ejecución remota de código (CVSS 9.8) |
| Versión sellada (corregida) | snakeyaml 1.33+sp1 del registro Maven de Seal |
| Integración | CLI de Seal como un paso de compilación — mostrado tanto para GitHub Actions como para Jenkins |
El proyecto también declara otras dependencias vulnerables bien conocidas (jackson-databind 2.13.1, commons-text 1.9, spring-core/web 5.3.26, json-smart 2.4.8, commons-lang3 3.12.0, spring-boot 2.7.18), cada una de las cuales Seal también remedia a una compilación sellada.
La página de bienvenida toma un name y lo analiza a través del constructor predeterminado de SnakeYAML:
Yaml yaml = new Yaml();
Object parsed = yaml.load(name); // SnakeYAML 1.33 — CVE-2022-1471
El Constructor predeterminado de SnakeYAML instanciará tipos Java arbitrarios nombrados en el YAML — el primitivo de inyección de objetos detrás de CVE‑2022‑1471. Un payload que nombre javax.script.ScriptEngineManager (el punto de entrada de la clásica cadena de gadgets RCE) es suficiente para demostrar que el analizador construirá cualquier clase que un atacante nombre.
Solicitud normal
/?name=alice → Welcome, alice!
Solicitud de exploit
/?name=!!javax.script.ScriptEngineManager []
El SnakeYAML vulnerable instancia la clase nombrada por el atacante, la aplicación muestra una página “You've been pwned” y luego el servidor se cierra (unos segundos después, para que la página se entregue primero). Recarga y la aplicación desaparece — a través de ngrok verás una página de “endpoint offline”. Este es el primitivo de inyección de objetos; un exploit completo lo encadena (mediante URLClassLoader) para cargar y ejecutar código remoto.
.
├── pom.xml # declara las dependencias vulnerables
├── src/main/java/… # Aplicación Spring Boot (HelloController, DataService)
├── .seal-actions.yml # mapeo opcional del modo de corrección local (vulnerable → sellada)
├── Jenkinsfile # pipeline de ejemplo Jenkins (Groovy) con la etapa Seal
└── .github/workflows/
├── build-and-run.yml # compila + expone la app para pruebas en navegador
└── seal-security.yml # ejecuta la remediación de Seal, luego inicia la app
Seal es SaaS, alojado por Seal — no se instala nada dentro de tu entorno, y todo el tráfico es solo HTTPS saliente en el puerto TCP 443. Para ejecutar la remediación necesitas:
| Secreto / credencial | Se usa para | Dónde se almacena |
|---|---|---|
| Seal token | Autenticar la CLI de Seal | secreto de GitHub Actions SEAL_TOKEN / credencial "Secret text" de Jenkins seal-token |
| Token de ngrok (opcional) | Exponer la aplicación en ejecución a un navegador para pruebas | secreto de GitHub Actions NGROK_TOKEN |
Configúralos en Settings → Secrets and variables → Actions (GitHub) o Manage Jenkins → Credentials (Jenkins). Nunca subas tokens al repositorio.
Agrega a la lista blanca estos hosts de Seal para el tráfico saliente 443:
app.sealsecurity.io, authorization.sealsecurity.io, cli.sealsecurity.io, y — para artefactos Maven sellados — maven.sealsecurity.io. El binario de la CLI se descarga desde github.com / objects.githubusercontent.com.
mvn clean package -DskipTests
java -jar target/java-example-1.0.0.jar # → http://localhost:8080
Abre http://localhost:8080/?name=alice (funciona), luego http://localhost:8080/?name=!!javax.script.ScriptEngineManager [] — la aplicación muestra "You've been pwned" y el servidor se cierra unos segundos después.
La CLI de Seal se ejecuta como un paso adicional, después de resolver las dependencias y antes del empaquetado. Escanea las dependencias resueltas y reescribe las vulnerables a sus versiones selladas, usando el modo de corrección remoto (la política se gestiona centralizadamente en la UI de Seal).
Utiliza seal-community/cli-action:
- uses: seal-community/cli-action@latest
with:
mode: fix
fix_mode: remote
token: ${{ secrets.SEAL_TOKEN }}
target: pom.xml # el manifiesto para este ecosistema
Ejecútalo a través de Actions → “Seal Security Remediation” → Run workflow. Consulta .github/workflows/seal-security.yml.
Una única etapa añadida, después de la resolución de dependencias y antes del empaquetado. Consulta Jenkinsfile:
stage('Seal') {
steps {
sh '''
curl -fsSL https://github.com/seal-community/cli/releases/download/latest/seal-linux-amd64-latest -o seal
chmod +x seal
./seal fix --mode remote "$SEAL_MANIFEST" # SEAL_MANIFEST=pom.xml
'''
}
}
SEAL_TOKEN proviene de la credencial seal-token de Jenkins; establece SEAL_PROJECT con tu ID de proyecto de Seal.
Después de seal fix, las dependencias vulnerables se resuelven a compilaciones selladas del registro Maven de Seal — mismas coordenadas, corrección de seguridad aplicada mediante backport:
| Dependencia | Antes | Después (sellada) |
|---|---|---|
| org.yaml:snakeyaml | 1.33 | 1.33+sp1 |
| com.fasterxml.jackson.core:jackson-databind | 2.13.1 | 2.13.1+sp1 |
| org.apache.commons:commons-text | 1.9 | 1.9+sp1 |
| org.springframework:spring-core / spring-web | 5.3.26 | 5.3.26+sp1 |
| net.minidev:json-smart | 2.4.8 | 2.4.8+sp1 |
| org.apache.commons:commons-lang3 | 3.12.0 | 3.12.0+sp1 |
| org.springframework.boot:spring-boot | 2.7.18 | 2.7.18+sp1 |
Una versión sellada es el mismo artefacto con la corrección de seguridad aplicada mediante backport — un reemplazo directo, sin cambios de código ni actualización a una versión mayor.
Vuelve a ejecutar el exploit contra la aplicación remediada. El snakeyaml sellado se niega a instanciar los tipos globales maliciosos, por lo que el payload ya no carga el JAR remoto — la ejecución remota de código está bloqueada.
seal fix al manifiesto específico — pom.xml para Maven. Para una compilación multimódulo, ejecuta un seal fix por cada manifiesto.Esa es toda la integración — una etapa, solo tráfico saliente, sin cambios en el código de la aplicación.