
Seal Security Beispiel — anfällige Maven-App (SnakeYAML CVE-2022-1471) behoben auf versiegelte Versionen; GitHub Actions + Jenkins Integration
Eine minimale, absichtlich verwundbare Spring Boot-Anwendung, die End-to-End demonstriert, wie Seal Security eine bekannte CVE behebt, indem eine verwundbare Abhängigkeit durch eine gesiegelte (backportierte, Drop‑in) Version ersetzt wird – ohne Änderung Ihrer deklarierten Koordinaten oder Ihres Codes.
Es ist als durchgehender Rauchtest für das Seal CLI in CI/CD konzipiert: App ausführen, einen echten Exploit auslösen, Seal ausführen und beobachten, wie derselbe Exploit blockiert wird.
| Ökosystem | Java / Maven |
| Verwundbares Paket | org.yaml:snakeyaml:1.33 |
| CVE | CVE‑2022‑1471 — SnakeYAML Constructor-Deserialisierung → Remote Code Execution (CVSS 9.8) |
| Gesiegelte (behobene) Version | snakeyaml 1.33+sp1 aus Seals Maven-Registry |
| Integration | Seal CLI als ein Build-Schritt – gezeigt für sowohl GitHub Actions als auch Jenkins |
Das Projekt deklariert auch andere bekannte verwundbare Abhängigkeiten (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), von denen jede Seal ebenfalls auf eine gesiegelte Version behebt.
Die Begrüßungsseite nimmt einen name entgegen und parst ihn über den Standardkonstruktor von SnakeYAML:
Yaml yaml = new Yaml();
Object parsed = yaml.load(name); // SnakeYAML 1.33 — CVE-2022-1471
Der Standard-Constructor von SnakeYAML instanziiert beliebige Java-Typen, die im YAML genannt werden – das Objektinjektions-Primitiv hinter CVE‑2022‑1471. Ein Payload, der javax.script.ScriptEngineManager nennt (der Einstiegspunkt der klassischen RCE-Gadget-Kette), reicht aus, um zu beweisen, dass der Parser jede von einem Angreifer benannte Klasse erstellt.
Normale Anfrage
/?name=alice → Welcome, alice!
Exploit-Anfrage
/?name=!!javax.script.ScriptEngineManager []
Das verwundbare SnakeYAML instanziiert die vom Angreifer benannte Klasse, die App zeigt eine „You've been pwned“-Seite an, und der Server wird dann getötet (einige Sekunden später, sodass die Seite zuerst ausgeliefert wird). Bei erneutem Laden ist die App verschwunden – über ngrok sehen Sie eine „endpoint offline“-Seite. Dies ist das Objektinjektions-Primitiv; ein vollständiger Exploit verknüpft es (über URLClassLoader), um entfernten Code zu laden und auszuführen.
.
├── pom.xml # deklariert die verwundbaren Abhängigkeiten
├── src/main/java/… # Spring Boot-App (HelloController, DataService)
├── .seal-actions.yml # optionales lokales Fix-Mode-Mapping (verwundbar → gesiegelt)
├── Jenkinsfile # Beispiel-Jenkins (Groovy)-Pipeline mit der Seal-Stufe
└── .github/workflows/
├── build-and-run.yml # Erstellen + App für Browsertests bereitstellen
└── seal-security.yml # Seal-Problembehebung ausführen, dann die App starten
Seal ist SaaS, von Seal gehostet – in Ihrer Umgebung wird nichts installiert, und der gesamte Datenverkehr erfolgt nur über ausgehendes HTTPS auf TCP 443. Um die Problembehebung auszuführen, benötigen Sie:
| Secret / Anmeldedaten |
|---|
Konfigurieren Sie diese in Einstellungen → Secrets and variables → Actions (GitHub) oder Manage Jenkins → Credentials (Jenkins). Committen Sie Tokens niemals in das Repository.
Setzen Sie diese Seal-Hosts für ausgehenden Port 443 auf die Whitelist: app.sealsecurity.io, authorization.sealsecurity.io, cli.sealsecurity.io, und – für gesiegelte Maven-Artefakte – maven.sealsecurity.io. Das CLI-Binary wird von github.com / objects.githubusercontent.com heruntergeladen.
mvn clean package -DskipTests
java -jar target/java-example-1.0.0.jar # → http://localhost:8080
Öffnen Sie http://localhost:8080/?name=alice (funktioniert), dann http://localhost:8080/?name=!!javax.script.ScriptEngineManager [] – die App zeigt "You've been pwned" und der Server wird einige Sekunden später getötet.
Das Seal CLI wird als ein zusätzlicher Schritt ausgeführt, nachdem die Abhängigkeiten aufgelöst wurden und vor dem Paketieren. Es scannt die aufgelösten Abhängigkeiten und schreibt die verwundbaren in ihre gesiegelten Versionen um, dabei wird der Remote-Fix-Modus verwendet (Richtlinien werden zentral in der Seal-Oberfläche verwaltet).
Verwendet seal-community/cli-action:
- uses: seal-community/cli-action@latest
with:
mode: fix
fix_mode: remote
token: ${{ secrets.SEAL_TOKEN }}
target: pom.xml # the manifest for this ecosystem
Führen Sie es über Actions → „Seal Security Remediation“ → Run workflow aus. Siehe .github/workflows/seal-security.yml.
Eine einzelne hinzugefügte Stufe, nach der Abhängigkeitsauflösung und vor dem Paketieren. Siehe 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 stammt aus dem Jenkins-Credential seal-token; setzen Sie SEAL_PROJECT auf Ihre Seal-Projekt-ID.
Nach seal fix lösen die verwundbaren Abhängigkeiten auf gesiegelte Builds aus Seals Maven-Registry auf – gleiche Koordinaten, Sicherheitsfix zurückportiert:
Eine gesiegelte Version ist dasselbe Artefakt mit dem zurückportierten Sicherheitsfix – ein Drop‑in-Ersatz, keine Codeänderungen und kein Major-Version-Upgrade.
Führen Sie den Exploit erneut gegen die behobene App aus. Das gesiegelte snakeyaml weigert sich, die bösartigen globalen Typen zu instanziieren, sodass der Payload das entfernte JAR nicht mehr lädt – Remote Code Execution wird blockiert.
seal fix auf das spezifische Manifest – pom.xml für Maven. Bei einem Multi-Modul-Build führen Sie ein seal fix pro Manifest aus.Das ist die gesamte Integration – eine Stufe, nur ausgehend, keine Änderungen am Anwendungscode.
| Verwendet für |
|---|
| Wohin es geht |
|---|
| Seal-Token | Authentifizierung des Seal CLI | GitHub Actions-Secret SEAL_TOKEN / Jenkins "Secret text"-Credential seal-token |
| ngrok-Token (optional) | Bereitstellen der laufenden App für Tests im Browser | GitHub Actions-Secret NGROK_TOKEN |
| Abhängigkeit | Vorher | Nachher (gesiegelt) |
|---|
| 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 |