Warum Dev-Dependencies kein Sicherheits-Blindfleck sein duerfen
Sicherheitsluecken in Produktionsabhaengigkeiten werden meist ernst genommen, waehrend Test- und Dev-Abhaengigkeiten wie PHPUnit-Plugins oder Coverage-Werkzeuge oft unbeachtet bleiben. Dabei laufen genau diese Pakete mit vollen Rechten in der CI/CD-Pipeline und sind ein reales Einfallstor fuer Supply-Chain-Angriffe, das composer audit gezielt aufdecken kann.
Inhaltsverzeichnis
- 1. Warum Dev-Dependencies oft uebersehen werden
- 2. Composer Audit: Funktionsweise und Aufruf
- 3. Warum Sicherheitsluecken in Testwerkzeugen trotzdem gefaehrlich sind
- 4. Composer Audit in die CI-Pipeline integrieren
- 5. Abgestufte Behandlung nach Schweregrad
- 6. Das Risiko von post-install-Skripten und Plugins
- 7. Automatisierte Updates fuer Testabhaengigkeiten
- 8. Kontinuierliches Monitoring jenseits einzelner CI-Laeufe
- 9. Besonderheiten im Magento-Projektkontext
- 10. Zusammenfassung
- 11. FAQ
1. Warum Dev-Dependencies oft uebersehen werden
In vielen Sicherheitsprozessen liegt der Fokus fast ausschliesslich auf require-Abhaengigkeiten, also den Paketen, die tatsaechlich mit in die Produktion ausgeliefert werden. Das ergibt auf den ersten Blick Sinn, denn nur dieser Code laeuft schliesslich auf dem produktiven Server und ist direkt von aussen erreichbar. Test- und Dev-Abhaengigkeiten unter require-dev, etwa PHPUnit selbst, Mocking-Bibliotheken, Coverage-Werkzeuge oder statische Analyse-Tools, fallen bei dieser Betrachtung meist komplett durchs Raster.
Dieser blinde Fleck ist gefaehrlich, weil Dev-Abhaengigkeiten keineswegs harmlos sind, nur weil sie nicht in Produktion laufen. Sie werden bei jedem composer install auf Entwicklerrechnern und in jeder CI-Pipeline ausgefuehrt, oft mit denselben Rechten wie der eigentliche Build-Prozess, inklusive Zugriff auf Umgebungsvariablen, SSH-Keys fuer Deployments und manchmal sogar auf Produktionszugangsdaten, die versehentlich in der CI-Umgebung verfuegbar sind.
2. Composer Audit: Funktionsweise und Aufruf
Seit Composer 2.4 steht der eingebaute Befehl composer audit zur Verfuegung, der die composer.lock-Datei gegen eine Sicherheitsdatenbank abgleicht, standardmaessig die FriendsOfPHP Security Advisories Datenbank. Der Befehl prueft dabei alle Pakete in der Lock-Datei, unabhaengig davon, ob sie unter require oder require-dev deklariert sind, sofern nicht explizit gefiltert wird. Das bedeutet, ein einfacher Aufruf ohne zusaetzliche Optionen deckt bereits Test- und Dev-Pakete mit ab.
Der Befehl gibt fuer jede gefundene Schwachstelle das betroffene Paket, die installierte Version, die CVE-Kennung sowie einen kurzen Titel der Advisory aus. Wichtig ist, den Rueckgabewert des Befehls in Skripten auszuwerten: composer audit liefert bei gefundenen Schwachstellen einen nicht-null Exit-Code zurueck, was sich direkt als Abbruchbedingung in einer CI-Pipeline nutzen laesst.
# Vollstaendiger Audit inklusive require-dev (Standardverhalten)
composer audit
# Nur Produktionsabhaengigkeiten pruefen (require-dev ausschliessen)
composer audit --no-dev
# Maschinenlesbare Ausgabe fuer die Weiterverarbeitung im CI-Skript
composer audit --format=json > audit-report.json
3. Warum Sicherheitsluecken in Testwerkzeugen trotzdem gefaehrlich sind
Der Gedanke 'PHPUnit laeuft doch nur lokal und in der Pipeline, nicht auf dem produktiven Server' unterschaetzt zwei Angriffsvektoren. Erstens laeuft PHPUnit mit allen Rechten des ausfuehrenden Prozesses, und in vielen CI-Setups hat dieser Prozess Zugriff auf Deployment-Secrets, Datenbank-Zugangsdaten fuer Testumgebungen, die produktiven Daten aehneln, oder sogar auf Cloud-Provider-Credentials fuer automatisierte Deployments. Eine kompromittierte Testabhaengigkeit mit Code-Ausfuehrung kann diese Secrets exfiltrieren, ganz ohne dass produktiver Code jemals angefasst wird.
Zweitens sind gerade Test- und Analyse-Tools haeufig Ziel von Supply-Chain-Angriffen, weil sie im Vergleich zu grossen Frameworks weniger Aufmerksamkeit von Sicherheitsforschern erhalten und trotzdem in tausenden Projekten als Dev-Abhaengigkeit installiert sind. Ein bekannter Fall betraf ein kompromittiertes Paket, das bei der Installation ueber ein post-install-Skript Schadcode ausfuehrte, lange bevor ein einziger Test tatsaechlich lief. Genau solche Angriffe treffen jeden Entwickler, der composer install ausfuehrt, unabhaengig davon, ob je ein Test gestartet wird.
4. Composer Audit in die CI-Pipeline integrieren
Ein composer audit-Schritt sollte fruh in der Pipeline stehen, idealerweise noch vor dem eigentlichen PHPUnit-Lauf, damit eine gefundene Schwachstelle den Build stoppt, bevor kompromittierter Code ueberhaupt ausgefuehrt wird. Fuer Magento-Projekte empfiehlt sich, den Audit sowohl im Standard-Composer-Root als auch, falls vorhanden, in separaten composer.json-Dateien einzelner Module durchzufuehren, sofern diese eigene Abhaengigkeiten deklarieren.
Ein pragmatischer Ansatz ist, den Audit-Schritt als eigenstaendigen, schnellen CI-Job zu definieren, der unabhaengig vom laengeren Testlauf existiert und damit auch bei einem fehlschlagenden PHPUnit-Lauf separat sichtbar bleibt. So laesst sich klar unterscheiden, ob ein Build wegen eines Testfehlers oder wegen einer Sicherheitsluecke fehlgeschlagen ist, was fuer die Priorisierung der Behebung entscheidend ist.
# .gitlab-ci.yml (Ausschnitt)
composer-audit:
stage: security
script:
- composer audit --format=json --no-interaction | tee audit-report.json
artifacts:
paths:
- audit-report.json
when: always
allow_failure: false
5. Abgestufte Behandlung nach Schweregrad
Nicht jede gemeldete Schwachstelle rechtfertigt einen sofortigen Build-Abbruch. composer audit liefert im JSON-Format auch den Schweregrad der jeweiligen Advisory, sodass sich eine differenzierte Policy umsetzen laesst: Schwachstellen mit hohem oder kritischem Schweregrad blockieren den Merge sofort, waehrend niedrige oder mittlere Schweregrade zunaechst nur eine Warnung erzeugen und in ein Ticket ueberfuehrt werden, das innerhalb einer definierten Frist bearbeitet werden muss.
Diese Abstufung verhindert, dass Teams composer audit nach wiederholten Fehlalarmen bei geringfuegigen Schwachstellen komplett ignorieren oder den Check faul mit allow_failure: true entschaerfen. Eine realistische, nach Risiko gestaffelte Policy erhoeht die Akzeptanz im Team deutlich gegenueber einer starren Alles-oder-Nichts-Regel.
<?php
// tools/audit-policy.php
declare(strict_types=1);
$report = json_decode((string) file_get_contents(__DIR__ . '/../audit-report.json'), true);
$blockingSeverities = ['critical', 'high'];
$blocked = false;
foreach ($report['advisories'] ?? [] as $package => $advisories) {
foreach ($advisories as $advisory) {
$severity = $advisory['severity'] ?? 'unknown';
$isDev = str_contains($package, 'phpunit') || str_contains($package, 'mockery');
if (in_array($severity, $blockingSeverities, true)) {
fwrite(STDERR, sprintf(
"BLOCKIEREND: %s (%s, Dev-Paket: %s)\n",
$package, $severity, $isDev ? 'ja' : 'nein'
));
$blocked = true;
} else {
fwrite(STDOUT, sprintf("WARNUNG: %s (%s)\n", $package, $severity));
}
}
}
exit($blocked ? 1 : 0);
6. Das Risiko von post-install-Skripten und Plugins
Neben bekannten CVEs birgt Composer selbst ein strukturelles Risiko: Pakete koennen ueber die scripts-Sektion in ihrer composer.json beliebigen PHP-Code bei der Installation ausfuehren, und Composer-Plugins koennen sich sogar in den Installationsprozess selbst einklinken. Ein boesartiges oder kompromittiertes Test-Utility-Paket kann so schon beim blossen composer install Code ausfuehren, ganz unabhaengig davon, ob es jemals in einem Test tatsaechlich referenziert wird.
Composer bietet seit Version 2.2 die Konfigurationsoption allow-plugins, die explizit festlegt, welche Pakete Composer-Plugin-Code ausfuehren duerfen. Fuer eine bewusste Sicherheitsstrategie lohnt es sich, diese Liste bewusst kurz zu halten und neue Eintraege nur nach kurzer Pruefung des jeweiligen Pakets zu erlauben, statt pauschal alles zu bestaetigen, was composer bei der ersten Installation vorschlaegt.
{
"config": {
"allow-plugins": {
"composer/installers": true,
"phpstan/extension-installer": true,
"dealerdirect/phpcodesniffer-composer-installer": false
}
}
}
7. Automatisierte Updates fuer Testabhaengigkeiten
Ein einmaliger composer audit-Lauf schuetzt nur gegen bereits bekannte Schwachstellen zum Zeitpunkt der Pruefung, nicht gegen kuenftig entdeckte. Ergaenzend dazu sollte ein Tool wie Renovate oder Dependabot eingerichtet werden, das automatisiert Pull-Requests fuer veraltete Abhaengigkeiten erstellt, inklusive Testabhaengigkeiten unter require-dev. Wichtig ist, diese Tools nicht nur fuer require, sondern explizit auch fuer require-dev zu konfigurieren, da manche Standardkonfigurationen Dev-Abhaengigkeiten mit niedrigerer Prioritaet oder gar nicht beruecksichtigen.
Ein sinnvoller Kompromiss ist, Sicherheitsupdates fuer Dev-Abhaengigkeiten mit hoher Prioritaet automatisch zu mergen, sofern die CI-Pipeline gruen bleibt, waehrend reine Feature-Updates ohne Sicherheitsbezug manuell geprueft werden. So bleibt der Wartungsaufwand ueberschaubar, ohne bekannte Luecken unnoetig lange offen zu lassen.
8. Kontinuierliches Monitoring jenseits einzelner CI-Laeufe
Ein composer audit-Schritt im CI-Pipeline prueft immer nur den Stand zum Zeitpunkt eines konkreten Merge- oder Pull-Requests. Wird danach eine neue Schwachstelle in einem bereits installierten Paket bekannt, faellt das erst beim naechsten Commit auf, der irgendeine CI-Pipeline ausloest, was in ruhigen Projektphasen Wochen dauern kann. Ein zusaetzlicher, zeitgesteuerter Job, der taeglich oder woechentlich unabhaengig von Code-Aenderungen gegen die aktuelle composer.lock laeuft, schliesst genau diese Luecke.
Ein solcher geplanter Job sollte bei einem Fund nicht nur die Pipeline rot faerben, sondern aktiv eine Benachrichtigung ausloesen, etwa an einen Slack-Kanal oder per E-Mail an das verantwortliche Team, da niemand taeglich manuell in eine ungenutzte, nur informative Pipeline schaut. Erst diese aktive Alarmierung stellt sicher, dass eine neu entdeckte Schwachstelle in einer bereits installierten Testabhaengigkeit zeitnah bemerkt wird, auch wenn zufaellig gerade niemand am betroffenen Modul arbeitet.
9. Besonderheiten im Magento-Projektkontext
Magento-Projekte bringen durch die grosse Zahl an Drittanbieter-Modulen und deren jeweils eigenen composer.json-Abhaengigkeiten eine besonders breite Angriffsflaeche mit. Viele Magento-Extensions deklarieren eigene Testabhaengigkeiten oder Entwicklerwerkzeuge, die selten von jemandem ausserhalb des urspruenglichen Entwicklerteams ueberprueft werden. Ein projektweiter composer audit-Lauf deckt diese transitive Abhaengigkeitskette vollstaendig ab, waehrend eine isolierte Pruefung nur der eigenen app/code-Module blinde Flecken hinterlaesst.
Bei Mark-Shust-Docker-Setups oder aehnlichen Entwicklungsumgebungen empfiehlt es sich, composer audit als Teil des bin/composer-Wrapper-Workflows zu etablieren, etwa als eigenstaendigen Befehl, der vor jedem composer update auf dem gesamten Lock-File laeuft, damit neue Schwachstellen sofort auffallen und nicht erst beim naechsten geplanten Sicherheits-Review Wochen spaeter entdeckt werden.
| Massnahme | Werkzeug | Zeitpunkt |
|---|---|---|
| Vollstaendiger Audit inkl. Dev-Deps | composer audit (Standardaufruf) | Bei jedem CI-Lauf, vor dem Testlauf |
| Abgestufte Severity-Policy | Eigenes Skript auf audit --format=json | Als blockierender Pipeline-Schritt |
| Plugin-Ausfuehrung einschraenken | config.allow-plugins in composer.json | Einmalig, bei jedem neuen Paket pruefen |
| Automatisierte Update-PRs | Renovate / Dependabot, inkl. require-dev | Kontinuierlich im Hintergrund |
| Transitive Modul-Dependencies pruefen | composer audit auf Projekt-Root | Vor Extension-Updates und Releases |
Mironsoft
Testautomatisierung, Magento-Qualitätssicherung und CI-Integration
Tests, die echte Fehler finden statt nur grün zu leuchten?
Wir prüfen bestehende PHPUnit-Suiten auf Implementierungsdetail-Tests, flaky Tests und fehlende Coverage an kritischen Stellen und bauen daraus eine Teststrategie, die bei jedem Magento-Update wirklich Sicherheit gibt.
Test-Audit
Bestehende Suiten auf Mocking-Antipatterns und blinde Flecken prüfen.
Teststrategie
Unit-, Integrations- und MFTF-Tests sinnvoll für Magento-Projekte kombinieren.
CI-Integration
Schnelle, zuverlässige Testläufe in GitLab CI oder GitHub Actions einrichten.
10. Zusammenfassung
Composer Audit fuer Dev-Deps: Das Wichtigste auf einen Blick
Blindfleck
Dev-Abhaengigkeiten wie PHPUnit-Plugins werden bei Security-Reviews oft ignoriert.
Risiko
Testtools laufen mit vollen CI-Rechten und Zugriff auf Deployment-Secrets.
Werkzeug
composer audit prueft standardmaessig auch require-dev gegen bekannte CVEs.
Durchsetzung
Frueher, blockierender CI-Schritt mit nach Schweregrad gestaffelter Policy.