You don't have access to the file. The rules are clear about that. Your account can't read it.
But there's a service running on the same system that can. It's trusted. It has elevated permissions. And it accepts requests.
So instead of reading the file yourself, you ask the service to read it for you.
The service checks whether it can access the file. It can. So it does.
You just read something you weren't allowed to read. And the service did exactly what it was designed to do.
What Just Happened
The attacker didn't steal any permissions. Nothing was compromised. No vulnerability was exploited in the traditional sense.
What happened is simpler and, in a way, more interesting: a trusted component used its own authority to fulfill a request that the caller wasn't authorized to make.
The deputy didn't get hacked. The deputy got confused.
In security terms, a deputy is a component that acts on behalf of others. A file service, a cloud function, a privileged API, a system daemon. These components often hold more authority than their callers, because they perform operations users can't or shouldn't perform directly.
A deputy becomes confused when it can't distinguish between what it is allowed to do and what the caller is allowed to ask it to do. It applies its own authority when it should be applying the caller's.
Those are two very different things.
The Central Problem: Two Separate Authority Questions
When a caller sends a request to a privileged service, there are two questions the service needs to answer:
What can I (the service) access?
What is this caller allowed to access through me?
A secure design answers the second question. A confused deputy only answers the first.
Caller: "Give me resource X"
↓
Trusted service
↓
"Can I access resource X?" → Yes
↓
Returns resource X
The service validates its own authority. It never validates the caller's authority. So the caller's permissions are irrelevant. Whatever the service can access, the caller can access through it.
The correct version of that flow looks different:
Caller: "Give me resource X"
↓
Trusted service
↓
"Is this caller allowed to access resource X?" → ?
↓
Allow or deny based on that answer
The service's own permissions are a prerequisite for performing the operation. They are not authorization for the caller to request it.
Why This Happens in Real Systems
Confused deputy problems appear naturally in systems that delegate work.
Delegation is useful. A privileged service often needs broader permissions than individual users because it operates across many users' contexts. A file processing service needs to read many files. A cloud function needs to call many downstream APIs. A logging daemon needs write access to system directories.
The architecture isn't the problem. The problem is the security question that gets lost inside it.
When a service acts on behalf of a user, whose authority should govern what the service is allowed to do? The service's authority tells you what it is technically capable of. It says nothing about what this particular caller is entitled to cause.
If the service never asks the second question, its entire permission set becomes accessible to anyone who can send it a request.
The Same Pattern in Cloud Systems
This isn't a problem specific to operating systems or classic privileged programs. The same structure appears constantly in modern cloud architectures.
A user can call Service A. Service A has an IAM role that allows it to access storage buckets, query databases, invoke other services. The role exists because Service A legitimately needs those permissions to function.
If Service A accepts an arbitrary resource identifier from the user and blindly uses its IAM role to access whatever was requested, the user can reach anything Service A can reach:
User (limited permissions)
↓
Service A
↓
Service A's IAM role (broader permissions)
↓
Resource the user couldn't access directly
The IAM role isn't the problem. The role is doing exactly what IAM roles are supposed to do. The problem is that Service A treats its own IAM authority as authorization for any caller, rather than enforcing what each caller is actually entitled to request.
How This Differs From Similar Vulnerabilities
It's worth being precise here, because confused deputy gets conflated with a few other patterns.
SSRF is about influencing where a server makes a network request. The attacker's goal is often to reach internal infrastructure. A confused deputy is a different question: the attacker isn't just redirecting a request, they're causing a trusted component to apply its own authority on their behalf. There can be overlap in real systems, but the underlying mechanism is distinct.
IDOR is about accessing an object through a predictable identifier that isn't properly access-controlled. The resource is exposed directly. A confused deputy involves an intermediary that holds the authority, not a directly accessible resource.
Privilege escalation is a broad category. Confused deputy can lead to unauthorized access, but the mechanism isn't about exploiting a flaw to gain new permissions. The deputy already has the permissions. The problem is that it applies them without checking whether the caller deserves the result.
Defenses That Follow From the Mechanism
Because the core issue is authority confusion, the defenses are about making the authority distinction explicit.
Enforce authorization at the right boundary. The service must evaluate whether the caller is allowed to perform the requested operation, not just whether the service itself can perform it. These are different checks and both are required.
Carry caller context through delegation chains. When a service acts on behalf of a user, the user's identity and permissions need to be part of the authorization decision, not discarded at the service boundary. A request that passes through multiple layers should not lose track of whose request it originally was.
Constrain what callers can request. A service that can access a hundred resources doesn't need to expose all of them to every caller. Scope the operations each caller can invoke rather than exposing the service's full capability set.
Apply least privilege to the service itself. A service should only hold the permissions it actually needs. This doesn't eliminate confused deputy problems, but it limits what an attacker can access if the deputy does get confused.
None of these individually close every confused deputy scenario. The fundamental requirement is that authorization decisions account for the caller's authority, not just the deputy's.
The Core Insight
The intuitive assumption is that a trusted component is safe because it's trusted. Its permissions are legitimate. Its operations are intentional.
But trust in a component is not the same as trust in every request that component receives. A service can be completely legitimate and still be the mechanism through which unauthorized access happens. It doesn't need to be compromised. It just needs to fail at one question.
The most important mental model from this article:
What the deputy can do and what the caller can cause the deputy to do are two separate things. A confused deputy forgets the difference.
Top comments (0)