Back to Blog

OAuth Redirect URI Manipulation via X-Forwarded-Host Injection

Muhammad Saad
OAuth Redirect URI Manipulation via X-Forwarded-Host Injection
VAPTHost Header InjectionWAPT

During an authorized black-box web application penetration test, I identified an issue in the Azure Active Directory (Azure AD) authentication flow of target.com.
The application appeared to construct its OAuth redirect_uri using the client-supplied X-Forwarded-Host HTTP header. By modifying this single header, I was able to change the callback hostname embedded in the OAuth authorization request.
In this article, I'll walk through how I identified the behavior, validated it through controlled comparisons, captured the proof of concept, and assessed its potential security impact.

Disclaimer: This research was conducted during an authorized vulnerability disclosure program assessment. Testing was limited to the in-scope application and a self-owned anonymous session. The results demonstrate callback URL manipulation; authorization-code interception and account takeover were not confirmed.


Understanding the OAuth Flow

OAuth authentication commonly involves redirecting a user from a web application to an identity provider. The authorization request contains a parameter named redirect_uri, which specifies where the identity provider should return the browser after authentication.
For example, the expected callback in this case was:
https://target.com/user/auth/azure_activedirectory_v2/callback
This callback URL should be constructed using a trusted, server-side configuration rather than an arbitrary value supplied by the client.
HTTP forwarding headers, such as X-Forwarded-Host, are frequently used by reverse proxies to communicate the original hostname. However, if an application trusts a client-controlled forwarding header without validating its source, that header may influence security-sensitive URL generation.
This led me to investigate whether the Azure AD authentication flow was affected by this behavior.


Identifying the Authentication Endpoint

I first mapped the legitimate authentication flow using Firefox and inspected the related HTTP requests.
The endpoint initiating the Azure AD authentication process was:

POST /user/auth/azure_activedirectory_v2 HTTP/2
Host: target.com

The endpoint responded with an HTTP redirect to Microsoft's OAuth authorization endpoint.
I focused on the Location response header because it contained the authorization request, including the redirect_uri parameter.


Establishing the Baseline

Before attempting any manipulation, I sent the authentication request without an X-Forwarded-Host header.
The application returned an HTTP 302 Found response. The resulting OAuth authorization URL contained a redirect_uri pointing to the expected production hostname.
A simplified, sanitized representation of the response is shown below:

HTTP/2 302 Found
Location: https://login.microsoftonline.com/.../authorize
  ?client_id=[REDACTED]
  &redirect_uri=https%3A%2F%2Ftarget.com%2Fuser%2Fauth%2Fazure_activedirectory_v2%2Fcallback
  &response_type=code
  &scope=openid%20profile%20email
  &state=[REDACTED]

After URL-decoding the redirect_uri parameter, the callback was:
https://target.com/user/auth/azure_activedirectory_v2/callback
This established the expected behavior and provided a baseline for comparison.

image


Testing X-Forwarded-Host Manipulation

After establishing the baseline, I repeated the same request while keeping the session and CSRF token unchanged.
The only relevant modification was the addition of the following header:
X-Forwarded-Host: evil.example
The application again returned a 302 Found response. However, this time the authorization URL contained a different callback hostname.
The resulting response included:

HTTP/2 302 Found
Location: https://login.microsoftonline.com/.../authorize
  ?client_id=[REDACTED]
  &redirect_uri=https%3A%2F%2Fevil.example%2Fuser%2Fauth%2Fazure_activedirectory_v2%2Fcallback
  &response_type=code
  &scope=openid%20profile%20email
  &state=[REDACTED]

Decoding the parameter revealed the following callback:
https://evil.example/user/auth/azure_activedirectory_v2/callback
The callback hostname had changed from target.com to evil.example after introducing the header. This was the key observation: a client-supplied HTTP header influenced the hostname embedded in a security-sensitive OAuth parameter.

image


Security Impact

OAuth redirect URI handling is security-sensitive because the callback determines where the identity provider returns the authorization response.
If an application allows an attacker to influence this URL, the consequences depend on how the identity provider validates redirect URIs and how the rest of the authentication flow is implemented.

Severity and Classification

The assessment classified the finding as Medium severity. The proposed CVSS v3.1 vector in the assessment was: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N


Conclusion

During an authorized black-box assessment, I identified a reproducible issue in the Azure AD authentication flow of target.com.
The application's OAuth authorization request used a callback hostname influenced by the client-supplied X-Forwarded-Host header. Controlled comparisons confirmed that different header values produced corresponding callback hostnames in the generated redirect_uri.

Lessons Learned

This assessment highlights several important principles for web application security:

  • Request headers are not inherently trustworthy. Their security depends on the architecture and the trust boundary between clients, proxies, and applications.
  • OAuth callback URLs deserve special protection. Their hostnames should be derived from trusted configuration.
  • Controlled comparisons strengthen findings. Establishing a baseline and changing one variable at a time helps isolate the actual cause.
  • **Negative controls matter. ** Testing related headers helps distinguish the demonstrated input from alternative explanations.
  • Impact must be evidence-based. A manipulated callback parameter is a meaningful finding, but it should not automatically be described as account takeover.

Blockquote
Thank you for reading. I hope you enjoyed this story and found it helpful.😊
LinkedIn: https://www.linkedin.com/in/muhammad-saad-9818502b3/
Guthub: https://github.com/msaadraj