GHSA-3735-5339-xfwx

Suggest an improvement
Source
https://github.com/advisories/GHSA-3735-5339-xfwx
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-3735-5339-xfwx/GHSA-3735-5339-xfwx.json
JSON Data
https://api.test.osv.dev/v1/vulns/GHSA-3735-5339-xfwx
Aliases
Published
2026-07-28T16:40:05Z
Modified
2026-07-28T16:45:21.922967613Z
Severity
  • 9.6 (Critical) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:L CVSS Calculator
Summary
Poweradmin has Host Header Injection in OIDC redirect_uri, SAML ACS/SLO URL, and Logout Redirect Construction.
Details

Summary

Poweradmin v4.3.2 uses the attacker-controlled HTTP_HOST request header as the authoritative source for building callback URLs in its OIDC, SAML, and logout authentication flows without any validation. An unauthenticated attacker can poison the redirect_uri sent to the Identity Provider, causing the IdP to redirect the victim's authorization code to an attacker-controlled server - resulting in full account takeover with no credentials required.

Three independent code paths are affected:

  • Primary (Critical): OidcService::getCallbackUrl() - redirect_uri poisoning
  • Secondary (High): SamlConfigurationService::getBaseUrl() - SAML ACS/SLO URL poisoning
  • Tertiary (Medium): LogoutController::getBaseUrl() - post-logout redirect poisoning

Details

Root Cause

The application constructs absolute URLs dynamically from HTTP_HOST rather than from a trusted configured base URL. The header is fully client-controlled and is not validated before use in any authentication flow.

Poweradmin's own codebase contains the correct pattern - DocsController::getValidatedHost() (line 244) calls isValidHostname() before using the value - but this was never applied to authentication flows.

### Primary: lib/Application/Service/OidcService.php (~line 460)

```php private function getCallbackUrl(): string { $scheme = $this->detectScheme(); // HTTPHOST taken directly with zero validation $host = $this->request->getServerParam('HTTPHOST', 'localhost'); $basePrefix = $this->configManager->get('interface', 'baseurlprefix', ''); return $scheme . '://' . $host . $basePrefix . '/oidc/callback'; }

HTTPHOST is embedded verbatim as redirecturi in the OAuth 2.0 authorization request sent to the IdP. HTTPXFORWARDED_PROTO is similarly used unvalidated for scheme detection.

Secondary: lib/Application/Service/SamlConfigurationService.php (~line 134)

private function getBaseUrl(): string { $configuredBaseUrl = $this->configManager->get('interface', 'base_url', ''); if (!empty($configuredBaseUrl)) { return rtrim($configuredBaseUrl, '/'); // safe path - rarely configured } // Falls through on every default installation $host = $SERVER['HTTPHOST'] ?? 'localhost'; ... return $scheme . '://' . $host . $prefix; }

Used to construct SAML ACS URL, SLO URL, and entity ID - all poisonable via Host header. The safe fallback only activates when interface.base_url is explicitly set, which is optional and empty by default.

Tertiary: lib/Application/Controller/LogoutController.php (~line 272)

Same $SERVER['HTTPHOST'] pattern used for post-logout redirect URL construction.

PoC

Environment: Poweradmin v4.3.2, Docker, PHP 8.2, OIDC enabled, interface.base_url empty (default).

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

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

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

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

parsestr(parseurl(\$authUrl, PHPURLQUERY), \$p); echo 'redirecturi: ' . urldecode(\$p['redirecturi']) . PHP_EOL;

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

Output:

redirect_uri: http://attacker.com/oidc/callback

[CONFIRMED] Host header injection successful - redirect_uri contains attacker.com

The redirect_uri in the authorization request sent to the Identity Provider is http://attacker.com/oidc/callback. The victim's authorization code will be delivered to this URL upon successful authentication.

Note on PKCE: PKCE does not mitigate this attack. The attacker initiates the flow themselves and controls both codechallenge and codeverifier.

Impact

Direct Impact

An attacker who can send a request with a spoofed Host header - directly or via a misconfigured reverse proxy (proxysetheader Host $http_host is the nginx default) - can steal any user's authorization code and gain full authenticated access to Poweradmin. No credentials, malware, or prior access required.

DNS Infrastructure Impact

Poweradmin manages PowerDNS. A compromised administrator account grants full DNS zone control, enabling:

  • MX hijacking - redirect all inbound email to attacker's mail server; intercept password reset emails and 2FA codes for any third-party service registered with the domain
  • SPF/DKIM manipulation - add attacker's IP to SPF, publish attacker's DKIM key → send cryptographically authenticated email as the organization (passes DMARC)
  • Subdomain takeover - point mail., vpn., app. to attacker infrastructure
  • SSL certificate theft - remove CAA records and complete ACME DNS-01 challenge to obtain wildcard certificate *.company.com from any CA
  • Full domain delegation - delegate subdomains to attacker nameserver

    CVSS v3.1

    ┌──────────────────────────────────┬─────────────────────────────────────┬──────────────┐ │ Scenario │ Vector │ Score │ ├──────────────────────────────────┼─────────────────────────────────────┼──────────────┤ │ Standard deployment │ AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:L │ 8.2 High │ ├──────────────────────────────────┼─────────────────────────────────────┼──────────────┤ │ Proxy misconfigured ($http_host) │ AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:L │ 9.3 Critical │ └──────────────────────────────────┴─────────────────────────────────────┴──────────────┘

    Recommended Fix

    Immediate mitigation: Set interface.base_url in config/settings.php - activates the safe branch in SamlConfigurationService immediately.

    Code fix for OidcService: Prefer the configured base URL; if absent, validate HTTPHOST via filtervar($hostname, FILTERVALIDATEDOMAIN, FILTERFLAGHOSTNAME) before use - the same pattern already implemented in DocsController::getValidatedHost().

Database specific
{
    "github_reviewed": true,
    "nvd_published_at": "2026-06-23T23:16:49Z",
    "cwe_ids": [
        "CWE-601"
    ],
    "severity": "CRITICAL",
    "github_reviewed_at": "2026-07-28T16:40:05Z"
}
References

Affected packages

Packagist / poweradmin/poweradmin

Package

Name
poweradmin/poweradmin
Purl
pkg:composer/poweradmin/poweradmin

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0Unknown introduced version / All previous versions are affected
Fixed
4.2.4

Affected versions

v2.*
v2.1.8
v2.1.9
v2.2.0
v2.2.1
v2.2.2
v3.*
v3.0.0
v3.1.0
v3.2.0
v3.3.0
v3.4.0
v3.4.1
v3.4.2
v3.5.0
v3.5.1
v3.6.0
v3.6.1
v3.7.0-alpha.1
v3.7.0
v3.8.0
v3.8.1
v3.9.0
v3.9.1
v3.9.2
v3.9.3
v3.9.4
v3.9.5
v3.9.6
v3.9.7
v3.9.8
v3.9.9
v3.9.10
v3.9.11
v4.*
v4.0.0
v4.0.1
v4.0.2
v4.0.3
v4.0.4
v4.0.5
v4.0.6
v4.0.7
v4.0.9
v4.0.10
v4.0.11
v4.1.0
v4.1.1
v4.1.2
v4.1.3
v4.1.4
v4.2.0
v4.2.1
v4.2.2
v4.2.3

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-3735-5339-xfwx/GHSA-3735-5339-xfwx.json"

Packagist / poweradmin/poweradmin

Package

Name
poweradmin/poweradmin
Purl
pkg:composer/poweradmin/poweradmin

Affected ranges

Type
ECOSYSTEM
Events
Introduced
4.3.0
Fixed
4.3.3

Affected versions

v4.*
v4.3.0
v4.3.1
v4.3.2

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-3735-5339-xfwx/GHSA-3735-5339-xfwx.json"