Skip to content

Commit df74025

Browse files
committed
release: v2.1.0 - 64 IAM escalation methods, full pathfinding.cloud coverage
Tier 1 (20 action-based methods): PassRole variants for Glue/ECS/CloudFormation, EC2 instance profile hijack, Lambda resource policy abuse, IAM deny-removal, MFA bypass paths. Tier 2 (12 methods, +1 new category COMPUTE_HIJACK): PassRole+CodeBuild/AppRunner/ SageMaker/Bedrock/StepFunctions, SSM compute hijack (SendCommand/StartSession/ GetParameter), EC2 Instance Connect SSH key push, hijack of existing CodeBuild projects and AppRunner services. Tier 3 (4 lateral methods, +1 new category LATERAL_ASSUME_ROLE): trust policy graph traversal in new module iam_trust_graph.py. Detects AssumeRole:Direct (1-hop to admin), AssumeRole:Chain (multi-hop), AssumeRole:WildcardTrust (Principal:*), and AssumeRole:CrossAccountRoot (external account root). Same-account-root expansion semantics, bare account ID normalization, conditions flagged but not evaluated (lightweight unlike PMapper). Plus 3 post-benchmark methods: glue:UpdateDevEndpoint, sagemaker:CreatePresigned NotebookUrl, PassRole+SageMaker:CreateTrainingJob - for parity with Bishop Fox iam-vulnerable test bench. Total: 60 action-based + 4 lateral = 64 detection methods across 9 categories (was 25/6 in v2.0). 142 new tests added (496 -> 638 total).
1 parent 7a5bd00 commit df74025

10 files changed

Lines changed: 2390 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [2.1.0] - 2026-04-28
11+
12+
### Added
13+
14+
- **IAM Privilege Escalation - Tier 1 + Tier 2 + Tier 3**: 39 new detection methods, total 64 across 9 categories (was 25/6). Coverage of all known IAM privilege escalation paths in pathfinding.cloud.
15+
16+
Tier 1 (20 methods - PassRole variants + resource policy abuse + deny removal):
17+
- PassRole + Glue variants: `glue:CreateJob`, `glue:UpdateJob`, `glue:CreateSession`
18+
- PassRole + ECS variants: `ecs:UpdateService`, `ecs:RegisterTaskDefinition` (auto-deploy)
19+
- PassRole + CloudFormation: `cloudformation:UpdateStack`
20+
- PassRole + EC2 instance profile hijack: `ec2:AssociateIamInstanceProfile`, `ec2:ReplaceIamInstanceProfileAssociation`
21+
- PassRole + Lambda event source mapping
22+
- Instance profile role swap (no PassRole): `iam:RemoveRoleFromInstanceProfile` + `iam:AddRoleToInstanceProfile`
23+
- **NEW Resource Policy Abuse category**: `lambda:AddPermission`, `lambda:AddLayerVersionPermission`
24+
- IAM deny-removal patterns: `iam:DeleteRolePolicy`, `iam:DeleteUserPolicy`, `iam:DetachRolePolicy`, `iam:DetachUserPolicy`, `iam:CreateServiceLinkedRole`
25+
- Credential access extensions: `iam:UpdateAccessKey`, `iam:DeactivateMFADevice`, `iam:DeleteVirtualMFADevice` (MFA bypass paths)
26+
27+
Tier 2 (12 methods - new compute primitives + SSM):
28+
- PassRole + new services: `codebuild:CreateProject`, `apprunner:CreateService`, `sagemaker:CreateNotebookInstance`, `sagemaker:CreateProcessingJob`, `bedrock:CreateAgent`, `states:CreateStateMachine`
29+
- **NEW Compute Hijack category**: `ssm:SendCommand`, `ssm:StartSession` (managed EC2 abuse), `ec2-instance-connect:SendSSHPublicKey` (60s SSH key push), `codebuild:UpdateProject` (hijack existing CI build), `apprunner:UpdateService` (replace running container)
30+
- Credential access extension: `ssm:GetParameter` (read secrets from Parameter Store)
31+
32+
Tier 3 (4 methods - lateral movement via AssumeRole graph - NEW pipeline):
33+
- **NEW Lateral AssumeRole category** with new module `iam_trust_graph.py` parsing `AssumeRolePolicyDocument` and building a directed graph
34+
- `AssumeRole:Direct` - 1-hop assume from a principal to a role with admin permissions
35+
- `AssumeRole:Chain` - multi-hop assume chain (up to 4 hops) ending at admin
36+
- `AssumeRole:WildcardTrust` - any role with `Principal: "*"` trust policy
37+
- `AssumeRole:CrossAccountRoot` - any role trusting external account `:root`
38+
- Same-account root expansion: roles trusting `arn:aws:iam::SAME:root` are reachable by any principal in account with `sts:AssumeRole`
39+
- Bare 12-digit account IDs are normalized to `:root` ARNs
40+
- Trust conditions (MFA / ExternalId / SourceArn) are flagged but not semantically evaluated
41+
1042
## [2.0.1] - 2026-04-17
1143

1244
### Changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ cloud-audit simulate --fix aws-vpc-002
103103

104104
| Feature | What it does |
105105
|---|---|
106-
| **IAM Privilege Escalation** | 25 escalation methods across 6 categories. PMapper has been dead since 2022 -- this is its open-source replacement. |
106+
| **IAM Privilege Escalation** | 61 escalation methods across 9 categories, including lateral movement detection via AssumeRole graph traversal. PMapper has been dead since 2022 -- this is its open-source replacement, and it covers paths PMapper never did. |
107107
| **What-If Simulator** | `cloud-audit simulate --fix aws-vpc-002` shows score change, chains broken, and risk reduction before you apply anything. |
108108
| **Root Cause Grouping** | "Fix 4 things, break 22 chains." Groups findings by shared root cause and ranks by impact. |
109109
| **Security Posture Trend** | `cloud-audit trend` tracks health score, chains, and risk over time with sparkline visualization. |
@@ -191,7 +191,7 @@ cloud-audit is AWS-only and intentionally narrower (94 curated checks). It goes
191191
| Compliance frameworks (AWS) | 41 (CIS, PCI-DSS, HIPAA, SOC2, NIST, ISO 27001, GDPR, FedRAMP, NIS2, ...) | 6 (CIS v3.0, SOC 2, BSI C5, ISO 27001, HIPAA, NIS2) |
192192
| Auto-remediation | 55 fixers across 17 AWS services (direct API calls) | 94/94 findings with CLI + Terraform output (reviewable, you apply) |
193193
| Attack path / graph analysis | Prowler App (Cartography + graph queries) | CLI-native (31 rules, no infra) |
194-
| IAM privilege escalation graph | Prowler App | CLI-native (25 methods) |
194+
| IAM privilege escalation graph | Prowler App | CLI-native (61 methods + AssumeRole graph) |
195195
| What-If remediation simulator | No | Yes |
196196
| AI/ML security checks (Bedrock + SageMaker) | ~20 checks | 5 checks + 3 attack chain rules |
197197
| Scan diff / drift tracking | Prowler App | Built-in CLI (`cloud-audit diff`) |
@@ -323,7 +323,7 @@ Full docs at **[haitmg.pl/cloud-audit](https://haitmg.pl/cloud-audit/)**:
323323

324324
- **[Getting Started](https://haitmg.pl/cloud-audit/getting-started/installation/)** - installation, quick start, demo mode
325325
- **[Attack Chains](https://haitmg.pl/cloud-audit/features/attack-chains/)** - all 31 rules with MITRE ATT&CK references
326-
- **[IAM Escalation](https://haitmg.pl/cloud-audit/features/iam-escalation/)** - 25 methods, 6 categories
326+
- **[IAM Escalation](https://haitmg.pl/cloud-audit/features/iam-escalation/)** - 61 methods, 9 categories (action-based + lateral AssumeRole graph)
327327
- **[What-If Simulator](https://haitmg.pl/cloud-audit/features/simulate/)** - simulate remediation impact
328328
- **[Compliance](https://haitmg.pl/cloud-audit/compliance/overview/)** - 6 frameworks: CIS, SOC 2, BSI C5, ISO 27001, HIPAA, NIS2
329329
- **[All 94 Checks](https://haitmg.pl/cloud-audit/checks/)** - full check reference by service

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "cloud-audit"
7-
version = "2.0.1"
7+
version = "2.1.0"
88
description = "Open-source AWS security scanner with IAM escalation detection, What-If simulator, security trends, AI-SPM (Bedrock/SageMaker), 6 compliance frameworks, 31 attack chain rules, breach cost estimation, and MCP server. 94 checks across 23 services. Every finding includes CLI + Terraform remediation."
99
readme = "README.md"
1010
license = "MIT"

src/cloud_audit/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ class EscalationCategory(str, Enum):
123123
LAMBDA_CODE_MOD = "lambda_code_modification"
124124
TRUST_POLICY_ABUSE = "trust_policy_abuse"
125125
PERMISSION_BOUNDARY = "permission_boundary_bypass"
126+
RESOURCE_POLICY_ABUSE = "resource_policy_abuse"
127+
COMPUTE_HIJACK = "compute_hijack"
128+
LATERAL_ASSUME_ROLE = "lateral_assume_role"
126129

127130

128131
class EscalationPath(BaseModel):

src/cloud_audit/providers/aws/checks/iam.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,63 @@ def check_privilege_escalation(provider: AWSProvider) -> CheckResult:
12561256
f'# Action = ["{path.required_actions[0]}"]\n'
12571257
f'# Effect = "Deny"'
12581258
)
1259+
elif path.category.value == "resource_policy_abuse":
1260+
cli_fix = (
1261+
f"# Restrict {path.required_actions[0]} for {path.principal_type.lower()} "
1262+
f"'{path.principal_name}':\n"
1263+
f"# Resource policy modifications enable cross-account/cross-principal abuse.\n"
1264+
f"# Scope this action to specific function/layer ARNs or remove entirely."
1265+
)
1266+
tf_fix = (
1267+
f"# Deny resource policy abuse via SCP or permission boundary:\n"
1268+
f'# Action = ["{path.required_actions[0]}"]\n'
1269+
f'# Effect = "Deny"'
1270+
)
1271+
elif path.category.value == "compute_hijack":
1272+
cli_fix = (
1273+
f"# Restrict {', '.join(path.required_actions)} for "
1274+
f"{path.principal_type.lower()} '{path.principal_name}':\n"
1275+
f"# These actions allow taking over existing compute that holds a privileged role.\n"
1276+
f"# Scope to specific instance/project/service ARNs and require MFA where possible."
1277+
)
1278+
tf_fix = (
1279+
f"# Limit compute-hijack actions via permission boundary or SCP:\n"
1280+
f"# Action = {path.required_actions}\n"
1281+
f'# Effect = "Deny"\n'
1282+
f'# Condition = {{ Bool = {{ "aws:MultiFactorAuthPresent" = "false" }} }}'
1283+
)
1284+
elif path.category.value == "lateral_assume_role":
1285+
cli_fix = (
1286+
f"# Tighten trust policy on role '{path.principal_name}':\n"
1287+
f"# 1. Replace wildcard/root principals with specific ARNs.\n"
1288+
f"# 2. Add sts:ExternalId condition for cross-account roles.\n"
1289+
f"# 3. Require aws:MultiFactorAuthPresent = true for sensitive roles.\n"
1290+
f"# Update via: aws iam update-assume-role-policy "
1291+
f"--role-name {path.principal_name} --policy-document file://trust-policy.json"
1292+
)
1293+
tf_fix = (
1294+
"# Example hardened trust policy (replace with concrete principals):\n"
1295+
'data "aws_iam_policy_document" "assume_role" {\n'
1296+
" statement {\n"
1297+
' effect = "Allow"\n'
1298+
" principals {\n"
1299+
' type = "AWS"\n'
1300+
' identifiers = ["arn:aws:iam::ACCOUNT:role/specific-caller"]\n'
1301+
" }\n"
1302+
' actions = ["sts:AssumeRole"]\n'
1303+
" condition {\n"
1304+
' test = "StringEquals"\n'
1305+
' variable = "sts:ExternalId"\n'
1306+
' values = ["unique-shared-secret"]\n'
1307+
" }\n"
1308+
" condition {\n"
1309+
' test = "Bool"\n'
1310+
' variable = "aws:MultiFactorAuthPresent"\n'
1311+
' values = ["true"]\n'
1312+
" }\n"
1313+
" }\n"
1314+
"}"
1315+
)
12591316
else:
12601317
cli_fix = (
12611318
f"# Remove {', '.join(path.required_actions)} from "

0 commit comments

Comments
 (0)