Attenuation, Not Approval

· Communications of the ACM ·

10 min read Original article ↗

Mobile permissions used to mean “This app can do anything on your phone, forever, once you tap allow.” It took the better part of a decade to get from there to “This app can see your location, once, for the next five minutes, and we’ll ask again after that.” That shift didn’t happen because someone had a nicer idea one morning; it happened because broad, standing grants of authority kept getting abused in ways nobody predicted at grant time, until the industry accepted that the safer default is authority that’s scoped tight and has to be re-earned, not handed out once and trusted forever.

AI agents are mostly still living in the era before that shift. And it’s not the first grant of authority that worries me; it’s what happens to it after it’s been handed off three more times.

Nobody’s Pricing in the Handoff

Take a fairly ordinary agentic setup. A support engineer asks an orchestrating agent to look into a billing dispute. Rather than doing everything itself, the orchestrating agent delegates the actual database lookup to a narrower sub-agent whose entire job is retrieving billing records. That sub-agent might delegate again, to something that formats a response or checks a policy document.

Ask what token that first sub-agent is actually holding. In most systems I’ve looked at, it’s some version of the same credential the orchestrating agent had and copied over because that was the path of least resistance when someone wired up the integration. The sub-agent, whose whole job is reading billing records for one customer, is frequently sitting on authority that could do a lot more than that, because nothing forced it to shrink on the way down.

This is easy to miss if you’re thinking about agent security mainly as a prompt injection problem. Prompt injection is about tricking an agent into doing something it wasn’t supposed to do. This is different; it’s an agent doing exactly what it was told, faithfully, correctly, with more authority than the task required, because nothing enforced otherwise.

Why Bearer Tokens Became the Water We Swim In

It’s worth being clear about why this keeps happening, because it isn’t laziness; it’s inheritance. Almost every agent framework built today sits on top of OAuth 2.0,3 and the standard credential OAuth hands out is a bearer token:4 a string that says, in effect, “whoever holds this gets whatever it authorizes.” No signature tied to a specific holder, no built-in way to narrow it further downstream. If you have the string, you have the access. That’s exactly why it spread everywhere; it’s simple, it’s fast, and it works great for the case it was designed for: a single client talking to a single API.

The trouble starts when that same bearer token gets forwarded, wholesale, from an orchestrating agent to a sub-agent, then to whatever that sub-agent calls next. Nothing in the bearer model has an opinion about that. The token doesn’t know it’s being handed to something narrower in scope than the thing that first requested it. It just keeps working, everywhere it’s presented, until someone revokes it entirely, which is usually a much blunter action than anyone wants to take mid-task.

‘Approved’ Was Never the Right Word

A lot of current thinking about agent permissions borrows the language of approval: a human approves an agent’s access, the agent is now approved, done. Approval is a yes-or-no gate at a single point in time. It says nothing about what happens to that ‘yes’ as it gets copied, forwarded, and reused three delegation hops downstream from whoever actually said it.

What the field needs is a less-forgiving word. Attenuation means authority is only allowed to shrink as it moves from hand to hand, never staying flat, never expanding. The orchestrating agent gets read and write access to a ticketing system. When it hands work to a sub-agent, that sub-agent doesn’t get a copy of the same authority; it gets whatever narrower slice the specific task requires, locked to that slice, with its own expiry, so it physically can’t be used for anything broader even if the sub-agent is compromised or just given a bad instruction.

Figure 1. shows the same idea side by side, bearer delegation on the left, attenuated delegation on the right:

Figure 1. Attenuation
Figure 1. Bearer delegation copies full authority down every hop. Attenuated delegation narrows it at each hop, so a sub-agent physically cannot exceed its task.

How Attenuation Actually Works

None of this is new in the abstract, and it’s worth knowing where it came from, because the lineage is older and more boring, in the good sense, than most AI security ideas. Back in 2014, a team at Google published a paper called Macaroons,1 describing a credential that looks like a bearer token but has caveats baked into it: little restrictions, chained together with cryptographic hashing, so that anyone holding the macaroon can add a caveat that narrows what it’s good for, but nobody downstream can strip a caveat back off. Once you’ve restricted a macaroon to “read-only, this one customer,” that restriction travels with it forever. It’s not a policy note sitting next to the token, it’s part of the token.

Biscuit,2 the token format I keep coming back to for agent delegation specifically, takes the same core idea and updates it: caveats get written as small logic statements (a datalog-style rule set) rather than opaque hashes, so a gateway checking the token can actually reason about what it allows, and every hop can append new restrictions offline, without a round trip back to whoever issued the original token. For an agent pipeline where a task might fan out across several sub-agents in a few hundred milliseconds, that offline part matters. Nobody’s waiting on a central server to bless every narrowing step.

The practical upshot: a sub-agent’s token isn’t a copy with a note attached saying “please only use this for billing lookups.” It’s a cryptographic object that is only capable of authorizing a billing lookup, for one customer, for five minutes, full stop.

 Bearer token (typical today)Attenuated token (Biscuit-style)
Scope across hopsSame scope, copied forwardNarrows at every hop, never widens
Verifying a requestTrusts whatever the token says it can doGateway checks the token’s actual caveats
Compromised sub-agentCan use full inherited authorityLimited to its own narrowed slice, nothing more
RevocationUsually all-or-nothing for that tokenCan expire or restrict at the specific hop
Needs a call home to verifySometimes, depending on setupNo, verifiable offline

What This Looks Like End to End

Back to the billing dispute. Here’s the same flow with the actual scopes attached at each hop:

Figure 2. Attenuation
Figure 2. The billing-dispute example end to end. A write request or the wrong customer ID gets rejected at the gateway, not because a rule happened to catch it, but because the token cannot authorize it.

The support engineer’s identity provider issues a token to the orchestrating agent scoped to ticketing, read and write. That agent, needing a billing lookup it isn’t itself built to do, mints an attenuated token for the sub-agent: billing, read-only, one customer ID, five-minute expiry. The sub-agent calls the billing system through a gateway, and the gateway checks the token’s actual caveats against the request before forwarding anything.

If everything lines up, read-only, right customer, still within the five minutes, the call goes through. If the sub-agent somehow tries to write instead of read, or reaches for a different customer’s records because of a bad instruction or a compromise, the gateway rejects it right there, because the token is not cryptographically capable of authorizing that request, not because a policy engine happened to catch it that time.

What You Actually Get for It

The clearest way to see the payoff is to look at what happens when something goes wrong. Say the billing-lookup sub-agent gets a malformed instruction, or is compromised somehow, and reaches for something outside its lane, a write instead of a read, a different customer’s record than the one it was scoped to.

With a bearer token, that request might just go through, because the underlying credential had broader authority than the task implied and nothing checked. With attenuated delegation, that request hits a wall at the gateway, exactly as sketched above. The failure turns into a rejected call instead of a quiet compromise, and because it happened at a chokepoint the agent had to pass through anyway, you get a record of the attempt without having built any special monitoring for it.

That last bit matters more than it sounds. A rejected call that gets logged is a security team’s favorite kind of evidence. A silent success that never should have happened is the thing nobody can explain eight months later when it shows up in a breach report.

A Question Worth Sitting With

If you’re running more than one agent right now, and they hand tasks to each other, here’s the thing to check: when task A goes to sub-agent B, does B’s authority actually shrink to fit what B needs, or is B just holding a copy of whatever A had because that was easier to wire up?

For most teams I’ve talked to, it’s the second one. That’s not a failure of judgment, it’s what happens when you’re moving fast and the tooling to do it properly isn’t the default yet. But “The sub-agent could have done more than it was supposed to, and it didn’t, this time” isn’t a security posture; it’s a streak, and streaks end.

Mobile took most of a decade to tighten its permission model, and that was with a relatively small, relatively slow-moving set of app developers to bring along. Agent delegation chains are being built faster than that, with more hops, and a lot less friction between handing out a task and handing out the authority to do it. Getting to attenuation on purpose beats backing into it after the first incident writes the case study for us.

Disclosure: This post was drafted with the assistance of an AI writing tool. The author provided the technical direction, argument, examples, and domain expertise, and reviewed, edited, and takes full responsibility for the final content. Figures 1 and 2 are original diagrams generated programmatically in Python (Matplotlib) based on the author’s specifications of the token delegation architecture and the worked example flow.

References

1. Birgisson, A., Politz, J. G., Erlingsson, Ú., Taly, A., Vrable, M., and Lentczner, M. Macaroons: Cookies with Contextual Caveats for Decentralized Authorization in the Cloud. Network and Distributed System Security Symposium (NDSS) (2014).

2. Eclipse Biscuit Project. Biscuit authorization token specification. biscuitsec.org

3. Hardt, D. (Ed.). The OAuth 2.0 Authorization Framework. IETF RFC 6749 (2012).

4. Jones, M. and Hardt, D. The OAuth 2.0 Authorization Framework: Bearer Token Usage. IETF RFC 6750 (2012).

Bhaskar Rajbongshi

Bhaskar Rajbongshi is a platform security engineer who spent years building trust boundaries for consumer devices before turning that lens on AI-assisted development. He writes about where the old assumptions in application security quietly stop holding.

Submit an Article to CACM

CACM welcomes unsolicited submissions on topics of relevance and value to the computing community.

You Just Read

Attenuation, Not Approval

© 2026 Copyright held by the owner/author(s).