This release includes 14 security fixes for security teams reviewing exposed deployments.
Topics
+13 more
Affected surfaces
ReleasePort's take
Moderate signalHTML entity escapes user‑controlled Mermaid node labels to prevent SVG context breakout.
Why it matters: Security fix (severity 90) mitigates SVG context breakout in Mermaid output generation; critical for developers and SREs handling untrusted diagram data.
Summary
AI summaryUpdates Tests, admin, and default across a mixed release.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Security | Critical |
HTML entity escapes user-controlled Mermaid node labels to prevent SVG context breakout. HTML entity escapes user-controlled Mermaid node labels to prevent SVG context breakout. Source: llm_adapter@2026-05-25 Confidence: high |
— |
| Security | High |
Strips non‑http(s) URL schemes from HTML report links to block JavaScript injection. Strips non‑http(s) URL schemes from HTML report links to block JavaScript injection. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Security | High |
Escapes markdown control characters in Markdown output to prevent link injection. Escapes markdown control characters in Markdown output to prevent link injection. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Security | Medium |
Prevents `_make_id` collisions by appending SHA‑256 suffix for long identifiers (CWE-345/CWE-1023). Prevents `_make_id` collisions by appending SHA‑256 suffix for long identifiers (CWE-345/CWE-1023). Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Security | Medium |
Eliminates AssumeRole cycle re‑emission of seed role as lateral target via ARN deduplication. Eliminates AssumeRole cycle re‑emission of seed role as lateral target via ARN deduplication. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Security | Medium |
Restricts `_find_execution_role_for_lambda` to return roles only for the queried Lambda (CWE-697). Restricts `_find_execution_role_for_lambda` to return roles only for the queried Lambda (CWE-697). Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Security | Medium |
Clamps `--max-depth` and `--max-nodes` CLI options to safe bounds (1‑25, 1‑10 000) to avoid DoS. Clamps `--max-depth` and `--max-nodes` CLI options to safe bounds (1‑25, 1‑10 000) to avoid DoS. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Security | Medium |
Errors when writing ANSI escape sequences to non‑TTY files (`--format tree --output FILE`). Errors when writing ANSI escape sequences to non‑TTY files (`--format tree --output FILE`). Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Security | Medium |
Escapes Rich markup in console rendering to prevent terminal recoloring attacks. Escapes Rich markup in console rendering to prevent terminal recoloring attacks. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Security | Medium |
Refuses to follow pre‑existing symlinks in `--output` writers (TOCTOU protection). Refuses to follow pre‑existing symlinks in `--output` writers (TOCTOU protection). Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Security | Low |
Wraps `OSError` in friendly messages instead of leaking full tracebacks. Wraps `OSError` in friendly messages instead of leaking full tracebacks. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Security | Low |
Persists `escalation_paths` in saved scans for blast‑radius consumption. Persists `escalation_paths` in saved scans for blast‑radius consumption. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Feature | Low |
Adds `cloud-audit blast-radius` CLI command for attack‑surface analysis. Adds `cloud-audit blast-radius` CLI command for attack‑surface analysis. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Feature | Low |
Supports EC2, IAM Role/User, Lambda, S3 bucket, and Secrets Manager secret as seed resources. Supports EC2, IAM Role/User, Lambda, S3 bucket, and Secrets Manager secret as seed resources. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Feature | Low |
Provides output formats: tree (default), JSON, Mermaid diagram, and Markdown summary. Provides output formats: tree (default), JSON, Mermaid diagram, and Markdown summary. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Feature | Low |
Introduces `cloud-audit exposure` command for account‑wide blast‑impact aggregation. Introduces `cloud-audit exposure` command for account‑wide blast‑impact aggregation. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Performance | Low |
Adds regression tests covering resource‑type detection, depth limits, rendering formats, and security fixes (26 new tests). Adds regression tests covering resource‑type detection, depth limits, rendering formats, and security fixes (26 new tests). Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Bugfix | Medium |
Falls back to `report.all_findings` when role missing from `escalation_paths` (EC2 admin‑role case). Falls back to `report.all_findings` when role missing from `escalation_paths` (EC2 admin‑role case). Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Bugfix | Medium |
Refines detection matching to require `/` or `:` boundaries, eliminating false positives from short labels. Refines detection matching to require `/` or `:` boundaries, eliminating false positives from short labels. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Bugfix | Low |
Corrects off‑by‑one depth handling so max‑depth = 1 reports Account Takeover for EC2 with attached admin role. Corrects off‑by‑one depth handling so max‑depth = 1 reports Account Takeover for EC2 with attached admin role. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
| Refactor | Medium |
Adds optional `security_graph` field to `ScanReport` with default None for backward compatibility. Adds optional `security_graph` field to `ScanReport` with default None for backward compatibility. Source: granite4.1:30b@2026-05-25-audit Confidence: low |
— |
Full changelog
Added
-
Blast Radius CLI - new
cloud-audit blast-radius --resource <id>command
that walks outward from a single AWS resource and shows what an attacker
could reach if THAT resource were compromised. Pure in-memory analysis
against a saved scan - zero AWS API calls at blast-radius time.Seed resource types supported:
- EC2 instance (short id
i-XXX) - IAM Role / IAM User (full ARN)
- Lambda function (full ARN)
- S3 bucket (full ARN)
- Secrets Manager secret (full ARN)
Expansion rules:
- Compute -> attached IAM role (via attack chain
viz_stepsfrom AC-01,
AC-02, AC-05 etc.) -> reachable identities and data - Identity -> admin impact node when
escalation_pathsindicate admin - Identity -> AssumeRole chain targets from
iam_trust_graph - Identity (admin) -> S3 buckets / Secrets Manager secrets present in
findings as candidate exfiltration targets
Output formats (
--format):tree(default) - Rich tree in CLI with color-coded node typesjson- BlastRadiusGraph v1.0 schema, the wire-format contract with
cloud-audit-demo's 3D visualization (camelCase fields preserved on purpose)mermaid- Mermaidgraph TDdiagram with per-type stylingmarkdown- compact summary for PRs or reports
Bounds:
--max-depth N(default 5) caps BFS hops--max-nodes N(default 50) caps total nodes in the graph
Pure CLI, no Neo4j, no Docker, no SaaS account. Built on top of the
existingiam_trust_graph(524 lines, AssumeRole BFS),iam_analyzer
(706 lines, 60 escalation methods catalog),correlate(1574 lines,
31 attack-chain rules withVizSteps), andcost_modelso the
same fixes you see inscanshow up under the same finding ids in the
blast-radius output. Documented indocs/features/blast-radius.md. - EC2 instance (short id
-
exposurecommand - newcloud-audit exposurerolls up findings by
blast-impact heuristic (which identities/data would compound on the next
hop). Complementsblast-radius(single-seed) with an account-wide view.
Changed
ScanReport.security_graph- new optional field (dict[str, object] | None).
Populated by the scanner for blast-radius / exposure consumers. Backwards-
compatible: existing parsers that don't know the field will keep working
thanks todefault=None.
Fixed
Nine issues addressed by the pre-release security audit (SECURITY-AUDIT-2026-05-15.md):
- SEC-001 - Mermaid output now HTML-entity escapes user-controlled node
labels (<,>,&,",\, plus brackets, braces, pipes). Without this,
a crafted scan label</text>would break out of the Mermaid SVG context
when the diagram is rendered in a GitHub README. - SEC-002 -
_make_idcollision protection: when a sanitised candidate id
exceeds 120 chars, a SHA-256(prefix + value) suffix is appended so two
long-but-different inputs cannot collide post-truncation (CWE-345 / CWE-1023). - SEC-003 - AssumeRole cycle (A->B->A) no longer re-emits the seed role
as a lateral target node. ARN-level dedup (visited_arns) catches the
cross-prefix duplicate that graph-id dedup alone misses. - SEC-004 -
_find_execution_role_for_lambdanow refuses to return a
role belonging to a different function (CWE-697 narrow-match): scan with
chain forfnAand query forfnBreturnsNone, notfnA's role. - SEC-005 -
--max-depthand--max-nodesare clamped to safe bounds
(1..25 and 1..10_000) instead of accepting unbounded user input (DoS). - SEC-006 -
--format tree+--output FILEreturns an error instead of
silently writing ANSI escape sequences to disk (CWE-684). - SEC-007 - Exception handler in the CLI wraps
OSErrorwith a friendly
message instead of leaking a full Python traceback to stderr. - SEC-008 - Rich console rendering of node lines escapes Rich markup
([red]...[/]) found inside scan labels so a crafted scan can't recolor
the terminal output. - SEC-009 - Scanner persists
escalation_pathsto the saved scan so
blast-radius can read them without re-running the IAM analyzer.
Plus pre-release follow-ups from the second security pass:
- F-S2-01 - HTML report templates (
report.html.j2,compliance_html.py)
now strip non-http(s)URL schemes fromfinding.cost_estimate.source_url
andfinding.remediation.doc_url. Without this, ajavascript:URL in a
crafted scan JSON would execute when the user clicks the link in the
rendered HTML report. - F-S2-02 - All
--outputwriters refuse to follow pre-existing symlinks
(TOCTOU symlink attack protection on shared CI runners). The CLI raises a
clear error instead of silently clobbering the symlink target. - F-S2-03 - Markdown output (
--format markdown) now escapes markdown
control characters in user-controlled labels so a crafted resource name
cannot inject[link](javascript:...)into the rendered report. - F-S2-04 -
_resolve_role_arnfalls back toreport.all_findingswhen
the role isn't present inescalation_paths(an EC2 with an attached
admin role but no separate escalation path previously returned a
seed-only blast graph - now resolves and reports Account Takeover). - F-S2-05 - BFS
--max-depth=1now surfaces Account Takeover for an
EC2 seed with an attached admin role (was off-by-one: compute->role
linkage previously consumed the depth budget). - F-S2-06 - Fix/detection matching no longer uses bare
endswith(label)
for short labels - now requires a/or:boundary, eliminating false
positives where label"admin"matchedsuper-admin.
Tests
- 786 -> 812 (+26 net). New regression tests in
tests/test_blast_radius.py
andtests/test_graph.pycover: resource-type detection (8 regex patterns),
empty-scan seed-only behaviour, IAM role -> impact node, EC2 with attached
role linkage, Lambda with execution role, max-depth and max-nodes
enforcement, Rich tree render, Mermaidgraph TDshape, JSON schema
spot-checks (top-level fields, camelCase preservation, node + edge type
enums), fixes and detections pulled from findings, and a full
TestSecurityRegressionclass for SEC-001 through SEC-009.
Schema contract
The JSON output is the schema documented in
cloud-audit-demo/src/types/blast-radius.ts (BlastRadiusGraph v1.0).
Field names are camelCase by intent because the demo's TypeScript types
are the consumer. A per-file ruff exemption in pyproject.toml documents
this trade-off.
Security Fixes
- SEC-001 – Mermaid output HTML‑entity escapes user‑controlled labels to prevent SVG context breakout
- SEC-002 – SHA‑256 suffix added when sanitized IDs exceed 120 chars (CWE‑345/CWE‑1023)
- SEC-003 – Deduplication prevents AssumeRole cycle re‑emission of seed role
- SEC-004 – `_find_execution_role_for_lambda` now rejects cross‑function role returns (CWE‑697)
- SEC-005 – `--max-depth` and `--max-nodes` clamped to safe bounds (1‑25, 1‑10 000) to avoid DoS
- SEC-006 – Error raised when writing ANSI escapes to a file via `--format tree --output FILE` (CWE‑684)
- SEC-007 – Friendly error message instead of full traceback on CLI OSError
- SEC-008 – Rich console rendering escapes markup in scan labels to prevent terminal recoloring
- F-S2-01 – HTML report strips non‑http(s) URL schemes from `source_url` and `doc_url` (prevents javascript: injection)
- F-S2-02 – CLI refuses to follow pre‑existing symlinks on `--output` paths (TOCTOU protection)
- F-S2-03 – Markdown output escapes markdown control characters in labels (prevents link injection)
- F-S2-04 – `_resolve_role_arn` falls back to all findings for missing escalation paths, enabling Account Takeover detection
- F-S2-05 – BFS `--max-depth=1` now surfaces Account Takeover for EC2 seeds with attached admin roles
- F-S2-06 – Detection matching requires `/` or `:` boundary to avoid false positives on short labels
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About gebalamariusz/cloud-audit
Open-source AWS security scanner with attack chain detection, breach cost estimation, and copy-paste remediation (CLI + Terraform). 47 checks, 16 attack chain rules. First free standalone AWS security MCP server.
Related context
Related tools
Earlier breaking changes
- v2.2.0 Category enum gains THREAT value, separating active-abuse from SECURITY misconfigurations.
Beta — feedback welcome: [email protected]