A support user asks an agent to find the last failed job for customer A. The agent calls the job service with its platform system token and searches by a caller-supplied ID. The service credential is valid and may read every tenant, so the response returns customer B's job. Authentication succeeded at every hop; the user's boundary disappeared between planning and execution.
The system token identifies the executor. It does not describe the person who initiated the task or the authority delegated for this run. Background workers and workflow engines have long faced the same separation, but agents amplify it by turning one instruction into several tool calls across search, files, jobs, and data stores.
Both identities belong in the design. An authority envelope should bind the initiating principal, tenant, delegated scopes, purpose, target constraints, approval state, and expiry to the run, while the system credential supplies only the technical means to execute. Downstream policy and audit need to see actor and executor as different fields all the way to the protected effect.
Key Takeaways
- A service token authenticates the agent runtime; it does not authorize the initiating user to exercise every service capability.
- Caller identity, tenant, delegated scope, target ownership, purpose, and expiration must survive every asynchronous and tool boundary.
- Authorization belongs at the protected effect, not only at the chat endpoint, planner, or tool-selection layer.
- Agent logs need both the initiating actor and the effective execution identity; recording only the system account destroys accountability.
- Multi-principal negative tests should compare what two users can cause the agent to read, change, delete, or launch, including other users' jobs.
- Safe autonomy requires least-privilege tool credentials, resource-bound delegation, explicit approval for authority expansion, and replayable authorization tests.
Two Identities Exist in Every Delegated Operation
When an agent acts for a user, at least two identities are involved:
- Initiating principal: The person, workload, or organization that requested the operation.
- Executing principal: The service, agent runtime, worker, or connector that technically performs it.
Sometimes there are more. A model provider may call a gateway, which invokes an agent service, which calls a connector, which uses a database role. Treating any one of these as "the user" collapses distinct trust decisions.
The executing principal answers, "Which software component is making this request?" The initiating principal answers, "Whose authority is being exercised?" Authorization often needs both. A data service might allow the agent runtime to call its API only when the request carries a valid, non-forgeable delegation for the relevant user and resource.
A Useful Authority Tuple
Represent the decision as structured context rather than an ambient token:
Authority = {
actor_id,
actor_type,
organization_id,
tenant_id,
executor_id,
delegated_actions,
resource_constraints,
purpose,
approval_id,
issued_at,
expires_at,
trace_id
}
Not every system needs these exact fields. The important property is that security-relevant dimensions are explicit and immutable. A tool handler should not have to infer tenant from a free-form prompt, select a user from request parameters, or assume that possession of a system credential grants caller authority.
How Principal Context Disappears
The dangerous pattern often begins with reasonable engineering choices. A downstream API accepts only service authentication. A background worker cannot reuse a browser session. An agent needs to continue after the initiating request ends. Developers therefore replace the user's token with a system token and move on.
The replacement solves authentication continuity but discards authorization context. Common loss points include:
| Boundary | Convenience shortcut | Security consequence | Required correction |
|---|---|---|---|
| Chat/API to planner | Store only prompt and run ID | Run is detached from caller and tenant | Persist immutable authority envelope with run |
| Planner to tool | Pass tool name and arguments only | Tool cannot authorize the initiator | Include signed or server-derived delegation context |
| API to queue | Serialize business payload without identity | Worker runs with ambient service power | Bind queue message to actor, scope, resource, and expiry |
| Worker to search/data API | Substitute a system token | Low-privilege caller gains service-level data reach | Use constrained delegation or server-side policy filter |
| Run history | Query by caller-controlled run ID | Cross-user jobs become readable or mutable | Authorize owner and tenant at object lookup |
| Retry/resume | Recreate context from current defaults | Old task gains newer or broader permissions | Replay original authority or require reauthorization |
| Audit logging | Record only service account | Initiator disappears from evidence | Log actor and executor separately |
The defect is rarely "the token was invalid." It is that a valid token represented the wrong security subject for the decision being made.
Ambient Authority Is the Root Problem
Ambient authority exists when code can exercise privileges simply because they are available in its environment. A global administrator token in an agent process is ambient authority. Any tool, plugin, error path, or injected instruction that reaches the client can use it unless every call applies a separate policy.
Capability design reverses that model. A tool receives only the authority needed for one operation, on one resource set, for one purpose, for a short period. If an agent is asked to summarize the initiating user's reports, it should not receive a token capable of deleting arbitrary users' search jobs. The restriction should be enforced downstream, not trusted to the model's prompt.
Authentication, Delegation, and Authorization Are Different Controls
These terms are often blended in agent architecture, which makes design reviews imprecise.
Authentication Identifies a Party
Authentication proves that the caller controls a credential associated with an identity. A system token can strongly authenticate the agent service. It says nothing by itself about which end user caused the request or which resources that user may access.
Delegation Constrains Acting on Behalf of Another Party
Delegation communicates that one principal may perform specific actions for another principal. Good delegation is explicit, audience-bound, time-limited, and narrower than the delegator's full authority. It should identify the actor and, where useful, distinguish the party that requested the delegation from the party executing it.
Delegation does not require sending an end-user bearer token through every service. An authorization service can issue a short-lived, audience-specific token exchange result. A backend can also enforce server-side filters from a signed context. What matters is that the downstream decision receives trustworthy caller constraints.
Authorization Decides the Protected Effect
Authorization determines whether the represented principal may perform an action on a resource in the current context. It must occur near the protected effect because conditions can change between planning and execution. Ownership may change, a session may be revoked, a run may expire, or a resource may move to another tenant.
The planner can avoid proposing forbidden tools, but that is usability guidance, not the final security boundary. Tool discovery can hide unavailable functions, but a direct invocation must still be denied. The tool server and resource service must enforce the decision independently of the model.
Design an Authority Envelope That Survives the Run
A robust agent run begins with a server-derived security context. The model may receive a readable summary of that context, but it must not be able to modify the authoritative object.
Bind the Run at Creation
When the run is created:
- Resolve the authenticated principal from the trusted session.
- Resolve organization and tenant from server-side membership, not request text.
- Calculate eligible actions from current policy.
- Bind requested resources by stable identifiers and ownership.
- Record whether the run is interactive or unattended.
- Set a maximum lifetime and approval requirements.
- Create an immutable run identity and audit trace.
Do not let a user submit actor_id, tenant_id, or effective roles as ordinary request fields. If an administrative feature supports acting on behalf of another user, model that as a separate privileged operation with explicit reason, approval, visibility, and audit.
Propagate Context Through Queues and Retries
Asynchronous execution is where context often degrades. A queue message should carry either a signed authority envelope or a reference to authoritative server-side state. The worker must validate issuer, audience, integrity, expiration, run state, and revocation before use.
Retries should not silently refresh authority. If the original delegation expires, the task should pause or request reauthorization. A long-running agent must not gain new privileges because the user's role changed after the task was queued. Likewise, revocation should have a defined effect: immediate cancellation for sensitive operations, or revalidation before each protected step.
Narrow Each Tool Invocation
The run-level envelope may still be broader than one tool needs. Each invocation can derive a narrower child capability:
run authority
-> tool eligibility check
-> target resource resolution
-> action-specific capability
-> downstream authorization
-> protected effect
The child capability should bind tool, action, resource, audience, and short expiration. If the tool tries to change arguments after approval, access another resource, or call a different service, the capability should fail.
Preserve Context in Stored Objects
Agent runs create histories, plans, outputs, temporary files, search jobs, and connector sessions. Each object needs ownership and tenant attributes. A random identifier is not an authorization policy. Object lookup should query by both object ID and authorized scope, or retrieve the object and perform a non-bypassable policy decision before returning or mutating it.
Deletion deserves special attention. Systems sometimes authorize a parent object after deleting a child record. The check must happen before the effect, and it must bind the same target that will be changed.
Separate Control Plane from Data Plane
Agent platforms benefit from a clear split:
- Control plane: Creates runs, evaluates policy, issues delegation, records approval, registers tools, and manages lifecycle.
- Data plane: Executes tool calls, reads resources, performs searches, changes state, and returns evidence.
The control plane decides which operations are eligible. The data plane still verifies the supplied authority at each effect. A compromised or confused planner should not be able to bypass the resource service simply by naming a tool.
Service Tokens Should Be Audience-Specific
One all-powerful token reused across connectors creates a broad compromise path. Distinct workload identities and audiences reduce that coupling: a search connector token has no reason to call the file service, a file tool does not need agent-configuration authority, and a reporting worker does not need to delete runs. Delegation works best when the executor's technical permissions are no broader than the feature requires.
Policy Filters Must Be Non-Optional
For data queries, the safest design often injects an authorization predicate server-side. The agent can choose search terms but cannot remove the tenant and ownership filter. For object operations, the service resolves the resource under the caller's authorized scope. For administrative tools, explicit approval can authorize a narrow elevation with a visible reason and expiry.
Do not rely on prompt language such as "only access the current user's data." Prompt instructions help the model behave, but an attacker can manipulate inputs and models can make mistakes. Security policy must be deterministic code outside the model.
Audit the Actor, Executor, Decision, and Effect
Agent observability often focuses on prompts, model outputs, token use, and latency. Security investigations need a different set of facts.
Each protected operation should record:
- Initiating actor and authenticated session.
- Organization and tenant.
- Agent run and parent task.
- Executing workload identity.
- Tool name and version.
- Requested action and normalized resource identifiers.
- Delegated scopes and policy version.
- Approval or consent reference.
- Authorization decision and reason code.
- Effective downstream credential audience.
- Result classification and protected effect.
- Trace links across queue, tool, and data service.
Sensitive arguments and outputs may require redaction or hashing, but redaction should not erase the resource or decision needed for accountability. Logs should be integrity-protected and unavailable for ordinary agent mutation.
Avoid the "System Did It" Audit Trail
If every event names only an agent service account, incident responders cannot determine which user initiated the operation. If every event names only the user, operators cannot tell which connector or worker exercised the authority. Recording both also improves user-facing transparency around automated actions and elevation.
Test Authorization by Comparing Principals and Effects
Single-user happy-path testing will not detect principal replacement. The test needs at least two distinct users and protected resources.
Build a Synthetic Identity Matrix
Deterministic fixtures can represent:
- User A and User B in the same tenant.
- User C in another tenant.
- A low-privilege role and an administrative role.
- Private resources owned by each user.
- Shared resources with explicit grants.
- Runs and jobs created by each principal.
- Revoked, expired, and suspended identities.
Then test reads, updates, deletion, execution, listing, history access, retry, cancellation, export, and connector actions.
| Scenario | Expected result | Evidence required |
|---|---|---|
| User A asks agent to read A's private resource | Allowed | Actor A, executor, resource A, policy allow |
| User A references B's private resource ID | Denied | No data returned and no downstream protected effect |
| User A guesses B's run or job ID | Denied | Object ownership enforced at lookup |
| User A requests a shared resource | Allowed only within granted action | Effective scope matches explicit grant |
| User A changes tenant in tool arguments | Denied | Server-derived tenant remains authoritative |
| User A's run retries after revocation | Denied or reauthorized | Original authority is not silently refreshed |
| Admin approves one elevated action | Only approved resource/action allowed | Approval ID, expiry, and exact effect recorded |
| Direct tool call bypasses chat | Same decision as chat path | Tool server independently enforces policy |
The oracle is not whether the agent refused in natural language. A model can say no while a tool already executed, or say yes while the backend denied it. The protected resource, downstream audit event, and effective identity reveal what actually happened.
Test Context Collisions and Concurrency
Agents run in parallel, so shared caches, deduplicated calls, connection pools, result stores, and retry queues need every security-relevant identity dimension in their keys. Run A's result must never satisfy Run B merely because tool arguments look similar. Coordinated overlap can show whether outputs, callbacks, and audit records remain bound to the correct principal.
Test Failure and Resume Paths
Authorization drift often appears in recovery logic:
- A tool times out and a worker retries under a default system identity.
- A connector refreshes a token without retaining user scope.
- A run is resumed from history by another user.
- An administrator transfers ownership but old child objects keep access.
- A partial failure stores output in a globally readable location.
These states deserve direct testing because reliable security behavior has to survive exceptions, not only successful orchestration.
What Autonomous Pentesting Should Prove
Agent authorization is a stateful, multi-principal problem. A useful security test needs to understand code paths and then exercise the application as different actors. Broad endpoint scanning will not show that a handler replaced caller context with a system credential unless it observes the downstream effect.
A code-aware autonomous workflow can:
- Identify where user context is created and where a system token is introduced.
- Trace run IDs, tenant IDs, and resource IDs into tool and data-service calls.
- Generate a principal-resource-action matrix from roles and ownership.
- Execute paired tests with synthetic users in an isolated target.
- Verify data access, job visibility, state changes, and audit attribution.
- Preserve a minimal, replayable proof for the vulnerable boundary.
- Re-run the proof when authentication, queue, tool, or connector code changes.
SecureHup fits this problem through its multi-persona auth testing, code-aware analysis, and verified exploit evidence. The practical benefit is not asking an AI model whether a flow looks secure. It is proving that a low-privilege principal cannot cause a protected effect through the agent's more powerful execution identity, then replaying that exact boundary test as the application changes.
A Remediation Blueprint
For an agent that currently relies on broad system authority, the transition can follow this sequence.
1. Inventory Identity Transitions
A hop-by-hop map from browser session to API, run, queue, worker, tool, and resource service shows which identity and tenant attributes survive. A blank cell is a likely authorization gap.
2. Define Protected Effects
Operations that read sensitive data, change state, start workloads, manage jobs, access other users' history, export content, or alter permissions need an owning service for the authorization decision.
3. Replace Ambient Tokens
Audience-specific workload identities, constrained delegation, and server-side policy context can replace global credentials in tools that do not need them.
4. Bind Stored State
Runs and artifacts need immutable owner, tenant, creator, and authority metadata. Older records require care because an unknown owner should not default to globally accessible.
5. Enforce at the Effect
The service that owns the data or operation is the natural enforcement point. Planner restrictions and UI filtering remain useful additional controls rather than final authorization.
6. Add Multi-Principal Regression
Every confirmed cross-user or cross-tenant path can become a test covering direct calls, retries, resumption, expired authority, and concurrent runs.
7. Improve Audit and User Visibility
Separate actor and executor fields, user-visible automated actions, and alerts for system-token operations without a valid authority envelope make delegation observable.
FAQ
Why can an agent not simply use the user's access token?
Passing the original bearer token through every component increases token exposure, may violate audience boundaries, and often fails for long-running tasks. The safer solution is constrained delegation: exchange or derive a short-lived credential for the exact downstream service, action, resource, and duration. Alternatively, pass integrity-protected caller context and let the resource service enforce policy. The goal is to preserve authority without spreading a reusable user credential.
Is a system token always dangerous in an AI agent?
No. Agent runtimes need workload identities for service-to-service authentication. The danger appears when the system token becomes the sole authorization context or carries unnecessary power. Narrow service permissions, initiating-principal delegation, and records of both identities keep those roles separate.
Where should authorization occur in an agent workflow?
Authorization should occur at every meaningful trust transition, with the final decision at the service that performs the protected effect. The API should authorize run creation, the control plane should restrict tool eligibility, the tool server should validate delegation, and the resource owner should authorize the exact read or mutation. Earlier checks improve safety and usability but do not replace downstream enforcement.
How do we prevent cross-user access to agent run history?
Each run, job, output, and temporary artifact should carry an immutable owner and tenant. Object resolution within that authorized scope is stronger than a lookup by caller-supplied ID alone, and the same relationship applies to list, read, update, delete, resume, export, and retry. A two-user test can observe the downstream effect rather than only the API response.
Can prompt instructions enforce least privilege?
No. Prompts can guide model behavior but are not a security boundary. They can be misunderstood, overridden by untrusted content, or bypassed through direct tool invocation. Least privilege requires deterministic credentials, policy checks, resource constraints, sandboxing, approvals, and audit controls outside the model.
Actor and Executor Belong in the Same Authorization Story
A delegated operation is easier to reason about when the initiating person and the service performing the work remain distinct but connected identities. The run carries the principal, tenant, purpose, and limits; the system credential identifies the component allowed to operate the machinery. Queues, retries, callbacks, and stored jobs should not turn that relationship into anonymous platform authority.
In our view, a two-user test is the clearest first proof. If a valid system token can complete work for the intended user but cannot cross into a resource that user does not control, the architecture is preserving delegation rather than substituting for it. Audit records should tell the same story by showing who requested the effect, what executed it, and why the policy allowed it.
#AISecurity #AgentSecurity #IdentitySecurity #Authorization #LeastPrivilege #AutonomousPentesting
Find issues like this in your own codebase
SecureHup runs this exact exploit chain — discovery, enumeration and cross-tenant validation — on every deployment, automatically.