CVE-2022-39369 is a critical vulnerability affecting the phpCAS authentication library. phpCAS helps PHP applications integrate with CAS, a Single Sign-On (SSO) protocol. Due to how phpCAS (versions before 1.6.) trusts certain HTTP headers to determine service URLs, attackers can trick phpCAS into accepting SSO tickets for the wrong service. In simple words: with the right conditions, someone can hijack users’ sessions and access accounts in supposed “protected” PHP apps that rely on CAS via phpCAS.

Below, I’ll walk you through what exactly is wrong, how it can be exploited, and what you need to do to fix or mitigate it. This is an exclusive deep-dive designed for practical understanding, especially if you manage PHP apps with CAS-based SSO.

Understanding the Vulnerability

phpCAS uses the HTTP Host header and sometimes X-Forwarded-Host or similar headers to build the service URL for CAS ticket validation. This service URL tells the CAS server what application is asking for authentication.

The Problem:  
Attackers can manipulate Host headers (or X-Forwarded-* headers in some setups) in requests sent to your PHP webserver. If phpCAS uses those untrusted values to build the service URL, it might validate SSO tickets intended for another app or domain, not just your own app.

Exploit Scenario

1. Attacker gets a valid SSO ticket for any app registered with your organization’s CAS (such as their own app or a test app).

2. Attacker crafts a request to your vulnerable phpCAS-based app, forging the Host (or X-Forwarded-Host) header to match the hostname of the original ticket.

3. Your vulnerable phpCAS app thinks the ticket is valid (because the service URL matches what the CAS server expects) and authenticates the attacker as the user whose ticket it is.

In the worst case: If your CAS server is configured to accept broadly-matching service URLs (e.g., using a wildcard pattern like ^(https)://.*), the attacker doesn’t even need a pre-authorized app—they can use any SSO-enabled service’s ticket to get into any other SSO-protected app running phpCAS!

Here’s an abridged pseudo-PHP example to show the problem

// Before phpCAS 1.6., typical service URL building:
$server_host = $_SERVER['HTTP_HOST']; // BAD: this is user-controlled!
$server_uri  = $_SERVER['REQUEST_URI'];
$service_url = "https://$server_host$server_uri";;

A clever attacker sends

GET /login/cas.php HTTP/1.1
Host: attacker.com
...

phpCAS tells the CAS server:  
“Validate this ticket for https://attacker.com/login/cas.php”  
If the ticket came from attacker.com, it passes. The CAS server says “yes,” and the attacker is logged in under the user whose ticket was stolen/reused.

Mitigation in phpCAS 1.6.+

Starting from 1.6., you must set the service base URL explicitly; phpCAS no longer builds it automatically from HTTP headers:

phpCAS::client(CAS_VERSION_2_, 'cas.example.org', 443, '';
phpCAS::setServiceBaseUrl('https://my.safe-service.com';);
// This tells phpCAS to only use this as the service URL base!

Exploit Details and Proof-of-Concept

Here’s a simplified exploit outline. Suppose you’re running vulnerable-app.com using phpCAS < 1.6.. The attacker has access to attacker-app.com, also registered to use CAS.

1. Attacker logs into attacker-app.com using their target victim’s CAS credentials (or, tricking them into giving up a service ticket, e.g., via phishing).

Attacker gets the SSO ticket for attacker-app.com: ST-abcde12345

3. Attacker crafts a request to vulnerable-app.com, but sets the Host header to attacker-app.com, and supplies the ticket:

GET /index.php?ticket=ST-abcde12345 HTTP/1.1
Host: attacker-app.com

4. vulnerable-app.com’s phpCAS builds the service URL as attacker-app.com and asks CAS to validate ST-abcde12345 for that URL. Since it matches, the ticket is accepted.

Real-World Severity

- If your *CAS server’s service registry* uses loose wildcards (like ^(https)://.*), all SSO services become attackable via cross-service replay.
- If you strictly whitelist URLs (like exact hostnames), the exploit only works if the attacker controls a whitelisted service.


## How to Fix / Mitigate

Upgrade phpCAS:

*Update to phpCAS 1.6.+ immediately* and follow the upgrade guide. You must set the serviceBaseUrl when you initialize phpCAS.

phpCAS::client(CAS_VERSION_2_, 'cas.example.org', 443, '');

phpCAS::setServiceBaseUrl('https://your-safe-domain.com');

Sanitize Incoming Headers:

If you use a reverse proxy or load balancer, make sure to sanitize the following headers so that end-users cannot set them:

References

- CVE-2022-39369 GHSA advisory
- phpCAS Release Notes (1.6.)
- CAS official documentation

Final Thoughts

CVE-2022-39369 is a wake-up call: never trust user-controlled HTTP headers for authentication logic! If your organization uses phpCAS for Single Sign-On, check your version and configuration right now. Upgrade, set explicit service URLs, and tighten your CAS service registry. Fast response can prevent compromised accounts and serious data leaks.

If you have further questions or discover your setup is impacted, reach out on the phpCAS GitHub for the latest guidance. Stay safe!

Timeline

Published on: 11/01/2022 17:15:00 UTC
Last modified on: 01/11/2023 17:23:00 UTC