Blog// 14 MIN READ

26 Out of 26: Where an Agent’s Authority Actually Comes From

Five papers in three days and a 9.9 in the wild describe one gap: an agent's authority is resolved from a source nobody named. The four places it comes from.

EVIDENCE → INTERPRETATION → DECISION

Yesterday a 9.9 was published against Casdoor: a request carrying any application’s clientId and clientSecret received an unconditional global allow, skipping the policy engine and all organisation scoping. Any tenant’s own application credentials granted unrestricted user administration across every other organisation, including reading password salts.

Answer first: the control ran. It authenticated a real credential. It then resolved authority against the wrong subject, and returned the right answer to a question nobody had asked. That is a different failure from the ones I have written about this week, and it has a name worth using: authority provenance, the question of where an agent’s permission actually came from.

In the same week, five arXiv papers landed on how tool-using agents should be authorised. Each attacks a different fragment of that question. Laid end to end, they describe four distinct places where authority gets resolved, and yesterday’s CVE is a textbook instance of the first.

The 9.9 that landed yesterday

Casdoor is an identity and access management platform. A request that carries any application’s OAuth client identifier and secret is resolved to the subject app/<appname>. The central authorisation check then returns an unconditional global allow for any subject owned by app. The organisation scoping and the policy engine are skipped entirely on that path.

The newly added /api/mcp user-management tools read owner, id and other user fields directly from the request arguments with no organisation scoping applied. Put those two facts together and the consequence is exact.

  • A per-application credential, legitimately known to one application’s owner, becomes a key to every tenant.
  • An attacker can enumerate user records in any organisation, including password salts and email addresses.
  • They can create administrator accounts, modify existing users, and delete users in organisations they have no relationship with.
  • The researcher confirmed it against the built binary: an attacker’s application credentials read users, created an administrator, and deleted a user in a different organisation.

The classification is CWE-285, improper authorisation, with CWE-639, authorisation bypass through a user-controlled key. The second is the instructive one. The key here is not a database identifier. It is the identity the system decided the caller was, chosen by the caller.

One more detail is worth stating plainly, because it shows why the fix pattern fails. An earlier change had blocked an attacker naming owner=admin. This bypass does not need to. It names a different owner and takes the path that returns a global allow before ownership is compared at all.

Four places where an agent's authority is resolved: the credential presented at the boundary, a parameter supplied in the call, the grant provisioned at deployment, and the resource the agent acquired mid-task
The four resolution points. Only one of them is a check, which is why a control review finds none of them.

The second source: the call parameter

The same week produced the clearest measurement of this problem I have seen. The Stochastic Deputy formalises a pattern every multi-tenant tool uses: the tool accepts a tenant identifier and validates it against the caller’s entitlement. The paper’s point is that for an agent, this delegates resource selection to a process whose context may contain attacker-controlled instructions.

The experiment is what makes it land. Across a 373-trial ablation spanning eight model configurations and two transports, a correctly validated tenant parameter served every out-of-scope attempt: 26 of 26, or 26 of 41 plausible-pretext trials overall. With the parameter removed from the tool schema, no tool signature could express the attack.

Read that carefully, because the wording is the whole lesson. The validation worked. The parameter was checked exactly as designed. What failed is the assumption underneath it: that the process choosing the value is the process whose entitlement should decide. Validate a parameter all you like; if the entity supplying it is the one you are defending against, validation is a formality.

The fix is architectural rather than corrective: remove tenant identity from the tool schema, bind scope to a verified credential, and enforce it below the agent, where the model cannot reach it. That is a design change, and it is the reason this class survives patching.

The third source: the deployment grant

Most agents are provisioned the way employee laptops used to be, with a static credential set fixed at deployment that includes everything the role might ever need. Role-based access control accepted that compromise for humans because scoping access per task was infeasible.

For an agent, the compromise has a different shape. The credentials stand exposed whether or not the current task uses them, and a compromised or misaligned agent can reach for the ones the task never needed. The literature calls this the task-context mismatch, and the proposed remedy has three parts: role-based ceilings, a task permission classifier, and policy prohibitions. Ceilings alone are what most deployments have. Ceilings without a task classifier are the status quo, which is why the failure persists.

The fourth source: what the agent acquires mid-task

This one is easy to miss because it is not in the task specification at all. An autonomous agent can acquire compute, credentials, accounts, services, and other agents. Each acquisition introduces new authority into a task. Payment, budget and fulfilment checks validate the conditions of a transaction without ever deciding whether what came back may become usable authority.

The paper names it the post-fulfillment activation gap, and it spans tool-mediated creation, inter-agent delegation, and agentic commerce. The remedy is a runtime activation step: quarantine what was acquired, resolve its actual capabilities from authenticated provider evidence, and activate it only through a transaction that checks the resolved manifest.

The generalisable point: an agent that can acquire capability mid-run has authority at the end of the run that nobody granted at the start. Any authorisation model that only looks at the start is answering a question about a system that no longer exists.

The fifth, and the reason the first four fail

One paper addresses the condition that makes all of the above exploitable. Every input to an agent enters one shared planning channel with equal influence: the user’s request, tool results, retrieved documents, shell output, memory, and instructions from skills and protocol servers. The least-privilege capability an agent needs is dynamic and depends on task intent, which is exactly what makes static capability models wrong.

The paper’s framing is the sharpest sentence in the batch: a user’s explicit request and a document’s extracted text carry different trust and should not share authority to choose a destination or widen access. When they do, you get scope widening, adversarial through injection and accidental through ordinary context accumulation.

That is the root condition. The first four sources all fail in the same way: authority gets resolved against something the agent’s context could influence.

The model: authority provenance

Here is what I take from the batch, stated as a model you can apply this week.

For any consequential action an agent can take, four questions have to have answers, and the answers have to be written down somewhere a reviewer can find them. The first is the one that matters and the one nobody asks: whose permission is being exercised? Not which control permitted it. Whose authority is it.

Then: where was that authority resolved? Where is it enforced, relative to the model? And what is the blast radius if the resolution is wrong, one tenant or every tenant?

The four resolution points are the ones above. A credential presented at a boundary, a parameter supplied in a call, a grant provisioned at deployment, or a resource the agent acquired on its own initiative. Name which one applies to each action, and you have the audit.

The authority provenance audit: four questions per action covering the principal, the resolution source, the enforcement point and the blast radius, the fix that scales, and the three properties of traceable, bounded and contestable
Four questions per action, then three properties the deployment must satisfy.

The three properties, and which ones hold

The authorisation-architectures paper supplies the acceptance criteria, and they are better than anything I would have written. A trustworthy deployment requires that every consequential agent action be traceable to a human principal, bounded by what that human actually delegated, and contestable after the fact. The paper’s own assessment of documented deployments is that few satisfy all three reliably and end to end.

That matches what I can find evidence for. Traceability is usually present, because logging is cheap and auditors ask for it. Bounding is partially present, because role ceilings approximate it and rarely equal it. Contestability is the one that fails, and it fails because a log that records actions is not a record of decisions, and most platforms record actions.

I should be careful here about what I am claiming. I have not measured a population, and I am not going to pretend otherwise. The honest formulation is that the papers report this pattern, the Casdoor finding demonstrates the failure in one live system, and the measurement in the tenant-isolation work shows the mechanism holds at 26 of 26 under test. Anyone wanting a number for their own estate has to produce it, which is the point of the four questions.

Why the fix pattern keeps failing

Two structural reasons, both visible in yesterday’s CVE.

The first is that the fix goes to the endpoint rather than the model. Blocking owner=admin is a fix to one input value. The bypass did not need that value. Any defence expressed as a list of prohibited inputs is defeated by an input the author did not enumerate, and the enumeration is unbounded because the space is.

The second is that enforcement sits in the same layer as the thing being enforced. When the resource-selecting component is the one holding the tenant parameter, protection has to be somewhere the model cannot reach. Anywhere else, and you are relying on the model’s cooperation, which an injection removes.

Why a scanner will not find this

Worth stating because it changes how you look. There is no payload in this class. The credential is legitimate, the request is well formed, the parameter passes validation, and the response is a normal success. Every input-based detector sees a correctly authenticated caller doing something the endpoint permits.

What is wrong is the relationship between the caller and the resource, and that relationship does not exist in the request. It exists in the deployment: who was issued the credential, what the policy says about subjects of that class, and whether the endpoint that just ran was written before or after the scoping rule was. No amount of fuzzing reaches it, because the defect is an omission in a comparison that never happens.

The way to test it is the way you test an architecture: pick one low-privilege principal, enumerate every action it can take, and for each one ask whose authority funded it. Where the answer is a class, a parameter or an acquisition rather than that principal, you have the finding. The Casdoor case was found exactly this way, which is why the writeup includes negative controls proving the bypass came from the subject-class path rather than a generally open route.

Instrumenting the resolution, not the action

If the failure is that authority was resolved against the wrong source, then the log has to record the resolution. Most platforms record the action, which is why contestability is the property that fails.

Three fields close most of the gap, and none of them is expensive. Record the principal whose authority funded the action, which is not the same as the authenticated caller and is frequently the field nobody writes. Record the resolution source, drawn from the four above, as a value rather than a sentence in a description string. Record the enforcement point, meaning the layer that made the decision, so a reviewer can see whether it sat above the model or below it.

With those three present, the question “whose permission was this and where did it come from” is answerable from the record rather than from an interview with whoever wrote the code. Without them, an incident review reconstructs intent from action logs, which is the situation described in most of the agent-forensics work published this year.

There is a discipline cost worth naming. If the resolution source is recorded as a structured value, it has to be decided at the time the code is written rather than inferred later, and that decision is the audit. Teams that skip it are not saving effort; they are deferring it to the worst possible moment.

What does not follow

This is not an argument that agents cannot be deployed. Tenants are separated correctly in plenty of systems, and the four questions are answerable cheaply once someone asks them.

It is also not an argument that the papers describe solved problems. Four of them propose architectures that are specified rather than evaluated at scale, and the one with a real measurement reports a control serving 26 of 26 out-of-scope attempts, which is a result about how hard the problem is rather than how solved it is.

And it is not an argument that this is an AI problem. Multi-tenant confusion is old. What is new is that the component choosing the scope is now a language model reading untrusted text, which turns a design smell into a reachable attack with a plausible pretext.

Evidence to look for in your own stack

Source What to look for Why it matters
Boundary credential Any authorisation branch that returns allow for a subject class rather than an individual principal, and any endpoint added after the original policy was written That is the Casdoor shape: one rule granting a global allow for an entire class, plus a newer endpoint that inherited none of the scoping
Call parameter Tool schemas that accept a tenant, organisation, account or user identifier from the model A correctly validated parameter still served 26 of 26 out-of-scope attempts when the model chose the value
Deployment grant Credentials present in the runtime that the current task does not use Every unused credential is authority the task never needed and an attack can reach for
Mid-task acquisition Any path where the agent can create an account, mint a token, provision compute or delegate to another agent Authority acquired during a run was never granted by a human, so no deployment-time check covers it

The cheapest version of this is one question asked per action, in writing: whose permission is this, and where was it resolved? Where the answer is a class rather than a principal, or a parameter rather than a credential, you have found the finding before anyone has exploited it.

Frequently asked questions

What is authority provenance?

It is the question of where an agent’s permission for a specific action actually came from. A conventional control review asks whether an action was permitted. Authority provenance asks whose authority was exercised, where that authority was resolved, where it is enforced relative to the model, and how far the damage reaches if the resolution is wrong. The distinction matters because a correctly enforced check on the wrong subject returns a correct answer to a question nobody asked.

How is this different from the OAuth session-issuance gap I wrote about earlier?

That case was two paths in one component where a second issuance route skipped checks the first one ran, so the problem was coverage: a control existed and was bypassed on a path its author forgot. Here the control runs, authenticates a real credential, and resolves authority against a source that is not the principal. The failure is semantic rather than procedural, which is why adding the check to the missing path fixed that one and would not fix this one.

Is the Casdoor finding an AI vulnerability?

Not in the model sense, and it is worth being precise. Casdoor is an identity platform, and the affected surface is an MCP user-management endpoint, which is the AI-facing part. The reason it belongs in this discussion is that it is a live, high-severity instance of the exact pattern the agent-authorisation research is measuring: authority resolved from a credential’s class, a caller-supplied value, or a grant that the task did not scope.

Why does validating a tenant identifier not fix this?

Because validation checks that the value is well formed and consistent with the caller’s entitlement, and in the measured case it did that correctly. What it cannot check is whether the entity choosing the value should have been choosing it. When the chooser is a language model whose context includes untrusted text, the value can be brought into scope by a document. The durable fix removes the parameter from the schema and binds scope to a credential resolved below the agent.

What should be fixed first?

The branches that return allow for a class rather than a principal, because they are the widest and the cheapest to find. In the live case, one such branch converted a single application’s credentials into administrative access across every tenant. After that, any tool schema that accepts an identity or scope parameter from the model, and then any credential in the runtime that the current task does not use.

Does this apply to single-tenant deployments?

Less severely. The tenant parameter and the acquired-authority problems still apply, because they concern which principal’s authority is exercised rather than which tenant it belongs to. The boundary-credential problem is the one that depends on shared infrastructure, which is why it produces the highest severity and why anyone running a multi-tenant platform should start there.

The four questions

If you take one thing from this: for every consequential action your agent can take, write down whose permission it is and where that permission was resolved. Do that before the next control review, because a review will confirm every check is correctly written and will tell you nothing about four of the five answers.

Classes I have covered that sit alongside this one: the agent that disabled its own sandbox, the three ways MCP and agent tooling fail, and the second session-issuance path that skipped the checks.

Primary sources

One next action

If you run an agent that executes tools, AgentCrash is an open-source harness that crash-tests it in a synthetic workplace: synthetic tools, visual evidence and regression tests. It is built for exactly this problem, turning a containment claim into something you can run against the system instead of arguing about it in review.