GHSA-g2fm-8hr4-j82h: High severity composer/easycorp/easyadmin-bundle vulnerability
Summary
EasyAdmin serves all backend requests through a single dashboard route and, for custom actions (Action::linkToRoute() / MenuItem::linkToRoute()), swaps the executed controller based on the routeName query parameter on the kernel.controller event.
That swap happens after Symfony's security firewall has already evaluated accesscontrol against the original dashboard URL, and the routeName value was not validated. As a result, a path-based accesscontrol rule protecting the target route was never evaluated, so a low-privilege backend user could reach a more restricted route by name.
Impact
Any application where accesscontrol (or another path-based Symfony security rule) protects some routes more strictly than the dashboard URL used to reach EasyAdmin. An attacker who can reach a single EasyAdmin URL and knows a target route's name can execute that route's controller, bypassing the path-based rule.
Only path-based protections are bypassed. Routes whose controller enforces its own authorization with #[IsGranted] / denyAccessUnlessGranted() remain protected, because those checks are recomputed against the swapped-in controller.
Patches
Fixed in 4.29.16 and 5.5.1. Before dispatching a custom-action route, EasyAdmin now re-evaluates the target route's accesscontrol rule and denies the request if the current user is not granted access.
Workarounds
Add controller-level authorization (#[IsGranted] / denyAccessUnlessGranted()) to any sensitive route, since controller-level checks are still enforced. Upgrading is the recommended fix.
Credits
Reported by @TungNGo02.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
composer/easycorp/easyadmin-bundleto a version that resolves this vulnerability.Fixed in 5.5.1 - Upgrade
Upgrade
composer/easycorp/easyadmin-bundleto a version that resolves this vulnerability.Fixed in 4.29.16 - Upgrade
Upgrade to a fixed release to a version that resolves this vulnerability.
Fixed in 4.29.16 - Upgrade
Upgrade to a fixed release to a version that resolves this vulnerability.
Fixed in 5.5.1 - Configuration
Add controller-level authorization (e.g., `#[IsGranted]` or `denyAccessUnlessGranted()`) to any sensitive route/controller to ensure authorization is enforced even when EasyAdmin re-routes via the `routeName` query parameter.
EasyAdmin (custom actions via Action::linkToRoute / MenuItem::linkToRoute) access_control enforcement = controller-level authorization (denyAccessUnlessGranted / #[IsGranted]) on sensitive controllers
Event History
Frequently Asked Questions
How can I determine whether an EasyAdmin deployment is exposed?
Review routes reachable through the EasyAdmin dashboard, especially custom actions or menu items linked with linkToRoute(). Exposure exists when a route has stricter path-based Symfony access_control protection than the dashboard URL and its controller does not independently enforce authorization.
Are routes protected by controller-level authorization affected?
No. Authorization enforced by #[IsGranted] or denyAccessUnlessGranted() is recomputed for the controller selected through the custom action, so those protections remain effective.
What does an attacker need to exploit this condition?
The attacker needs access to at least one EasyAdmin URL and knowledge of the target route's name. A low-privilege backend user can then invoke the target controller through the routeName query parameter when only a path-based rule protects that route.