Administrator password-reset link poisoning enables account takeover
The password-reset email derived its absolute authority from the anonymous request Host header
CVSS 3.1 base score
HighVector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Summary
Source
reset-password operation
src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/admin/AdminUserPassword.xml:27
Sink
adminPasswordReset template
src/Sylius/Bundle/CoreBundle/Resources/views/Email/adminPasswordReset.html.twig:41
An unauthenticated attacker could request an administrator password reset with an attacker-controlled Host header. The legitimate email then contained the real reset token under the attacker's HTTPS origin, allowing token capture when the administrator clicked it.
Root cause. Reset token generation and email rendering happened synchronously inside the initiating request. Twig's absolute url() helper used the request-derived router context, while the application supplied neither a strict trusted-host policy nor a canonical security-link origin.
Remediation evidence. Sylius confirmed the report, published GHSA-77w3-2367-7xvq with an explicit Winfunc Research credit, and released fixes in 1.12.25, 1.13.17, 1.14.20, 2.1.16, and 2.2.9.
Severity
- Attack vectorAV
- Network
- Attack complexityAC
- Low
- Privileges requiredPR
- None
- User interactionUI
- Required
- ScopeS
- Unchanged
- ConfidentialityC
- High
- IntegrityI
- High
- AvailabilityA
- High
Metric values as published in the disclosure vector. Meters show how far each value raises exposure.
Source-to-sink trace
- Source · attacker-controlledsrc/
Sylius/ Bundle/ ApiBundle/ Resources/ config/ api_platform/ resources/ admin/ AdminUserPassword.xml:27 reset-password operation
- Step 01src/
Sylius/ Bundle/ ApiBundle/ Resources/ config/ api_platform/ resources/ admin/ AdminUserPassword.xml:27 The public reset operation accepts the victim administrator email while the request carries attacker-selected authority metadata.
python POST /api/v2/admin/administrators/reset-password Host: attacker.example - Step 02src/
Sylius/ Bundle/ ApiBundle/ CommandHandler/ Account/ RequestResetPasswordEmailHandler.php The handler generates a fresh token and dispatches the email command within the same poisoned request context.
php $token = $this->tokenGenerator->generate(); $this->commandBus->dispatch(new SendResetPasswordEmail($email, $token)); - Step 03src/
Sylius/ Bundle/ CoreBundle/ Resources/ views/ Email/ adminPasswordReset.html.twig:41 The absolute URL helper embeds the attacker-controlled authority together with the valid secret token.
python {{ url('sylius_admin_password_reset', {'token': user.passwordResetToken}) }} - Sinksrc/
Sylius/ Bundle/ CoreBundle/ Resources/ views/ Email/ adminPasswordReset.html.twig:41 adminPasswordReset template
Impact
Reported impact
The attacker can replace the administrator's password and exercise that account's administrative privileges. Downstream access to customer data, orders, configuration, and user management depends on the victim administrator's assigned roles.
Attack surface
The unauthenticated Sylius administrator password-reset API on deployments that accepted arbitrary Host headers.
Preconditions
The attacker knows the administrator's email and controls an HTTPS origin. The victim must click the legitimate reset email; no mailbox access, existing session, or Sylius credential is required.
Attack path
- 1
Request a reset for the target administrator while supplying the attacker's Host value.
- 2
Sylius sends the legitimate mailbox a link whose authority is the attacker origin.
- 3
Capture the fresh token when the administrator follows the link.
- 4
Redeem the token at the real public reset endpoint with an attacker-chosen password.
- 5
Authenticate as the compromised administrator.
Proof of concept
- 01
Environment setup
Use an isolated affected Sylius instance, a test administrator mailbox, and an attacker-controlled local HTTPS origin.
- 02
Target configuration
Route a request with an arbitrary Host value to Sylius without an upstream host allowlist, matching the vulnerable deployment condition.
- 03
Exploit delivery
Send the public reset request with
Host: attacker.example, then follow the received email and record the token-bearing request made to the attacker origin. - 04
Expected response
The email link points to the attacker host and contains a valid administrator reset token that the real reset endpoint accepts.
- 05
Outcome
Patched releases construct the security link from trusted canonical configuration, so request authority cannot redirect a valid reset token to another host.
Remediation
Guidance
Upgrade to a version listed in GHSA-77w3-2367-7xvq, configure a canonical application origin, and enforce trusted hosts at both the application and reverse proxy.
{{ url('sylius_admin_password_reset', {'token': token}) }}const hostname = $this->channelContext->getChannel()->getHostname();$path = $this->router->generate( 'sylius_admin_render_password_reset', ['token' => (string) $user->getPasswordResetToken()], UrlGeneratorInterface::ABSOLUTE_PATH,);return ($this->unsecuredUrls ? 'http://' : 'https://') . $hostname . $path;
Check the upstream record for the project's current remediation status.
Investigate the paths that matter in your codebase.
Winfunc can trace relevant code paths, preserve supporting evidence, and prepare remediation suggestions for engineering review within an agreed scope.
