cloud-audit
English | ็ฎไฝไธญๆ
What can a hijacked AI agent reach in your AWS account, and can you prove it?
Open-source, read-only AWS security scanner. 110 checks, 64 IAM privilege-escalation methods, 31 attack-chain
rules, blast radius for any resource, and agent-blast for Bedrock Agents and AgentCore:
what a prompt-injected or credential-stolen agent can reach, with the IAM policy simulator as the witness.
Every finding ships an AWS CLI + Terraform fix. Nothing is written to your account.
30-second demo -
agent-blast -
Full scan -
What's inside -
Proof Mode -
Installation -
Documentation
Thirty seconds, no AWS account needed
pip install cloud-audit
cloud-audit agent-blast --demo
cloud-audit demo --save demo.json
cloud-audit blast-radius --report demo.json --resource arn:aws:iam::123456789012:role/support-bot-ticket-role
cloud-audit simulate --report demo.json --fix aws-iam-018
cloud-audit exposure --report demo.json
The sample account is invented. Everything derived from it (attack chains, root causes, breach cost,
security graph, agent reach) is produced by the same engines a real scan uses.
With credentials, the real thing is one command and read-only. The AWS-managed SecurityAudit
policy covers every check (permissions):
cloud-audit scan
cloud-audit scan --verify
cloud-audit agent-blast --verify
agent-blast: what a hijacked AI agent can reach
An AI agent in AWS is a bundle of IAM identities: the role the agent runs as, the execution roles of
the Lambda functions behind its tools, the roles of its knowledge bases, gateways and sandboxes.
When the agent is hijacked, the attacker acts with those identities. agent-blast answers what
that means, per agent, under two threat models:
| Threat model | What the attacker has | What is in reach |
|---|
| Identity takeover | the credentials of a role the agent runs as (sandbox escape, metadata-service read, leaked session) | the full role: privilege-escalation methods, AssumeRole hops, data |
| Behaviour takeover | nothing but a prompt (indirect prompt injection through a document, a ticket, a web page) | what the agent's tools can do, bounded by the tools' own execution roles |
Real output for the sample agent (cloud-audit agent-blast --demo -a support-bot):
support-bot (bedrock_agent, eu-central-1)
โโโ A hijacked tool (tool: create-ticket) can escalate to account admin via PassRole+Lambda
โโโ status: PREPARED
โโโ Identity takeover (attacker holds the role's credentials)
โ โโโ support-bot-agent-role arn:aws:iam::123456789012:role/support-bot-agent-role
โ โโโ no escalation path; 3 reach(es) from policy grants, 1 on named resources (see Reach)
โ (risk 0/100, 1 nodes)
โโโ Behaviour takeover (prompt injection: the agent's tools, their roles)
โ โโโ search-docs action_group_lambda -> support-bot-search-role
โ โ โโโ 3 OpenAPI path(s) in apiSchema; state ENABLED
โ โ โโโ no escalation path; 4 reach(es) from policy grants, 4 on named resources (see Reach)
โ โโโ create-ticket action_group_lambda -> support-bot-ticket-role
โ โ โโโ 2 function(s) in functionSchema; state ENABLED
โ โ โโโ reaches Account Takeover in 1 hop(s) via PassRole+Lambda (risk 72/100)
โ โ โโโ escalation: PassRole+Lambda
โ โโโ product-docs knowledge_base -> support-bot-kb-role
โ โโโ 1 S3 data source(s)
โ โโโ no escalation path; 2 reach(es) from policy grants, 2 on named resources (see Reach)
โโโ Reach (13 action/resource pairs)
โ โโโ tool: search-docs secretsmanager:GetSecretValue on
โ โ arn:aws:secretsmanager:eu-central-1:123456789012:secret:prod/db-credentials-Ab12Cd
โ โ unverified read secret values
โ โโโ tool: create-ticket sts:AssumeRole on arn:aws:iam::123456789012:role/ops-admin unverified
โ โ assume IAM roles
โ โโโ tool: create-ticket lambda:InvokeFunction on * unverified invoke Lambda functions
โ โโโ tool: search-docs s3:PutObject on arn:aws:s3:::company-backups-2024/* unverified write S3
โ โ objects
โ โโโ support-bot-agent-role s3:GetObject on arn:aws:s3:::kb-product-docs/* unverified read the
โ โ agent's knowledge base
โ โโโ tool: search-docs s3:GetObject on arn:aws:s3:::company-backups-2024/* unverified read S3
โ โ objects
โ ...
โโโ Tags
โ โโโ OWASP Agentic: ASI02 Tool Misuse and Exploitation, ASI03 Identity and Privilege Abuse,
โ โ ASI05 Unexpected Code Execution
โ โโโ MITRE ATLAS: AML.T0034 Cost Harvesting, AML.T0040 AI Model Inference API Access, AML.T0053
โ AI Agent Tool Invocation, AML.T0086 Exfiltration via AI Agent Tool Invocation
โโโ Simulated, not executed: identity policies, the attached permissions boundary and SCPs are
evaluated by the IAM policy simulator; resource-based policies of the targets, RCPs and VPC
endpoint policies are not. Tool reach is an upper bound set by the tool's role; what the tool
code does with its inputs is narrower.
The story the output tells: the support bot itself is harmless, but a document that tricks it into
calling create-ticket runs code under a role that can pass an admin role to a new Lambda. The
search-docs tool, meant to read product docs, can also read the production database secret and
write into the backups bucket. Every line names the identity, the action and the resource, so the
fix is a policy statement, not a debate.
The same engine covers AgentCore. For the sample gateway (--demo -a tools-gw) the headline is a
cross-agent one:
tools-gw (agentcore_gateway, eu-central-1)
โโโ tool: crm-sync can write into agent 'support-bot' knowledge base (RAG poisoning): arn:aws:s3:::kb-product-docs/*
โโโ inbound authorizer: NONE; policy engine: none
...
โ โโโ tool: crm-sync s3:PutObject on arn:aws:s3:::kb-product-docs/* unverified write into agent
โ โ 'support-bot' knowledge base (RAG poisoning)
...
โโโ Coverage notes
โ โโโ tool 'erp-mcp' (gateway_target_mcp_server): backend identity unknown, not assessed - remote
โ MCP server; credential provider: OAUTH
What agent-blast reads (all list/get, no charge):
- Bedrock Agents: the agent resource role, every action group at the
DRAFT version resolved to
its Lambda and the Lambda's execution role, knowledge bases resolved to their S3 data-source buckets.
- AgentCore: runtime role and network mode, gateway role with authorizer, policy engine and every
target (Lambda, remote MCP server, API Gateway, OpenAPI, Smithy) with its credential provider,
code interpreter and browser execution roles.
- IAM policies of exactly those identities (inline, attached, group), kept raw: action, resource,
effect, whether a
Condition is present. Conditions are flagged, never guessed. The simulator
decides.
Then, per identity: the 64 privilege-escalation methods, AssumeRole hops through the trust graph,
and every data, secret, lateral, code-execution and model-invocation grant matched against concrete
resources. A knowledge-base bucket is always a concrete target, even behind s3:* on *, and
write access to it is reported as RAG poisoning. Anything the scanner could not read (a denied
region, a tool without an IAM identity) is a coverage note, never a silent pass.
--verify asks iam:SimulatePrincipalPolicy about every concrete pair, with the context an attacker
really has (no MFA on the session, TLS transport), and marks each reach PROVEN, DENIED (with the
policy layer that denied: SCP, permissions boundary) or not asserted. Output formats: tree,
json, markdown. The MCP server exposes the same report as get_agent_blast.
A full scan
cloud-audit scan runs 110 read-only checks across 25 AWS services, correlates the findings into
attack chains, ranks the fixes by how many chains they break and prices the exposure. This is the
sample account (cloud-audit demo), rendered by the same code as a real scan and trimmed for length:
โโโโโโโโ Health Score โโโโโโโโ
โ 15 / 100 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Provider AWS
Account 123456789012
Regions eu-central-1
Resources scanned 80
Checks passed 14
Checks failed 6
Attack chains 3
Risk exposure $572K - $12.5M (IBM/Verizon data)
โโโโโโโโโโโโโโโโโโโโโโโโโโ Attack Chains (3 detected) โโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CRITICAL PassRole Escalation to Admin (support-bot-ticket-role) โ
โ Principal 'support-bot-ticket-role' has iam:PassRole and โ
โ can create resources with privileged roles via: โ
โ PassRole+Lambda. The attacker passes an admin role to a โ
โ service, then uses that service to execute code with admin โ
โ privileges. โ
โ Fix: Scope iam:PassRole for 'support-bot-ticket-role' to โ
โ specific role ARNs โ
โ Risk: $250K - $5.0M โ
โ โ
โ CRITICAL Internet-Exposed Admin Instance โ
โ i-0abc123def456789, sg-0a1b2c3d4e5f67890 โ
โ Instance i-0abc123def456789 is reachable from the internet โ
โ via open security group and has admin IAM role โ
โ 'prod-admin-role'. An attacker can reach the instance, โ
โ access IMDS credentials, and gain full admin access to the โ
โ AWS account. โ
โ Fix: Restrict security group sg-0a1b2c3d4e5f67890 to โ
โ specific IPs (effort: LOW). โ
โ Risk: $62K - $625K โ
โ โ
โ CRITICAL CI/CD to Admin Takeover โ
โ Role 'github-deploy-role' trusts an OIDC provider without โ
โ restricting the 'sub' claim AND has admin permissions. Any โ
โ repository on the CI/CD platform can assume this role and โ
โ gain full AWS admin access. โ
โ Fix: Add 'sub' condition to the trust policy (effort: โ
โ LOW). โ
โ Risk: $125K - $1.2M โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโ Remediation Plan (fix 3 things, break 3 chains) โโโโโโโโโโโโโโโโ
โ # Fix Effort Chains Findings Risk Red โ
โ 1 Restrict security groups LOW 1 1 $62.5K - โ
โ 2 Add OIDC 'sub' condition to LOW 1 1 $125K - โ
โ trust policies โ
โ 3 Remove IAM privilege MEDIUM 1 1 $250K - โ
โ escalation paths โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโ Quick Wins (break CRITICAL chains now) โโโโโโโโโโโโโโโโโโโโ
โ 1. aws ec2 revoke-security-group-ingress --group-id sg-0a1b2c3d4e5f67890 โ
โ --protocol tcp --port 22 --cidr 0.0.0.0/0 โ
โ Breaks: AC-01 (Internet-Exposed Admin Instance) โ
โ โ
โ 2. aws iam update-assume-role-policy --role-name github-deploy-role โ
โ --policy-document file://trust-with-sub.json โ
โ Breaks: AC-07 (CI/CD to Admin Takeover) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Preview a fix before touching anything. simulate removes the findings a check would fix and
recomputes score, chains and exposure offline:
$ cloud-audit simulate --report demo.json --fix aws-iam-018
Simulation: Apply Remove IAM privilege escalation paths
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ Impact Analysis โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Metric Before After Delta โ
โ Health Score 15/100 35/100 +20 โ
โ Attack Chains 3 2 -1 โ
โ Findings 6 5 -1 โ
โ Risk Exposure $572K - $12.5M $187.5K - $1.9M -85% โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Chains broken (1):
CRITICAL PassRole Escalation to Admin (support-bot-ticket-role) -> GONE
Chains remaining (2):
CRITICAL Internet-Exposed Admin Instance
CRITICAL CI/CD to Admin Takeover
Next recommended fix: Restrict security groups -> breaks 1 more chain(s)
Walk outward from any resource to see what its compromise reaches:
$ cloud-audit blast-radius --report demo.json --resource arn:aws:iam::123456789012:role/support-bot-ticket-role
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ Blast Radius โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Compromise of role/support-bot-ticket-role leads to Account Takeover via 2 hop(s). โ
โ Resource: arn:aws:iam::123456789012:role/support-bot-ticket-role โ
โ Reachable: 3 | Paths to impact: 1 | Risk score: 72/100 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
role/support-bot-ticket-role - IAM Role (assumed compromised)
โโโ Account Takeover - Full AWS admin (via grants admin, type=exploit) <high-value>
โโโ arn:aws:s3:::company-backups-2024 - S3 bucket (reachable via admin) (via s3:GetObject +
ListBucket, type=data) <high-value>
Available fixes (from scan findings):
- aws-iam-018 Role 'support-bot-ticket-role' can escalate via PassRole+Lambda (breaks chain, effort=MEDIUM)
- aws-s3-001 Bucket 'company-backups-2024' has Block Public Access disabled (breaks chain, effort=LOW)
--format json drops straight into the open browser visualizer at
blast-audit.haitmg.pl; --format mermaid gives a diagram for a
wiki page. exposure ranks every node of the security graph by internet reachability and escalation:
$ cloud-audit exposure --report demo.json -n 6
Score Type Label Why
60 iam_role prod-admin-role internet-reachable
41 internet Internet internet-reachable
41 ec2 i-0abc123def456789 internet-reachable
41 security_group sg-0a1b2c3d4e5f67890 internet-reachable
20 iam_role support-bot-ticket-role escalation
20 iam_role support-bot-search-role linked to others
The visualizer runs entirely in your browser on a blast-radius --format json export.
What's inside
| Capability | Size | Command |
|---|
| Configuration checks, each with an AWS CLI and Terraform fix | 110 checks, 25 services: IAM, S3, EC2, VPC, RDS, KMS, CloudTrail, CloudWatch, GuardDuty, Config, Lambda, ECS, EFS, SSM, Secrets Manager, DynamoDB, Backup, Inspector, Security Hub, WAF, Bedrock, SageMaker, Bedrock AgentCore, Data Perimeter, account | scan, list-checks |
| IAM privilege escalation | 64 methods in 9 categories: IAM self-mutation, credential access, PassRole to a service, Lambda code modification, trust-policy abuse, permission-boundary bypass, resource-policy abuse, compute hijack, lateral AssumeRole (BFS over the trust graph) | scan (aws-iam-018) |
| Attack chains | 31 rules correlating findings and live relationships (EC2 to role, Lambda to role, OIDC to policy) into paths with MITRE ATT&CK references and a priority fix | scan |
| Root causes and quick wins | groups findings by the fix that removes them and ranks by chains broken | scan |
| What-If | before/after score, chains and exposure for any set of checks, offline | simulate --fix |
| Blast radius | forward BFS from an EC2 instance, IAM role or user, Lambda, S3 bucket or secret; JSON contract for the visualizer | blast-radius |
| Exposure ranking | every security-graph node scored by internet reachability and escalation | exposure |
| AI agents | inventory of Bedrock Agents and AgentCore runtimes, gateways, code interpreters, browsers with their IAM identities and tools; two-threat-model reach; OWASP Agentic and MITRE ATLAS tags; simulator proof | agent-blast |
| Proof Mode | iam:SimulatePrincipalPolicy on escalation paths (broad) and on concrete (principal, action, resource) triples (agent-blast) | scan --verify, agent-blast --verify |
| Threat feed | 10 detectors of active abuse, each tied to a documented 2025-2026 incident pattern, versioned as a rules pack | threat-feed |
| Data perimeter | 5 checks on resource policies: confused deputy and cross-organization exposure, evaluating condition values | scan (aws-dp-*) |
| AgentCore configuration | 6 checks: code interpreter and runtime network mode, MMDSv2, memory KMS, gateway authorizer, gateway policy engine | scan (aws-agc-*) |
| Breach cost | USD range per finding and per chain with the public source behind each number | scan |
| Compliance | 6 frameworks with per-control evidence: CIS AWS v3.0, SOC 2 Type II, ISO 27001:2022, HIPAA, NIS2, BSI C5:2020 | scan --compliance, list-frameworks |
| Drift and trend | diff two scans with exit codes; posture history with sparklines | diff, trend |
| Coverage gaps | a read the scanner was denied is reported as "not assessed", never as a pass | every command |
| Outputs | console, JSON, HTML report, SARIF (GitHub Code Scanning), Markdown | scan --format |
| MCP server | 7 read-only tools for Claude Code, Cursor and any MCP client, including get_agent_blast | cloud-audit-mcp |
The ten threat-feed detectors, as cloud-audit threat-feed --list prints them (rules pack 2026-Q2):
| Pattern | Severity | What it catches |
|---|
| TF-001 | MEDIUM | SES recently verified identity (phishing setup precursor) |
| TF-002 | HIGH | Public Lambda Function URL (AuthType=NONE) |
| TF-003 | CRITICAL | AWS-attached credential quarantine policy |
| TF-004 | CRITICAL | Leaked-credentials scanner user-agent observed in CloudTrail |
| TF-005 | HIGH | Recently-created IAM role with cryptomining-style compute access |
| TF-006 | HIGH | EC2 or AgentCore using IMDSv1 / MMDSv1 (SSRF credential theft vector) |
| TF-007 | MEDIUM | CI/CD role at risk of whoAMI confusion attack |
| TF-008 | HIGH | CloudTrail tampering precursor (logging stopped or delivery failing) |
| TF-009 | HIGH | IAM Roles Anywhere trust anchor with external CA |
| TF-010 | HIGH | AmazonDataZoneFullAccess attached to a non-admin principal |
Proof Mode: simulated, not guessed
Static analysis of IAM policies over-reports. Proof Mode asks AWS's own authorization engine,
iam:SimulatePrincipalPolicy, which is read-only and carries no per-call charge.
scan --verify checks every detected escalation path. verified: true means the simulator allowed
every required action; false means it denied one (the path is very likely a false positive);
null means not asserted, with the reason in verification_detail.
agent-blast --verify checks every concrete (principal, action, resource) reach, supplies the
context an attacker with stolen or assumed credentials has, and names the layer that denied.
What the simulator evaluates as of 2026-07-30: identity policies, the attached permissions boundary,
the organization's SCPs including their condition keys, and the context keys you supply. What it does
not: resource control policies, VPC endpoint policies, role chaining, and resource-based policies for
IAM roles. cloud-audit says so on every verified line. A true proves the permission exists. It does
not prove an end-to-end attack; nothing is executed.
Reports
cloud-audit scan --format html -o report.html
cloud-audit scan --format sarif -o results.sarif
cloud-audit scan --format json -o report.json
cloud-audit scan --format markdown -o report.md
cloud-audit scan --compliance cis_aws_v3 --format html -o cis.html
cloud-audit agent-blast --format markdown -o agents.md
CI/CD
- run: pip install cloud-audit
- run: cloud-audit scan --format sarif --output results.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
--quiet exits with a code only: 0 clean, 1 findings, 2 error. Gate on severity with
--min-severity high. cloud-audit diff old.json new.json --quiet exits 1 on new findings, so a
daily scan catches ClickOps drift. The repository is also a composite GitHub Action
(gebalamariusz/cloud-audit@v0). Ready-made workflows: basic scan,
daily diff, post-deploy.
Installation
pip install cloud-audit
pipx install cloud-audit
uvx --from cloud-audit cloud-audit scan
docker run ghcr.io/gebalamariusz/cloud-audit scan
Docker with credentials:
docker run -v ~/.aws:/home/cloudaudit/.aws:ro ghcr.io/gebalamariusz/cloud-audit scan
Python 3.10 to 3.13. Dependencies: boto3, typer, rich, pydantic, jinja2, pyyaml, mcp.
AWS permissions
Read-only. Attach the AWS-managed SecurityAudit policy; it covers every check, the IAM escalation
analysis, the agent inventory and Proof Mode:
aws iam attach-role-policy --role-name auditor \
--policy-arn arn:aws:iam::aws:policy/SecurityAudit
cloud-audit never modifies your infrastructure. simulate, blast-radius, exposure, diff,
trend and agent-blast run locally against a saved scan and make no AWS calls; --verify adds
simulator calls only. Regions where a service does not exist are skipped; regions where the scanner
is denied a read are listed as coverage gaps.
MCP server
Seven read-only tools for AI assistants: scan_aws, get_findings, get_attack_chains,
get_remediation, get_health_score, list_checks, get_agent_blast.
claude mcp add cloud-audit -- uvx --from cloud-audit cloud-audit-mcp
Then ask: "scan my AWS account and tell me what my Bedrock agents could reach if hijacked".
Common flags and configuration
cloud-audit scan -R
cloud-audit scan --profile prod --regions eu-central-1
cloud-audit scan --regions all
cloud-audit scan --role-arn arn:aws:iam::...:role/audit
cloud-audit scan --export-fixes fixes.sh
cloud-audit scan --categories security,cost
cloud-audit agent-blast -a support-bot --profile prod --verify
Defaults live in .cloud-audit.yml (regions, min_severity, exclude_checks, time-boxed
suppressions). Environment variables (CLOUD_AUDIT_REGIONS, CLOUD_AUDIT_MIN_SEVERITY, ...)
override the file; CLI flags override everything. See the
configuration guide.
Documentation
Full documentation at haitmg.pl/cloud-audit:
getting started,
agent-blast,
attack chains,
IAM escalation,
blast radius,
Proof Mode,
threat feed,
data perimeter,
AgentCore,
compliance, and the
full check reference.
Commercial support
cloud-audit is free and stays free. If you want a human on the findings, the author offers
professional services:
- Scanner output review (free): send your cloud-audit, Prowler or Security Hub output, get a short written review of what actually matters and what to fix first
- AWS security audit: full account audit with a prioritized report and ready-to-apply fixes
- AI agent access review: what your Bedrock and AgentCore agents can reach, with the policy changes to narrow it
- Remediation support: Terraform and IAM changes, verified against your workloads
- Palo Alto VM-Series on AWS: architecture and security review (GWLB/TGW, HA, routing)
Details: haitmg.pl/cloud-audit-support
or email kontakt@haitmg.pl.
Development
git clone https://github.com/gebalamariusz/cloud-audit.git
cd cloud-audit
pip install -e ".[dev]"
pytest -q && ruff check src/ tests/ && mypy src/
See CONTRIBUTING.md to add a check. Releases in CHANGELOG.md.
License
MIT - Mariusz Gebala / HAIT