Agent Blast-Radius
shieldly agent-scan answers one question: what could this AI agent's AWS credentials destroy, exfiltrate, or escalate to? Included in every Shieldly plan, same price — no new SKU.
Quickstart
npm install -g @shieldly/cliRun it with no arguments in a project that has an agent config (.mcp.json, Claude Code settings, Claude Desktop, Cursor, Windsurf, VS Code) — it auto-discovers the config and any AWS profile or role it references:
shieldly agent-scanOr point it at an input explicitly:
shieldly agent-scan --policy-file agent-policy.json
shieldly agent-scan --role-arn arn:aws:iam::123456789012:role/my-agent
shieldly agent-scan --cfn-file cdk.out/MyStack.template.json
shieldly agent-scan --sarif > results.sarifInputs
| Flag | What it analyzes |
|---|---|
| (none) | Auto-discover agent configs in the current directory + well-known global locations |
| --policy-file <path> | Analyze an IAM policy JSON file |
| --role-arn <arn> | Fetch + analyze a role's attached and inline policies (local AWS credentials) |
| --profile <name> | Resolve a local AWS profile's identity and analyze it |
| --cfn-file <path> | Scan a synthesized CloudFormation template for agent-like resources (Bedrock agent, ECS task definition, Lambda function) and their in-template IAM role |
Auto-discovery paths
With no input flag, agent-scan walks these paths (project-level relative to the current directory, plus global/cross-project locations) looking for AWS_PROFILE, role ARNs, or hardcoded access keys:
| Path | Scope | Notes |
|---|---|---|
| .mcp.json / mcp.json | Project | Any OS |
| .claude/settings.json, .claude/settings.local.json | Project | Any OS |
| .cursor/mcp.json | Project | Any OS |
| .vscode/mcp.json | Project | Any OS |
| ~/.cursor/mcp.json | Global | Any OS |
| ~/.codeium/windsurf/mcp_config.json | Global (Windsurf) | Any OS |
| .../Code/User/mcp.json | Global (VS Code user profile) | macOS / Windows / Linux paths |
| claude_desktop_config.json | Global (Claude Desktop) | macOS / Windows / Linux paths |
How to read a blast-radius report
Every scan produces one overall grade — the worst finding wins:
| Grade | Meaning |
|---|---|
| CRITICAL | At least one CRITICAL finding — the agent could take over the account or destroy production data. |
| HIGH | At least one HIGH finding, no CRITICAL — serious but bounded (e.g. can delete resources in one service). |
| MODERATE | At least one MEDIUM finding, nothing higher — worth tightening, not an emergency. |
| LOW | Only LOW findings or none — the credential is reasonably scoped. |
Findings are grouped into six categories:
| Category | Meaning |
|---|---|
| DESTRUCTIVE | Can delete/terminate/modify infrastructure or data (S3, RDS, DynamoDB, EC2, ECS, Lambda, CloudFormation, Route53) |
| ESCALATION | Can grant itself (or others) more permissions (iam:PassRole, CreateAccessKey, AttachPolicy, sts:AssumeRole on *) |
| DATA_ACCESS | Can read sensitive data stores (S3, Secrets Manager, SSM, RDS snapshots, DynamoDB) |
| COST_RISK | Can run up the AWS bill without constraints (ec2:RunInstances, SageMaker, Bedrock InvokeModel) |
| WILDCARD | Structurally unbounded grants (Action "*", service-wide wildcards, Resource "*", NotAction+Allow) |
| NO_GUARDRAILS | Missing boundaries or hardcoded long-lived credentials in a config file |
Each finding lists the matched actions, the affected resources, and a one-line fix — start with CRITICAL/HIGH findings in ESCALATION and DESTRUCTIVE first; those are the ones that turn a compromised or misbehaving agent into an account-wide incident.
Rule reference
Rules are matched by glob intersection (e.g. a grant of s3:* matches a rule for s3:DeleteObject) — no AWS action list is expanded or shipped.* marks rules whose severity is bumped when the statement's Resource is also "*". Suppress any rule with --ignore <rule-id>.
| Rule ID | Category | Severity | Title |
|---|---|---|---|
| BR-DEST-S3 | DESTRUCTIVE | HIGH / CRITICAL* | Can delete or rewrite S3 data |
| BR-DEST-RDS | DESTRUCTIVE | HIGH / CRITICAL* | Can delete or modify RDS databases |
| BR-DEST-DDB | DESTRUCTIVE | HIGH / CRITICAL* | Can delete DynamoDB tables or items |
| BR-DEST-EC2 | DESTRUCTIVE | HIGH / CRITICAL* | Can terminate or modify EC2 instances |
| BR-DEST-ECS | DESTRUCTIVE | HIGH / CRITICAL* | Can delete or modify ECS services |
| BR-DEST-LAMBDA | DESTRUCTIVE | HIGH / CRITICAL* | Can delete or rewrite Lambda functions |
| BR-DEST-CFN | DESTRUCTIVE | HIGH / CRITICAL* | Can delete or mutate CloudFormation stacks |
| BR-DEST-R53 | DESTRUCTIVE | HIGH / CRITICAL* | Can change DNS records |
| BR-ESC-PASSROLE | ESCALATION | HIGH / CRITICAL* | Can pass IAM roles to services |
| BR-ESC-CREATEKEY | ESCALATION | CRITICAL | Can mint credentials for other identities |
| BR-ESC-ATTACH | ESCALATION | CRITICAL | Can grant itself more permissions |
| BR-ESC-ASSUME-STAR | ESCALATION | CRITICAL | Can assume any role in the account (sts:AssumeRole on *) |
| BR-DATA-S3 | DATA_ACCESS | MEDIUM / HIGH* | Can read S3 data |
| BR-DATA-SECRETS | DATA_ACCESS | HIGH / CRITICAL* | Can read Secrets Manager secrets |
| BR-DATA-SSM | DATA_ACCESS | HIGH / CRITICAL* | Can read SSM parameters |
| BR-DATA-RDS-SNAP | DATA_ACCESS | MEDIUM / HIGH* | Can access RDS snapshots |
| BR-DATA-DDB | DATA_ACCESS | MEDIUM / HIGH* | Can read DynamoDB data |
| BR-COST-EC2 | COST_RISK | MEDIUM / HIGH* | Can launch EC2 instances without constraints |
| BR-COST-SAGEMAKER | COST_RISK | MEDIUM / HIGH* | Can create SageMaker resources without constraints |
| BR-COST-BEDROCK | COST_RISK | MEDIUM / HIGH* | Can invoke Bedrock models without constraints |
| BR-WILD-ACTION | WILDCARD | CRITICAL | Action "*" — unrestricted actions |
| BR-WILD-RESOURCE | WILDCARD | MEDIUM | Resource "*" — applies to every resource |
| BR-WILD-SERVICE | WILDCARD | HIGH | Service-wide wildcard action (e.g. s3:*) |
| BR-WILD-NOTACTION | WILDCARD | HIGH | Allow + NotAction — grants everything not listed |
| BR-GUARD-HARDCODED-KEY | NO_GUARDRAILS | CRITICAL | Hardcoded AWS access key in agent config |
| BR-GUARD-NO-BOUNDARY | NO_GUARDRAILS | LOW | No permission boundary on the agent identity |
Budget file reference (CI enforcement)
--budget shieldly.policy.yml declares the maximum permission budget an agent's credentials may have; agent-scan exits non-zero when a scan violates it — wire it into a PR check the same way you would a test suite.
# shieldly.policy.yml
maxSeverity: HIGH
denyCategories:
- ESCALATION
ignoreRules:
- BR-GUARD-NO-BOUNDARY
maxFindings: 10| Field | Type | Meaning |
|---|---|---|
| maxSeverity | string | Highest severity allowed before the check fails: LOW | MEDIUM | HIGH | CRITICAL |
| denyCategories | string[] | Fail if any finding falls in one of these categories (e.g. ESCALATION) |
| ignoreRules | string[] | Rule IDs to suppress, same as repeating --ignore <rule-id> |
| maxFindings | number | Fail if the total finding count exceeds this |
YAML or JSON both work. See shieldly.policy.example.yml for a full example.
Use in CI
The Shieldly GitHub Action runs agent-scan directly — no API key needed, fully offline:
- name: Agent Blast-Radius
uses: shieldly-io/action@v1
with:
agent-scan: true
agent-scan-path: .
budget-file: shieldly.policy.ymlSee the GitHub Action docs for every input.
History, diffs & alerts (Builder plan+)
--upload sends the scan's findings (rule IDs, categories, severities, grade — never the policy document itself) to your Shieldly account: it builds a per-agent history, diffs each scan against the last one for that identity, and alerts Slack when a new CRITICAL finding appears. View it at /app/agents. Connected AWS accounts (Team plan+) also get a daily scheduled re-scan of their registered agent roles, so permission drift is caught even between manual scans.
FAQ
Does my agent config or policy ever leave my machine?
No. agent-scan runs fully offline — it never makes a network call unless you explicitly pass --upload with an API key, in which case only the finding metadata (rule IDs, categories, severities, counts) is sent, never the raw policy or config content.
Does agent-scan expand wildcard actions like s3:* into every matching AWS action?
No — it matches wildcard grants against rule patterns with glob intersection, so there's no AWS action list to ship, download, or go stale.
I got a false positive — how do I suppress just that rule?
Pass --ignore <rule-id> (repeatable), or add it to ignoreRules in your budget file. Think it's a bug in the rule itself? Open a false-positive report on the CLI's GitHub issues.
Does this replace IAM Access Analyzer?
No — they're complementary. Access Analyzer finds unused access across your whole account; agent-scan is agent-config-aware (it finds the credential an AI agent is actually using) and built for CI-native enforcement with a single command.