Hoch

Wenn ein composer install zur Code-Ausführung wird: CVE-2026-40176 und CVE-2026-40261 in der Composer-Lieferkette

Eine präzise Reihe gleichartiger Kraftpapier-Pakete auf Beton, zwischen zwei Paketen entweicht ein dünner oxbloodfarbener Staubfaden nach oben; daneben Messingstempel und Lupe im kühlen Nordlicht.

Composer ist das ruhige Rückgrat jeder PHP-Pipeline. Genau das macht zwei am 10. April 2026 veröffentlichte Lücken so unangenehm: Ein bewusst harmloses composer install kann zur Ausführung beliebiger Befehle führen – auch ohne Perforce auf dem Zielsystem.

TL;DR — die 90-Sekunden-Zusammenfassung

CVE-2026-40176 (CVSS 7.8)

Unzureichendes Escaping in Composer-Repository-Metadaten — präparierte composer.json führt zu Code-Ausführung im Build-User-Kontext

CVE-2026-40261 (CVSS 8.8)

Identische Klasse über jedes Composer-Repository inklusive Packagist auslösbar, keine Perforce-Installation nötig

Sofort-Patch

Composer 2.9.6 oder 2.2.27 LTS — plus Packagist hat Perforce-Source-Metadaten deaktiviert

Eigentliche Gefahr

Build-User hat SSH-Keys, Registry-Tokens, Cloud-Credentials — RCE im Build ist Lateral Movement

Vier Leitplanken

Lockfile-Builds, eingefrorenes Composer-Bin in CI-Image, Renovate mit Karenzzeit, read-only Composer-Mirror

Wer ist gefordert

jeder Mittelstand mit PHP-Stack — TYPO3, Sylius, Symfony, Laravel sind gleich exponiert

 

Was ist das Problem?

Am 10. April 2026 hat das Composer-Maintainer-Team zwei Schwachstellen veröffentlicht und gleichzeitig Patches geliefert: CVE-2026-40176 (CVSS 7.8) und CVE-2026-40261 (CVSS 8.8). Beide Lücken liegen im Pfad, in dem Composer Repository-Metadaten verarbeitet. Eine präparierte composer.json oder eine manipulierte Source-Reference, die Shell-Metazeichen enthält, wird unzureichend escaped und an einen Subprozess weitergegeben. Resultat: beliebige Code-Ausführung im Kontext des Build-Users.

Die schwerwiegendere Variante lässt sich über jedes Composer-Repository auslösen, also auch über Packagist, und benötigt keine Perforce-Installation auf dem Zielsystem. Als Sofortmaßnahme hat Packagist.org am 10. April die Veröffentlichung von Perforce-Source-Metadaten deaktiviert.

Wir sind in unseren Pipelines nicht getroffen worden. Das ist keine Glanzleistung, sondern das Ergebnis derselben Disziplin, mit der wir auch andere Werkzeuge in unserer Build-Chain führen. In diesem Beitrag ordnen wir den Vorfall ein und beschreiben, welche strukturellen Entscheidungen den Unterschied machen — unabhängig davon, ob das nächste Composer-CVE oder die nächste npm-Welle kommt.

Auswirkungen: warum ein Build-RCE kein Build-Problem ist

Composer-Lücken treffen nicht das Produkt, sondern den Weg dorthin. Der eigentliche Code in Ihrem Repository ist sauber, die Anwendung läuft, der Build wäre erfolgreich — und genau in diesem Moment hat ein Subprozess auf Ihrem CI-Runner einen fremden Befehl ausgeführt. Drei Effekte machen das Risikoprofil so unangenehm.

Builds laufen oft mit höheren Rechten als die spätere Anwendung

SSH-Keys, Container-Registry-Tokens, Cloud-Credentials, Deployment-Tokens — alles liegt im Build-Kontext bereit. Code-Ausführung im Build ist deshalb fast nie nur ein Build-Problem, sondern der Schritt zu Lateral Movement. Dasselbe Muster wie bei der CI/CD-Verdichtung, die wir an anderer Stelle ausführlich beschrieben haben.

Composer in CI-Images wird selten aktualisiert

In den Pipeline-Reviews der letzten Wochen war Composer in vielen Fundstücken in einem fest eingefrorenen Image-Tag, ohne automatischen Update-Pfad. Eine 2.9.4 oder 2.8.x in der CI ist solange unsichtbar, bis ein Vorfall sie sichtbar macht. Anwendungs-Dependencies bekommen Renovate-PRs, die Toolchain bekommt keine.

Composer-Pakete sind transitiv

Selbst wer die eigene composer.json sauber führt, ist auf das Verhalten von Tools angewiesen, die im CI-Container vorinstalliert sind, sowie auf Plugins, die andere Pakete laden. Genau diese Klasse von Plugins hat im April 2026 — sichtbar am bekannten Intercom-Composer-Plugin-Vorfall — zur Verteilung der Mini-Shai-Hulud-Welle in den Packagist-Bereich beigetragen.

Wer ist betroffen?

Selbst ein vergleichsweise schlanker PHP-Stack hat in der Regel eine deutliche Anzahl direkter und transitiver Composer-Abhängigkeiten. Eine TYPO3-, Sylius- oder Symfony-basierte Plattform unterscheidet sich da nicht von einem größeren Konzern-Stack. Wer in der CI keinen klaren Regelkreis dafür hat, welche Pakete überhaupt akzeptiert werden, hat kein „kleineres“ Risiko, sondern nur ein weniger sichtbares.

Drei Konstellationen sind besonders exponiert:

Mitigation und Sofortmaßnahmen — die vier Leitplanken

Quick-Start in der Reihenfolge, in der wir Pipelines aktuell durchziehen — jede Zeile schlägt eine bestimmte Klasse von Vorfällen ab.

 

composer self-update 2.9.6   # oder 2.2.27 (LTS-Linie)
composer diagnose            # Repository-Liste prüfen
composer config --global --unset repositories.perforce-*
composer audit               # known vulns gegen lock prüfen

 

1. Reproduzierbare Installationen über composer install gegen ein committetes composer.lock

Unsere Builds aktualisieren keine Pakete, sie installieren genau die, die per Lockfile festgeschrieben sind. Eine geänderte Source-Reference kommt damit nur über einen expliziten Lockfile-Commit in den Build, nicht spontan im Hintergrund. composer update hat im CI nichts verloren.

2. Ein definierter Composer-Pfad lokal und in CI

Wir nutzen ein eingefrorenes Composer-Binärprogramm in einer klar versionierten Variante. Composer wird nicht spontan über composer self-update auf dem Runner aktualisiert; CI-Images werden gebaut, signiert, freigegeben. Der Versionssprung auf Composer 2.9.6 oder 2.2.27 LTS ist damit ein bewusster Schritt, kein Hintergrundgeschehen.

3. Updates über Renovate mit Karenzzeit

Neue Composer-Versionen werden nicht aus der Shell aktualisiert, sondern als Pull Request vorgeschlagen und nach Karenzzeit (typisch 72–168 Stunden) gemerged. Die Karenzzeit gibt der Community Zeit, einen Bug oder eine Sicherheitslücke zu entdecken. Ausnahme bleibt der bekannte, aktiv ausgenutzte CVE in der laufenden Version.

4. Read-only Composer-Mirror für produktive Builds

Wo immer möglich, läuft das CI gegen einen internen Mirror, der nur freigegebene Versionen weitergibt. Das ist Aufwand, gibt aber ein verlässliches Audit-Log darüber, welche Pakete jemals in den Build-Kontext kamen — und filtert Pakete heraus, die in einer Stunde Lebenszeit kompromittiert auf einer öffentlichen Registry stehen. Dasselbe Muster wie der npm-Mirror, den wir nach dem EVM/DeFi-Cluster vom 6. Mai dokumentiert haben.

Detection und Prüfung

Fünf Kernfragen, die in einer halben Stunde Klarheit bringen — ob Sie heute getroffen sein könnten und wo der größte Hebel liegt.

Quick-Check-Snippets, die wir in der ersten Stunde fahren:

 

# Composer-Bins in allen erreichbaren Images
for img in $(docker images --format '{{.Repository}}:{{.Tag}}'); do
  docker run --rm "$img" composer --version 2>/dev/null \
    | grep -i composer
done

# Perforce-Repositories in den Lockfiles
git grep -nE '"type":\s*"perforce"' -- 'composer.lock' '**/composer.lock'

Betreiberempfehlung

Was für welchen PHP-Stack jetzt operativ sitzen sollte — in Bullet-Form, weil die Entscheidungen meist nicht zwischen „richtig“ und „falsch“ liegen, sondern zwischen „Rest-Risiko ist akzeptiert“ und „Rest-Risiko ist Zufall“.

Cross-Referenzen: der npm-EVM-Cluster-Beitrag für Mirror-Topologien, der CI/CD-Verdichtungs-Beitrag für die strukturelle Argumentation, und der KI-Security-Audits-Beitrag für die Einbettung in eine Release-Disziplin.

Fazit

Die meisten PHP-Pipelines, die wir im Review sehen, haben einzelne dieser Bausteine. Selten alle. Entweder es gibt ein Lockfile, aber Composer wird im CI per self-update auf das jeweils aktuellste verfügbare Binärprogramm gezogen. Oder Renovate schlägt brav PRs vor, aber ohne Karenzzeit, sodass eine soeben kompromittierte Version am Folgetag im Build steht. Oder die Produktivserver bauen anders als die CI, und niemand kann nach einem Vorfall eindeutig sagen, welche Composer-Version dort gerade läuft.

Die Frage lautet nicht, ob Composer 2.9.6 in Ihren Images ist. Sie lautet, ob Ihre Pipeline den nächsten Vorfall überhaupt bemerken würde — und ob Sie nach dem Bemerken in derselben Stunde wissen, welche Builds in den Tagen davor mit der kompromittierten Version gelaufen sind.

Eine längere Aufarbeitung mit Beispielen unserer GitLab-CI-Components, der Renovate-Konfiguration und unserer Mirror-Topologie findet sich unter ole-hartwig.eu.

Häufige Fragen zu den Composer-CVEs

Warum ist Composer als Lieferketten-Vektor unter NIS-2 besonders heikel?+

Weil NIS-2 in den zehn Risikomanagement-Bereichen explizit Lieferkettensicherheit und Sicherheit beim Erwerb und bei der Entwicklung von Systemen verlangt. Eine Build-Pipeline, die unkontrolliert beliebige Pakete aus einer öffentlichen Registry zieht, ist genau die Stelle, an der diese beiden Pflichtbereiche zusammenfallen. Wer keinen Audit-Pfad über installierte Pakete hat, kann im Audit nicht nachweisen, was er tut.

Wie lange dauert es, diese Leitplanken nachträglich einzuziehen?+

Lockfile-Disziplin und Composer-Pinning lassen sich in wenigen Tagen umsetzen. Renovate mit Karenzzeit braucht etwas länger, weil sie zur eigenen Release-Logik passen muss. Ein read-only Mirror ist die größere Investition, in der Regel zwei bis drei Wochen für Aufbau, Spiegel-Logik und Anbindung an die CI. Für ein sauberes Gesamtbild rechnen wir mit zwei bis vier Wochen, abhängig davon, wie stark Ihre Pipelines historisch gewachsen sind.

Was bringt ein eigener Composer-Mirror, wenn Packagist gut funktioniert?+

Ein read-only Mirror schiebt einen kontrollierten Filter zwischen Ihre Builds und die öffentliche Registry. Eine Stunde Lebenszeit eines kompromittierten Pakets reicht in der öffentlichen Welt aus, um nightly builds zu treffen. Im Mirror passiert nichts, weil das neue Paket nicht freigegeben ist. Zusätzlich erhalten Sie ein Audit-Log darüber, welche Pakete jemals in Ihren Builds waren – das ist im Schadensfall Gold wert.

Reicht es, Composer auf 2.9.6 zu aktualisieren?+

Das ist die notwendige Sofortmaßnahme, aber alleine nicht ausreichend. Aktualisieren müssen Sie nicht eine Composer-Installation, sondern alle: lokale Dev-Container, alle CI-Images, alle Produktivserver, auf denen Composer ausgeführt wird. Wenn ein einziger Worker mit einer alten Version weiterläuft, hat der Vorfall einen offenen Pfad. Prüfen Sie deshalb Image-Bauten, Pinning und Cron-gesteuerte Composer-Aufrufe.

Wir nutzen kein Perforce — sind wir trotzdem betroffen?+

Ja. CVE-2026-40261 (CVSS 8.8) lässt sich über jedes Composer-Repository auslösen, auch über Packagist, und benötigt keine Perforce-Installation. Composer führt die eingeschleusten Befehle auch dann aus, wenn Perforce auf dem System gar nicht vorhanden ist. Die zweite Lücke (CVE-2026-40176) ist enger, aber das Risikoprofil bestimmt die schwerere.

Bevor das nächste Composer-CVE kommt – sprechen wir über Ihre Pipeline.

Wie diszipliniert ist Ihre PHP-Pipeline wirklich?

Wenn Sie den Composer-Vorfall zum Anlass nehmen wollen, Ihre Build-Pipeline einmal nüchtern zu prüfen, lohnt sich ein kurzes Gespräch. 30 Minuten, kein Pitch. Wir gehen mit Ihnen durch, ob Lockfile, Karenzzeit, definierter Composer-Pfad und ein etwaiger Mirror in Summe greifen – und wo die nächsten zwei bis drei Schritte den größten Hebel hätten.

Termin direkt vereinbaren