Weakness reference
CWE-441

Unintended Proxy or Intermediary ('Confused Deputy')

A "Confused Deputy" vulnerability occurs when a trusted application or service is tricked into performing actions on behalf of an attacker, rather than the…

01Summary

A "Confused Deputy" vulnerability occurs when a trusted application or service is tricked into performing actions on behalf of an attacker, rather than the legitimate user who initiated the request. The application fails to verify that an intermediate request actually came from the person it claims to represent, allowing an attacker to impersonate another user or escalate their own privileges through a trusted intermediary.

02How It Happens

This weakness arises when an application trusts information passed to it by an upstream component—such as a proxy, load balancer, API gateway, or another service—without verifying that the information is authentic. A common scenario involves HTTP headers (like X-Forwarded-For, X-Original-User, or custom authentication headers) that are meant to convey the identity of the original requester. If the application blindly accepts these headers without validating their source, an attacker can forge them to impersonate another user. Similarly, if a service accepts requests from a trusted intermediary but doesn't verify that the intermediary itself validated the request, the service may execute commands intended for a different actor.

03Real-World Impact

An attacker exploiting this vulnerability can perform unauthorized actions as another user—accessing their data, modifying their settings, or triggering sensitive operations in their name. In multi-tier architectures, a compromised or attacker-controlled intermediary can escalate privileges by forging identity headers. The impact ranges from account takeover and data theft to unauthorized administrative actions, depending on the privileges of the impersonated user.

04Vulnerable & Fixed Patterns

Vulnerable pattern
from flask import Flask, request

app = Flask(__name__)

@app.route('/transfer', methods=['POST'])
def transfer_funds():
    # Trusts the X-User-ID header without validation
    user_id = request.headers.get('X-User-ID')
    amount = request.form.get('amount')
    
    # Performs action on behalf of the header-supplied user
    process_transfer(user_id, amount)
    return "Transfer complete"

Why it's vulnerable:
The application accepts the user identity directly from an HTTP header without verifying that the header came from a trusted, authenticated source. An attacker can forge this header to impersonate any user.

Fixed pattern
from flask import Flask, request, session

app = Flask(__name__)

@app.route('/transfer', methods=['POST'])
def transfer_funds():
    # Use the authenticated session, not untrusted headers
    user_id = session.get('user_id')
    
    if not user_id:
        return "Unauthorized", 401
    
    amount = request.form.get('amount')
    process_transfer(user_id, amount)
    return "Transfer complete"
Vulnerable pattern
<?php
// Trusts the X-User-ID header without validation
$user_id = $_SERVER['HTTP_X_USER_ID'] ?? null;
$amount = $_POST['amount'] ?? null;

if ($user_id && $amount) {
    // Performs action on behalf of the header-supplied user
    process_transfer($user_id, $amount);
    echo "Transfer complete";
}
?>

Why it's vulnerable:
The application reads user identity from a custom HTTP header that an attacker can easily forge in their own request, bypassing authentication.

Fixed pattern
<?php
// Use the authenticated session established during login
session_start();

if (!isset($_SESSION['user_id'])) {
    http_response_code(401);
    die("Unauthorized");
}

$user_id = $_SESSION['user_id'];
$amount = $_POST['amount'] ?? null;

if ($amount) {
    process_transfer($user_id, $amount);
    echo "Transfer complete";
}
?>

05Prevention Checklist

Authenticate at the boundary.
Establish the user's identity through a secure, tamper-proof mechanism (session tokens, signed JWTs, mutual TLS) before accepting any request, rather than trusting headers from the client.
Never trust forwarding headers alone.
If you must use X-Forwarded-For or similar headers (e.g., behind a proxy), validate that the request came from a known, trusted proxy IP and never use these headers as the sole source of identity.
Validate intermediary identity.
If your application receives requests from another service or proxy, authenticate that intermediary using certificates, API keys, or mutual TLS—not just network proximity.
Use signed or encrypted tokens.
If passing identity information between services, sign or encrypt it cryptographically so that only authorized parties can create or modify it.
Log and monitor identity sources.
Track which identity mechanism was used for each request and alert on unexpected patterns (e.g., a sudden spike in requests with forged headers).
Apply the principle of least privilege.
Ensure that even if an attacker impersonates a user, the damage is limited by restricting what that user can do.

06Signs You May Already Be Affected

Look for unexpected actions performed by users who deny initiating them, or audit logs showing requests from unusual IP addresses or with mismatched identity headers. If you see requests with custom identity headers that don't match the authenticated session, or if your application accepts identity from multiple conflicting sources, you may be vulnerable. Review your proxy and load-balancer configurations to ensure they are not injecting or allowing client-controlled identity headers.

07Related Recent Vulnerabilities