Identity and Privilege Abuse
Description
Agents inherit excessive credentials from their operators, cache authentication tokens in accessible memory, or escalate privileges across agent boundaries to access resources beyond their authorized scope.
Risk
Risk Overview
Agents typically execute with the credentials of the user or service account that launched them. This creates a privilege amplification problem: a human user who can access 10 systems now has an agent that can access those same 10 systems at machine speed, 24/7, without the cognitive friction that normally limits human misuse. Worse, agents may cache tokens, share credentials across sessions, or discover they can authenticate to services their operator did not intend them to reach.
Attack Surface
- Overprivileged service accounts: Agents run under broad service accounts with access far exceeding their task requirements
- Token caching and leakage: OAuth tokens, API keys, or session cookies stored in agent memory, conversation history, or log files where they can be extracted
- Cross-agent privilege escalation: Agent A delegates a task to Agent B, passing along Agent A's credentials, giving Agent B access it should not have
- Credential persistence: Tokens that outlive the agent session, remaining in memory or scratch files after the task completes
- Ambient authority: Agents inheriting all permissions from their hosting environment (cloud IAM roles, Kubernetes service accounts) without scoping
Business Impact
- Unauthorized data access: Agent accesses databases, file shares, or APIs beyond its task scope using inherited broad credentials
- Privilege escalation chains: Compromised low-privilege agent leverages cached tokens to reach high-value targets
- Audit trail gaps: Actions taken under shared service accounts cannot be attributed to specific agents or tasks
- Compliance violations: Violates principle of least privilege requirements in SOC 2, ISO 27001, and regulatory frameworks
Attack Scenarios
A code review agent runs under a CI/CD service account that has read/write access to all repositories, secrets management, and deployment pipelines. An attacker triggers a review on a malicious PR containing prompt injection. The hijacked agent uses its broad credentials to read secrets from the vault, clone private repositories, and push a backdoored commit to the main branch of an unrelated critical service.
An agent caches an OAuth bearer token in its conversation memory after authenticating to an internal API. A subsequent user session on the same agent instance extracts the cached token from the agent's context window and uses it to access the previous user's resources — a cross-tenant credential leak.
Agent A (customer support, low privilege) delegates a data lookup to Agent B (analytics, high privilege). Agent A passes its task context including a cached database connection string. Agent B stores this context for future reference. Later, Agent B uses Agent A's database credentials in combination with its own analytics permissions to access customer data that neither agent should reach independently.
Mitigations
Just-in-Time Credentials
Never pre-load agents with long-lived credentials:
- Issue short-lived, scoped tokens at the moment of each tool invocation
- Tokens should expire within minutes, not hours — ideally bound to a single API call
- Use a credential broker that mints tokens on demand based on the agent's current task and identity
- Revoke tokens immediately upon task completion or agent termination
Per-Action Authorization
Authorize each action individually rather than granting blanket access:
- Implement a policy decision point (PDP) that evaluates every tool call against the agent's current authorization context
- Authorization decisions should consider: agent identity, current task, target resource, action type, and time of day
- Deny by default — agents have zero access until explicitly granted for a specific operation
- Log all authorization decisions for audit
Credential Scoping
Limit credential scope to the minimum required:
- Use resource-specific credentials (one token per API, not one token for all APIs)
- Implement audience restrictions on tokens so they cannot be used against unintended services
- Apply IP binding or client-certificate binding to prevent token replay from unauthorized hosts
- Never include credentials in agent context windows, conversation history, or log output
Agent Identity Isolation
Prevent credential sharing across agent boundaries:
- Each agent instance must have a unique, non-transferable identity
- Delegation between agents must use the delegated agent's own credentials, not the delegating agent's
- Implement agent-to-agent authentication so receiving agents can verify the delegator's identity without receiving their credentials
- Clear all credential material from memory when agent sessions end
Audit Attribution
Ensure every action is attributable to a specific agent and task:
- Tag all API calls with agent ID, task ID, and correlation ID
- Use separate service accounts per agent role, never shared accounts
- Implement non-repudiation through signed action logs
Code Examples
Scoped Credential Provider
import time
import uuid
import hashlib
import secrets
from dataclasses import dataclass
from typing import Optional
@dataclass
class ScopedToken:
token: str
agent_id: str
task_id: str
resource: str
actions: list[str]
expires_at: float
fingerprint: str
@property
def is_expired(self) -> bool:
return time.time() > self.expires_at
class CredentialProvider:
"""Issues short-lived, scoped credentials for agent tool invocations."""
def __init__(self, ttl_seconds: int = 120):
self._ttl = ttl_seconds
self._active_tokens: dict[str, ScopedToken] = {}
self._revoked: set[str] = set()
def issue_token(
self,
agent_id: str,
task_id: str,
resource: str,
actions: list[str],
) -> ScopedToken:
"""Mint a short-lived token scoped to one resource and action set."""
token_value = secrets.token_urlsafe(32)
fingerprint = hashlib.sha256(
f"{agent_id}:{task_id}:{resource}:{time.time()}".encode()
).hexdigest()[:16]
token = ScopedToken(
token=token_value,
agent_id=agent_id,
task_id=task_id,
resource=resource,
actions=actions,
expires_at=time.time() + self._ttl,
fingerprint=fingerprint,
)
self._active_tokens[token_value] = token
return token
def validate_token(
self, token_value: str, resource: str, action: str
) -> dict:
"""Validate token is active, unexpired, and scoped for the request."""
if token_value in self._revoked:
return {"valid": False, "reason": "Token has been revoked"}
token = self._active_tokens.get(token_value)
if not token:
return {"valid": False, "reason": "Token not found"}
if token.is_expired:
self._cleanup_token(token_value)
return {"valid": False, "reason": "Token expired"}
if token.resource != resource:
return {"valid": False, "reason": f"Token not scoped for resource '{resource}'"}
if action not in token.actions:
return {"valid": False, "reason": f"Action '{action}' not permitted by token"}
return {"valid": True, "agent_id": token.agent_id, "task_id": token.task_id}
def revoke_all_for_task(self, task_id: str) -> int:
"""Revoke every token associated with a completed task."""
revoked_count = 0
for token_value, token in list(self._active_tokens.items()):
if token.task_id == task_id:
self._revoked.add(token_value)
del self._active_tokens[token_value]
revoked_count += 1
return revoked_count
def _cleanup_token(self, token_value: str):
self._active_tokens.pop(token_value, None)
Evidence Requirements
- Token issuance and validation logs with agent/task attribution
- Credential scope audit showing tokens matched to minimum required permissions
- Cross-agent delegation logs proving credential isolation
- Token lifecycle reports showing TTL compliance and revocation completeness
- Periodic access review confirming no stale or overprivileged service accounts