Affected versions
Symfony versions <5.4.53, >=6, <6.4.41, >=7, <7.4.13, >=8, <8.0.13 of the Symfony Security HTTP component are affected by this security issue.
The issue has been fixed in Symfony 5.4.53, 6.4.41, 7.4.13, 8.0.13.
Description
When a firewall is configured with form-login (or any authenticator
using DefaultAuthenticationFailureHandler) and the
failure_forward: true option, the handler reads the _failure_path
parameter from the failing login request and uses it as the path of an
internal subrequest dispatched through HttpKernelInterface::SUB_REQUEST.
Symfony's Firewall::onKernelRequest listener intentionally skips
subrequests under the assumption they are internally generated and trusted,
which also means AccessListener (the listener that evaluates
access_control) does not run. Because the attacker controls the target
of the subrequest, an unauthenticated POST to the check path with
_failure_path=/admin/whatever performs a local request forgery that
executes the target controller outside the firewall perimeter and returns
its response to the caller.
Applications that follow Symfony's recommended best practice of protecting
administrative areas with broad access_control rules (e.g. ^/admin
requires ROLE_ADMIN) and expose read-only GET endpoints under that area
(data exports, internal APIs, account views) are fully exposed: any such
GET route can be read by an unauthenticated attacker without any developer
misconfiguration, debug mode, or state-changing GET handler being required.
Resolution
DefaultAuthenticationFailureHandler no longer honors the
request-supplied _failure_path parameter when failure_forward is
enabled. The subrequest is always dispatched to the configured
failure_path option (defaulting to login_path), which is set by the
application owner and not by the request. The redirect branch
(failure_forward: false) is unchanged because redirects re-enter the
firewall on the next request and are not subject to this bypass.
The patch for this issue is available here for branch 5.4.
Credits
We would like to thank Trung Tran and attom for reporting the issue, and Nicolas Grekas for providing the fix.