19 Min. Lesezeit
Hoch
Von

Nachzug zur Symfony-Mai-Welle — vier Webhook-Parser, die das Secret nie geprüft haben (CVE-2026-45754 / -45755 / -47212) plus die JsonPath-ReDoS (CVE-2026-45756)

22. Mai 2026. Unser ausführlicher Beitrag zur Symfony-Patch-Welle vom 20. Mai hat sieben Sicherheits-Advisories behandelt: HtmlSanitizer-Trio, UrlGenerator-Bypass, X509Authenticator, Mime\Address, CVE-2024-50340-Bypass. Vier weitere Einträge dieser Welle wurden erst danach in den Symfony-Advisory-Index aufgenommen: drei Webhook-Parser-Bypässe (CVE-2026-45755 Mailtrap, CVE-2026-45754 Mailjet + LOX24, CVE-2026-47212 Twilio) und eine ReDoS in der JsonPath-Komponente (CVE-2026-45756). Alle vier wurden vom selben Researcher gemeldet (Himanshu Anand). Dieser Folgebeitrag arbeitet sie auf; der Hauptbeitrag vom 20. Mai bleibt der Anker für die übrigen sieben CVEs.

Vier cremefarbene Briefe mit identischen oxblutroten Wachssiegeln auf mattem Schiefer, eine Messing-Petschaft daneben — ungenutzt, obwohl die Siegel hätten geprüft werden sollen.
AI-generated · gpt-image 2.0

TL;DR — die 90-Sekunden-Zusammenfassung

FrageAntwort
Betroffen?Drei Provider-Bridges aus dem symfony/mailer-/symfony/notifier-Stack — Mailtrap (Symfony 7.2–7.4.11, 8.0–8.0.11; nicht in 6.4), Mailjet (Symfony 6.4–6.4.39, 7.0–7.4.11, 8.0–8.0.11), LOX24 (Symfony 7.1–7.4.11, 8.0–8.0.11; eingeführt mit 7.1, daher nicht in 6.4), Twilio (Symfony 6.4–6.4.39, 7.0–7.4.11, 8.0–8.0.11). Plus die JsonPath-Komponente (symfony/json-path, eingeführt mit Symfony 7.3, also 7.3–7.4.11 und 8.0–8.0.11).
Risiko?Unauthenticated Event Injection in jede Mail-/SMS-Webhook-Pipeline mit aktiv konfiguriertem Secret — der Parser empfing den Secret als Argument, las ihn aber nie. Ein Angreifer, der den öffentlichen Webhook-Endpunkt kennt, kann beliebige Bounce-/Delivery-/Click-/Status-Events einspielen. Bei JsonPath: ReDoS über attacker-controlled Pattern in match()/search()-Filter (z. B. $[?search(@, "(a+)+$")]), pinnt eine CPU-Kern für Sekunden pro Request, ein paar parallele Anfragen erschöpfen den Worker-Pool — und die @-prefixed preg_match()-Calls schlucken die PCRE-Backtrack-Limit-Fehler, so dass keine Spur im Log bleibt.
Sofortmaßnahme?composer update "symfony/*" --with-all-dependencies auf 7.4.12 / 8.0.12 / 6.4.40 (sofern noch nicht über die 20.05.-Welle erledigt). Wer Provider-Bridges einzeln pinnt: symfony/mailtrap-mailer, symfony/mailjet-mailer, symfony/lox24-notifier, symfony/twilio-notifier, symfony/json-path mitziehen. Nach dem Patch: Webhook-Provider-Konfigurationen prüfen, dass für jeden aktiven Bridge ein Secret in der App-Konfiguration steht (vorher konnte der Secret weglassen werden — der Parser hätte ihn ohnehin nicht geprüft; jetzt fängt die Signatur-Prüfung wirklich an zu blocken). Bei Twilio zusätzlich: framework.trusted_proxies und framework.trusted_headers setzen, damit Request::getUri() hinter TLS-terminating Proxy die URL liefert, die Twilio signiert hat.
Empfehlung?Mittelstand: SBOM-Inventur prüft, ob einer der vier Bridges produktiv im Tree ist; wo ja, ist heute der Konfigurations-Verify gegen das Provider-Dashboard fällig (Secret-Wert plus, bei Twilio, trusted_proxies). Wer den Patch noch nicht eingespielt hat (kein Renovate / kein automatisierter Composer-Update-Strom): heute updaten, dann verifizieren. Enterprise: dazu Eigenbau-Webhook-Parser-Audit gegen das HMAC-Pattern (siehe Strukturhinweis weiter unten).
Kritikalität?Siehe Hero-Badge — high. Unauthentifizierte, triggerbare Pfade, keine öffentlich bestätigten Mass-Exploits, aber Endpoints sind seit der Einführung der Bridges (Mailtrap, Mailjet, Twilio seit längerem im symfony/* Set; LOX24 seit 7.1, also frühestens November 2024) öffentlich erreichbar.

Was ist das Problem? — derselbe Bug in vier Provider-Bridges

Vorab — derselbe Bug in vier Bridges

Alle vier Webhook-Parser haben dieselbe Signatur:

 

protected function doParse(Request $request, #[SensitiveParameter] string $secret): RemoteEvent

 

Das SensitiveParameter-Attribut markiert $secret als sensibel, damit der Wert nicht in Stack-Traces auftaucht. Das heißt: der konfigurierte Webhook-Secret kommt tatsächlich bis in die Methode hinein. Er wurde dort nur nie ausgewertet. doParse() hat den Request dekodiert und die Payload bedingungslos zurückgegeben.

Das ist kein klassischer Code-Bug. Es ist eine Lücke auf Vertragsebene: die Symfony-Dokumentation hat die HMAC-Prüfung als empfohlene Praxis beschrieben, das AbstractRequestParser::doParse()-Interface hat sie aber nicht erzwungen. Wer einen neuen Provider-Parser geschrieben hat — Symfony-Kernteam oder externer Contributor — konnte den Signatur-Check vergessen, ohne dass eine Code-Prüfung Alarm schlägt. Genau das ist bei Mailtrap, Mailjet, LOX24 und Twilio passiert.

Dass alle vier vom selben Researcher (Himanshu Anand) gemeldet wurden, ist keine Koinzidenz. Er hat die Provider-Bridge-Klasse systematisch durchgesehen, weil ein Treffer auf einem Bridge immer die Frage stellt: „und die anderen?“ Sicherheitsforschung in Frameworks folgt der Klasse, nicht dem Einzelfall — darin liegt der größere Erkenntniswert dieser Welle.

CVE-2026-45755 — Mailtrap Mailer Webhook Parser

AdvisorySymfony Blog — CVE-2026-45755
Komponentesymfony/mailtrap-mailer Webhook-Bridge
Affected Versions>=7.2, <7.4.12 und >=8.0, <8.0.12 (Mailtrap-Bridge ist in 6.4 nicht enthalten)
Fixed inSymfony 7.4.12, 8.0.12
HMAC-SchichtX-Mt-Signature HTTP-Header, HMAC-SHA256 der Raw-Request-Body, keyed mit dem konfigurierten Webhook-Secret
ReporterHimanshu Anand
Fix-AutorAlexandre Daubois
Fix-Commitsymfony/symfony@4e0467e (branch 7.4)

MailtrapRequestParser::doParse() empfing den Secret, verifizierte aber X-Mt-Signature nie. Ein Angreifer mit Kenntnis des öffentlichen Mailtrap-Webhook-Endpunkts der App konnte forged Events einspielen — Bounce-/Delivery-/Open-/Click-/Spam-Events. Folge: Suppression-List-Corruption, Delivery-Metrics-Fraud. Fix: HMAC-Vergleich in Constant-Time vor dem Decode.

CVE-2026-45754 — Mailjet + LOX24 Webhook Parsers (ein Advisory, zwei Bridges)

AdvisorySymfony Blog — CVE-2026-45754
Komponentensymfony/mailjet-mailer (Mail-Provider-Bridge), symfony/lox24-notifier (SMS-Provider-Bridge)
Affected VersionsMailjet: >=6.4, <6.4.40, >=7.0, <7.4.12, >=8.0, <8.0.12. LOX24: erst ab Symfony 7.1, also >=7.1, <7.4.12 und >=8.0, <8.0.12 — nicht in 6.4
Fixed inSymfony 6.4.40, 7.4.12, 8.0.12
Auth-Schicht MailjetHTTP Basic credentials, eingebettet als user:password in der Mailjet-Webhook-URL — bei URL ohne Username im Format :password zu konfigurieren
Auth-Schicht LOX24X-LOX24-Token HTTP-Header gegen den im LOX24-Dashboard (Callback-Settings) konfigurierten Token
ReporterHimanshu Anand
Fix-AutorenAlexandre Daubois (Mailjet), Nicolas Grekas (LOX24)
Fix-CommitsMailjet 3e52bf5 (branch 6.4); LOX24 4aaa45d (branch 7.4)

Beide Bridges hatten denselben Bug — doParse() empfing den Secret-Wert ohne ihn zu lesen. Ein Angreifer mit Kenntnis der Webhook-URL konnte Bounce-/Blocked-/Spam-/Open-/Click-/Delivery-Events fälschen (Mailjet) oder SMS-Status-Events fälschen (LOX24). Mailjet nutzt Basic-Auth gegen den im URL eingebetteten User-/Password-Pair; LOX24 nutzt einen Token im X-LOX24-Token-Header. Beide Vergleiche jetzt in Constant-Time.

CVE-2026-47212 — Twilio Notifier Webhook Parser

AdvisorySymfony Blog — CVE-2026-47212
Komponentesymfony/twilio-notifier SMS-Provider-Bridge
Affected Versions>=6.4, <6.4.40, >=7.0, <7.4.12, >=8.0, <8.0.12
Fixed inSymfony 6.4.40, 7.4.12, 8.0.12
HMAC-SchichtX-Twilio-Signature HTTP-Header, HMAC-SHA1 über die volle Request-URL konkateniert mit den alphabetisch sortierten POST-Parametern, base64-encoded, keyed mit dem Twilio-Account-Auth-Token
Pflicht hinter Reverse-Proxyframework.trusted_proxies und framework.trusted_headers setzen, damit Request::getUri() die öffentliche URL liefert, die Twilio signiert hat
ReporterHimanshu Anand
Fix-AutorNicolas Grekas
Fix-Commitsymfony/symfony@8545fb2 (branch 6.4)

Twilios HMAC-Schema ist das anspruchsvollste der vier: der Signaturwert wird über URL || sort(post_params) gebildet, was bedeutet, dass die App dieselbe URL sehen muss wie Twilio sie verschickt hat — sonst stimmt die HMAC nicht. Hinter einem TLS-terminating Reverse-Proxy (Standard bei Container-Deployments) muss framework.trusted_proxies korrekt konfiguriert sein, sonst gibt Request::getUri() die interne URL zurück und der Vergleich schlägt fehl, obwohl Secret und Signatur stimmen. Das ist ein Konfigurationspunkt, der nach dem Patch in der App zu prüfen ist.

CVE-2026-45756 — JsonPath-Komponente, ReDoS via match() / search()

AdvisorySymfony Blog — CVE-2026-45756
Komponentesymfony/json-path (eingeführt mit Symfony 7.3)
Affected Versions>=7.3, <7.4.12 und >=8.0, <8.0.12
Fixed inSymfony 7.4.12, 8.0.12
ReporterHimanshu Anand
Fix-AutorAlexandre Daubois
Fix-Commitsymfony/symfony@1ac2d47 (branch 7.4)

JsonPath JsonCrawler evaluiert match()- und search()-Filter über preg_match() mit dem caller-supplied Pattern direkt. Das transformJsonPathRegex()-Helper macht nur kosmetisches Escaping — keine Längenbegrenzung, keine Beschränkung auf den RFC-9485-i-regexp-Subset, kein Backtracking-Bound. Eine attacker-controlled JSONPath-Expression mit catastrophic-backtracking Pattern wie $[?search(@, "(a+)+$")] gegen ein mässig grosses Dokument pinnt eine CPU-Kern für Sekunden pro Request; ein paar parallele Anfragen erschöpfen den Worker-Pool.

Der raffinierte Teil: die preg_match()-Calls in der betroffenen Code-Stelle sind mit @ prefixed, das heisst PCRE-Backtrack-Limit-Errors werden geschluckt — kein Log-Trace, kein Fehler-Event, nur stille Worker-Erschöpfung. Fix: JsonCrawler setzt pcre.backtrack_limit für die Dauer des Calls auf 10.000 herunter (und stellt den ursprünglichen Wert nachher wieder her), so dass pathologische Pattern schnell scheitern, statt den Worker zu stallen.

Conditions for exploitation: eine App, die einen attacker-influenced JSONPath-Ausdruck mit match()-/search()-Filter gegen ein nicht-triviales JSON-Eingabedokument auswertet. In der Praxis selten direkt aus End-User-UI, gelegentlich in Admin-Filter-Backends, API-Query-Sprachen, Reporting-DSLs.

Wer ist betroffen?

SetupStatusBedingung
Symfony-App mit symfony/mailtrap-mailer und konfiguriertem Webhook-EndpunktVoll betroffenWenn der Endpoint öffentlich erreichbar ist (Standardfall), nimmt er jeden POST entgegen. Patch einspielen, danach Secret-Konfiguration verifizieren.
Symfony-App mit symfony/mailjet-mailer und konfiguriertem Mailjet-WebhookVoll betroffenMailjet authentifiziert über Basic-Auth in der Webhook-URL. Der konfigurierte Secret wurde nicht gegen diese Credentials verglichen. Patch einspielen, URL-Konfiguration im Format user:password@… prüfen.
Symfony-App mit symfony/lox24-notifier und konfiguriertem LOX24-CallbackVoll betroffen ab Symfony 7.1Die LOX24-Bridge existiert erst seit Symfony 7.1; ältere 6.4-Apps haben sie nicht im Tree.
Symfony-App mit symfony/twilio-notifier und konfiguriertem Twilio-Status-WebhookVoll betroffenHMAC-Signatur wurde nicht verifiziert. Nach dem Patch muss zusätzlich trusted_proxies stimmen, sonst schlägt die Prüfung hinter dem Reverse-Proxy fehl.
Symfony-App ≥ 7.3 mit symfony/json-path und nicht vertrauenswürdigen JSONPath-AusdrückenVoll betroffenSelten direkt in End-User-UI, häufiger in Admin-Filtern, API-Query-Pfaden, Reporting-DSLs.
Symfony- oder Sylius-App ohne die vier Provider-Bridges und ohne JsonPath im TreeDurch diese vier CVEs nicht betroffenTrotzdem updaten — der Core-Patch der 20.05.-Welle adressiert die anderen sieben CVEs.
TYPO3-StacksNicht direkt betroffenTYPO3-Core zieht keine der vier Provider-Bridges und kein symfony/json-path. Wer das in Extensions zusätzlich eingebunden hat, sieht es in der SBOM oder im composer audit.
Sylius StorefrontsDurch diese vier CVEs nicht direkt betroffenSylius bringt die vier Bridges nicht im Default-Tree mit. Eigene Bundles für Mail- oder SMS-Notifications können sie nachziehen.

Bei Moselwal: was automatisch lief, was bleibt

Unser Beitrag zur 20.05.-Welle hat den Plattform-Audit für HtmlSanitizer-Trio, UrlGenerator, Mime\Address und X509Authenticator dokumentiert: 11 von 14 Sylius-Plattformen haben Multi-Locale-Routes, vier Symfony-Apps fahren API-Platform-Constraints, der Container-Rebuild lief via Renovate über Nacht.

Die heutigen vier Einträge sind im selben Patch-Strom eingelaufen: Mailtrap-, Mailjet-, LOX24- und Twilio-Bridge sowie symfony/json-path sind Sub-Pakete unter symfony/* und wurden mit dem Core-Update auf 6.4.40 / 7.4.12 / 8.0.12 mitgezogen. Manuelle composer show-Stichproben führen wir nicht durch. Die Komponenten-Inventur sitzt in der je Build automatisch erzeugten SBOM (CycloneDX), das CI-Gate über composer audit schlägt bei jeder bekannten Advisory ohnehin Alarm. Beides war nach dem 20.05.-Rebuild grün.

Was Renovate nicht abdecken kann, bleibt als manueller Schritt: die Konfigurations-Verifikation pro produktiv genutztem Webhook-Bridge. Welche Bridges in welchem Mandanten-Setup laufen, steht in der SBOM. Wo ein Bridge produktiv ist, müssen heute zwei Punkte geprüft werden — erstens der Secret-Wert in der App-Konfiguration gegen den aktuellen Wert im Provider-Dashboard (sonst blockt die ab 7.4.12 scharfe HMAC-Prüfung legitime Provider-Posts), zweitens bei Twilio framework.trusted_proxies. Renovate kann weder ENV-Variablen rotieren noch Provider-Dashboards öffnen.

Auswirkungen

Webhook-Event-Injection (drei der vier CVEs). Ein Angreifer mit Kenntnis des öffentlichen Webhook-Endpunkts kann gefälschte Events einspielen, sobald der Endpoint öffentlich erreichbar ist. In der Praxis sind diese Endpunkte trivial zu finden — sie tauchen in JS-Bundles auf, in der Setup-Anleitung des jeweiligen Providers, oder als Crawler-Treffer unter /webhook/…-Routen. Effekt je nach Provider:

JsonPath-ReDoS. CPU-Erschöpfung am Worker, kein RCE, kein Datenleck. In der Praxis: bei mässiger Parallelität (10–20 Requests) blockiert der Worker-Pool, weitere Anfragen laufen in den Queue-Timeout. Wo JsonPath in einem Admin-Backend hinter Auth eingesetzt wird, ist die Angriffsfläche auf eingeloggte Operatoren beschränkt — relevant, aber kein Public-Path-Vektor. Wo JsonPath dagegen in einer öffentlich erreichbaren API-Query-DSL exponiert ist (selten, aber in Headless-CMS-Kontexten existent), ist der Vektor öffentlich.

Nicht-Auswirkung: Code-Execution, Datenleck, Sandbox-Escape — keiner der vier Pfade führt dorthin. Es sind Authentizitäts- und Verfügbarkeitsprobleme, kein Integritätsbruch im Application-Code.

Kein bestätigter Mass-Exploit Stand 22.05.2026. Ein gezielter Angreifer auf eine bestimmte Plattform mit bekannter Webhook-URL hätte allerdings seit der Einführung der jeweiligen Bridge (Mailtrap, Mailjet, Twilio seit Symfony 5.x/6.x; LOX24 seit 7.1, also frühestens November 2024) ein offenes Tor — das Pattern ist trivial, der Endpoint öffentlich. Wer in den letzten Wochen ungewöhnliche Bounce- oder Delivery-Spitzen im CRM oder SMS-Status-Anomalien im Reporting hatte, prüft im Reverse-Proxy-Log Requests an /webhook/*-Routen, die nicht von Provider-IPs kommen.

Mitigation / Sofortmaßnahmen

Pfad 1 — Composer-Update (vorhanden, wenn die 20.05.-Welle eingelaufen ist)

 

composer update "symfony/*" --with-all-dependencies

# Verifikation der Hauptkomponente
composer show symfony/runtime | grep versions
# erwartet: 6.4.40 / 7.4.12 / 8.0.12 je nach Major-Linie

 

Die vier Webhook-Bridges und symfony/json-path sind Sub-Pakete unter dem symfony/*-Schirm. Wer in der 20.05.-Welle ein composer update "symfony/*" gefahren hat, hat sie damit bereits aktualisiert. Das heißt nicht, dass die Konfiguration erledigt ist — dazu Pfad 2.

Pfad 2 — Webhook-Secret in der App-Konfiguration verifizieren

Nach dem Patch greift die HMAC-Prüfung im Parser, sobald ein Secret konfiguriert ist. Die Symfony-Doku formuliert das so: „When no secret is configured the behaviour is unchanged: signature verification remains opt-in, but it is now actually enforced once opted in.“ Das bedeutet:

# config/packages/webhook.yaml
framework:
    webhook:
        routing:
            mailtrap:
                service: 'mailer.webhook.request_parser.mailtrap'
                secret: '%env(MAILTRAP_WEBHOOK_SECRET)%'
            mailjet:
                service: 'mailer.webhook.request_parser.mailjet'
                secret: '%env(MAILJET_WEBHOOK_SECRET)%'
            lox24:
                service: 'notifier.webhook.request_parser.lox24'
                secret: '%env(LOX24_WEBHOOK_SECRET)%'
            twilio:
                service: 'notifier.webhook.request_parser.twilio'
                secret: '%env(TWILIO_AUTH_TOKEN)%'

 

Die *_WEBHOOK_SECRET-Werte stammen aus dem jeweiligen Provider-Dashboard: Mailtrap (Settings → Webhooks → Signing Secret), Mailjet (Basic-Auth-Credentials in der Webhook-URL), LOX24 (Callback-Settings → Token), Twilio (Account-Dashboard → Auth Token).

Pfad 3 — Twilio-spezifisch: trusted_proxies setzen

Twilios HMAC bildet sich über die signierte URL inklusive der vollen &hellip;-Form. Hinter einem TLS-terminierenden Reverse-Proxy (nginx, HAProxy, Cloudflare, Traefik) sieht der PHP-Worker normalerweise internal-ip/&hellip;. Damit Request::getUri() die öffentliche URL zurückgibt, müssen trusted_proxies und trusted_headers korrekt konfiguriert sein.

 

# config/packages/framework.yaml
framework:
    trusted_proxies: '%env(default::TRUSTED_PROXIES)%'
    trusted_headers:
        - 'x-forwarded-for'
        - 'x-forwarded-host'
        - 'x-forwarded-proto'
        - 'x-forwarded-port'

 

Pfad 4 — composer audit als CI-Gate

Wie im 20.05.-Beitrag dokumentiert: composer audit als Pre-Deploy-Gate ist bei uns Standard, und war nach dem 20.05.-Rebuild grün. Wer das Gate noch nicht hat, baut es heute ein.

 

composer audit --format=plain

Detection / Prüfung

Webhook-Endpunkte inventarisieren

 

# Symfony-CLI im Projekt-Root
php bin/console debug:router | grep -iE '(webhook|notify|incoming|callback)'

 

Jeder Treffer ist ein produktiv erreichbarer Endpoint. Im Reverse-Proxy- oder Load-Balancer-Log nach Requests an diese Pfade in den letzten 30 Tagen scannen. Auffällige Spitzen, die nicht zur Provider-Dashboard-Aussage passen (z. B. „Mailtrap meldet 1.200 Events versendet, App-Log zeigt 4.700 POSTs am Endpoint“), sind ein klarer Hinweis auf laufende Injection-Versuche.

Falco-Rule: Webhook-Endpunkt von Nicht-Provider-IP (Skizze)

 

- rule: Symfony Webhook Anomalous Source
  desc: Webhook endpoint receives requests from non-provider IP ranges
  condition: >
    evt.type=accept and
    fd.lport in (80, 443) and
    not fd.cip in (mailtrap_provider_ranges, mailjet_provider_ranges, twilio_provider_ranges, lox24_provider_ranges)
  output: "Webhook endpoint accessed from non-provider IP (cip=%fd.cip lport=%fd.lport)"
  priority: NOTICE

 

Die *_provider_ranges-Listen sind je Provider mehrstellig CIDR-basiert. Mailtrap, Twilio und Mailjet publizieren ihre Edge-IPs in ihrer Doku. Die Falco-Rule ist eine Detection-Spur, kein Schutz — der eigentliche Schutz sitzt nach dem Patch in der HMAC-Prüfung.

Twilio-Smoke-Test nach dem Patch

Im Twilio-Dashboard: SMS Logs → einzelne SMS → „Send to Webhook Now“. Im App-Log auf RejectWebhookException oder erfolgreichen Decode prüfen. Schlägt der Smoke-Test fehl, ist meist trusted_proxies falsch konfiguriert (siehe Mitigation-Pfad 3).

JsonPath: Telemetrie für ReDoS-Versuche

Im JsonCrawler-Pfad ist pcre.backtrack_limit nach dem Patch auf 10.000 reduziert. Pathologische Pattern werfen jetzt einen Fehler, statt zu stallen. Wer die JsonPath-Komponente in einem öffentlich erreichbaren Pfad einsetzt, hängt der Fehlerbehandlung am besten ein Log-Event an, das client_ip und den auslösenden Pattern protokolliert — so wird ein gezielter ReDoS-Versuch sichtbar.

Betreiberempfehlung

Operational Decision Block

Mittelstand (Symfony- und Sylius-Plattformen)

Wer in der 20.05.-Welle den Composer-Update-Strom gefahren hat, hat den Patch schon drin. Was bleibt, ist der Verify-Pass pro aktivem Webhook-Bridge: Secret in der App-Konfiguration gegen den Wert im Provider-Dashboard prüfen, bei Twilio zusätzlich trusted_proxies. Ein Smoke-Test je Provider gibt Sicherheit.

Enterprise (mit eigenen Webhook-Parsern für andere Provider)

Wer eigene Webhook-Parser-Klassen für Provider geschrieben hat, die Symfony nicht abdeckt (Sipgate, MessageBird, Vonage, Plivo, lokale DACH-Provider), prüft das Pattern in der eigenen Implementierung: empfängt doParse() den Secret und vergleicht ihn auch gegen die Provider-Signatur? Wenn nicht, hat der Eigenbau dieselbe Klasse Bug wie der Symfony-Default vor 7.4.12. Die Fix-Commits (4e0467e Mailtrap, 8545fb2 Twilio) zeigen das Muster: hash_equals() für Constant-Time-Vergleich, RejectWebhookException bei Fehl-Signatur, Opt-in nur dort, wo explizit kein Secret konfiguriert ist.

Kubernetes und containerisierte Setups

Image-Rebuild gegen das aktualisierte composer.lock (im Regelfall schon Teil der 20.05.-Welle), gestaffelter Rollout. Bei Twilio die TRUSTED_PROXIES-Env-Variable im Deployment-Manifest gegen die Ingress-Cluster-IPs setzen, falls noch nicht geschehen.

Deklarative Stacks (NixOS, Talos, Flatcar mit Wolfi-Images)

Wie bei der 20.05.-Welle: Rebuild gegen das aktualisierte Composer-Lock, neuer Image-Tag, gestaffelter Rollout.

Was wir konkret getan haben

Der Symfony-Patch-Strom lief bei uns über die 20.05.-Renovate-Welle. Die Webhook-Parser-Bridges und symfony/json-path sind Sub-Pakete unter symfony/* und sind mit dem Core-Update auf 6.4.40 / 7.4.12 / 8.0.12 mitgezogen. composer audit als CI-Gate war nach dem 20.05.-Rebuild grün und ist es geblieben. Eine manuelle composer show-Stichprobe pro Mandant gibt es bei uns nicht — die Komponenten-Inventur sitzt in der je Build automatisch erzeugten SBOM (CycloneDX), nicht in einem heutigen Ad-hoc-Lauf.

Was die vier Webhook-Bridges zusätzlich verlangen und was Renovate nicht abdecken kann, ist die Konfigurations-Verifikation pro produktiv genutztem Provider. Ab 7.4.12 wird die HMAC-Prüfung im Default-Pfad scharf. Wer einen Secret konfiguriert hatte, dessen Wert zwischenzeitlich im Provider-Dashboard rotiert wurde (oder umgekehrt), bekommt jetzt RejectWebhookException auf legitime Provider-Posts. Diese Drift lässt sich nicht durch Code-Inventur finden, sondern nur durch Abgleich gegen das Provider-Dashboard und einen Smoke-Test (Provider-Backend → „Send Test Event“). Bei Twilio kommt der framework.trusted_proxies-Check dazu. Wo die SBOM einen der vier Bridges als produktiv ausweist, ist dieser Verify-Schritt heute fällig.

Was wir aus der Welle mitnehmen: sie trifft nicht den Symfony-Core, sondern vier Provider-Bridges parallel, alle gemeldet vom selben Researcher (Himanshu Anand), alle mit demselben Bug in doParse(Request, #[SensitiveParameter] string $secret). Solche Klassen-Treffer entstehen, wenn jemand eine Komponenten-Familie systematisch durchgeht — das gehört zur Aufmerksamkeit, nicht nur der Patch selbst. Auf Bridge-Ebene macht der 20.05.-Fix Symfony strukturell besser: die HMAC-Prüfung sitzt jetzt im Default-Pfad, die früher nur empfohlene Praxis ist zum Vertrag im Code geworden. Für die eigene Plattform-Disziplin bestätigt die Welle, was der 20.05.-Beitrag schon beschrieben hat: Inventur via SBOM, Patches via Renovate, Audit-Gate via composer audit. Der manuelle Schritt bleibt dort, wo Konfiguration ausserhalb des Code-Trees sitzt — Secret-Werte im Provider-Dashboard, Proxy-Topologie, ENV-Variablen.

Technischer Deep-Dive zur Twilio-HMAC: die Signatur ist HMAC-SHA1 über URL || sort(post_params), base64-encoded. Jede Differenz zwischen der URL, die Twilio versendet, und der URL, die Request::getUri() in der App zurückgibt, lässt die Verifikation scheitern. Hinter einem Reverse-Proxy ist das ein Konfigurationspunkt; in Container-Setups häufig der einzige Stolperstein nach dem Patch. Mailtrap, Mailjet und LOX24 sind hier einfacher: Mailtrap signiert HMAC-SHA256 über den Raw-Body (URL irrelevant), Mailjet vergleicht Basic-Auth-Credentials aus der URL (Sender bestimmt die Form), LOX24 prüft einen Token im X-LOX24-Token-Header (kein URL-Bezug).

Häufige Fragen zur Webhook-HMAC- und JsonPath-Welle

Müssen wir alle vier Provider-Bridges patchen, auch wenn wir keinen davon nutzen?+

Nein. Der eigentliche Patch ist Bestandteil des Symfony-Core-Updates auf 7.4.12 / 8.0.12 / 6.4.40, das ohnehin aus der 20.05.-Welle kommt. Die vier Bridges sind separate Composer-Pakete unter symfony/*, die nur installiert werden, wenn sie als Dependency angefordert sind. Wer keinen der vier in composer.lock hat, ist nicht direkt betroffen — der Core-Update genügt.

Wir nutzen Stripe-Webhooks — sind die auch betroffen?+

Stripe ist nicht in dieser Welle. Der Stripe-Webhook-Parser von Symfony (symfony/stripe-webhook bzw. Stripe-eigene SDKs) hatte die HMAC-Prüfung bereits implementiert und ist in dieser Advisory-Welle nicht enthalten. Stand 22.05.2026.

Wie prüfe ich, ob unser eigener Webhook-Endpoint (Eigenbau statt Symfony-Parser) den HMAC verifiziert?+

grep -rn 'hash_equals\|X-Mt-Signature\|X-Twilio-Signature\|X-LOX24-Token' src/Controller/ src/Webhook/ — wenn die Controller-Methode die Signatur aus dem Request liest und mit hash_equals() gegen einen Server-seitig berechneten HMAC vergleicht: Eigenbau ist im Konzept richtig. Wenn die Controller-Methode den eingehenden Request einfach an die Datenbank weiterreicht: kritisch, Eigenbau-Fix nach dem Symfony-Pattern (siehe Fix-Commits in den CVE-Detail-Tabellen oben). Kein Symfony-Update reicht hier — Eigenbau bleibt Eigenbau-Verantwortung.

Was passiert, wenn wir nach dem Patch denselben Secret in App-Config und Provider-Dashboard haben?+

Nichts — die HMAC-Prüfung greift und akzeptiert legitime Provider-Posts. Das ist der Soll-Zustand. Das Problem entsteht nur, wenn der Secret im App-Config einen anderen Wert hat als im Provider-Dashboard — dann werden alle bisherigen Provider-Posts ab 7.4.12 mit RejectWebhookException geblockt. Smoke-Test nach Patch ist Pflicht.

Warum erscheinen die vier Einträge nicht auch im Twig-3.26.0-Cluster vom selben Tag?+

Weil sie nicht in Twig, sondern in symfony/mailer, symfony/notifier und symfony/json-path sitzen. Der 20.05. war ein Doppel-Tag: Twig-3.26.0-Welle (13 Twig-CVEs) und Symfony-Patch-Welle (11+ Symfony-CVEs in den Releases 5.4.52, 6.4.40, 7.4.12, 8.0.12). Twig und Symfony-Core sind getrennte Repositories mit getrennten Advisory-Streams.

Müssen TYPO3-Plattformen reagieren?+

TYPO3-Core zieht keinen der vier Provider-Bridges und keine symfony/json-path als Default-Dependency. Wer in einer TYPO3-Installation Extensions hat, die diese Komponenten zusätzlich einziehen, sieht das in der SBOM und in composer.lock; composer audit als CI-Gate würde bei einer betroffenen Version Alarm schlagen. In den von uns betriebenen TYPO3-Stacks zeigt die SBOM-Inventur keinen der vier Bridges und kein symfony/json-path im Tree.

Fazit

Die vier heute nachgezogenen Einträge sind keine zweite Welle. Es sind vier Advisorys aus derselben Schicht wie am 20. Mai, gemeldet vom selben Researcher, alle mit demselben Bug im doParse(Request, #[SensitiveParameter] string $secret): das Secret wurde übergeben, aber nie ausgewertet. Das eigentliche Update kam mit der 20.05.-Welle in den composer.lock. Was bleibt, ist der Verify-Pass pro produktiv eingesetztem Bridge — Secret in der App-Konfiguration gegen den Wert im Provider-Dashboard, bei Twilio zusätzlich trusted_proxies. Der eigentliche Strukturhinweis: nicht eine einzelne Bridge war kaputt, sondern die ganze Bridge-Klasse hatte das HMAC-Prüfen nicht im Vertrag. Der Fix in 7.4.12 macht das Verify im Default-Pfad scharf. Wer eigene Provider-Bridges geschrieben hat, prüft das Muster jetzt in der eigenen Implementierung.

Bevor der nächste Provider-Webhook dazukommt

Symfony-Webhook-Schichten gegen die 20.05.-Welle prüfen und absichern?

Wir prüfen, mitigieren und validieren produktive Symfony-Plattformen gegen die Webhook-Welle vom 20. Mai. SBOM-Audit auf Mailtrap-, Mailjet-, LOX24- und Twilio-Bridges, Konfigurations-Verify gegen das Provider-Dashboard, Twilio-trusted_proxies-Validierung hinter dem Reverse-Proxy, Smoke-Test je Provider, Falco-/Tetragon-Telemetrie für Anomalien am Webhook-Endpunkt. JsonPath-Audit dort, wo symfony/json-path aus nicht vertrauenswürdiger Quelle ausgewertet wird, inklusive Längen-Validierung als Defense-in-Depth.

Plattformbetrieb statt Beratung auf Papier: wir übernehmen den Audit über mehrere Mandanten, die Verify-Sweeps und die Detection-Schicht — oder begleiten das eigene Team beim ersten Durchlauf. Cross-Reference zu DevSecOps und CMS-Plattformbetrieb.

Termin direkt vereinbaren

Über den Autor

Foto von Kai Ole Hartwig.

Kai Ole Hartwig

Founder · Moselwal Digitalagentur · OnlyOle

Programmiert seit 2002 – autodidaktisch gelernt, 2012 mit KO-Web selbständig gemacht, heute Moselwal. Über 100 Projekte, Fokus auf Security, Performance, Automatisierung und Qualität.