Affected versions
Symfony versions >=2.22.0, <2.36.0, >=3.0.0, <3.1.0 of the Symfony UX Live Component component are affected by this security issue.
The issue has been fixed in Symfony 2.36.0, 3.1.0.
Description
When using symfony/ux-live-component, methods annotated with
#[LiveAction] are invokable from the browser and mutate server-side state
via AJAX.
Symfony
gated these invocations on the presence of
Accept: application/vnd.live-component+html, with a code comment stating
that this acted as a CSRF protection.
The Accept header is a CORS-safelisted request header, so a
cross-origin fetch() can set it without triggering a preflight. The header
therefore provided no CSRF protection. Any #[LiveAction] could be forged
cross-origin against a victim's session.
In practice the attack is mitigated by SameSite=Lax session cookies
(Symfony's default), but applications using SameSite=None,
credentials: 'include' with a permissive cookie policy, or that have been
pivoted from another same-origin vector remained exposed.
Resolution
isLiveComponentRequest() now additionally requires the request header
X-Requested-With: XMLHttpRequest. This header is not CORS-safelisted, so
the browser issues a preflight OPTIONS request for any cross-origin
attempt; Symfony does not advertise CORS for LiveComponent endpoints, the
preflight fails, and the real request is blocked before it reaches the
application. The bundled Stimulus client already sends X-Requested-With on
every LiveComponent request (RequestBuilder.ts), so standard usage is
unaffected. Cross-origin callers must add X-Requested-With to their CORS
Access-Control-Allow-Headers allow-list.
The patch for this issue is available here for branch 2.x (and forward-ported to 3.x).
Credits
We would like to thank Anthropic (via Project Glasswing) for reporting the issue and Hugo Alliaume for providing the fix.