cloud-audit 2.1.0__tar.gz → 2.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/CHANGELOG.md +115 -0
  2. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/PKG-INFO +18 -2
  3. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/README.md +16 -0
  4. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/mkdocs.yml +1 -0
  5. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/pyproject.toml +9 -2
  6. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/cli.py +139 -0
  7. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/models.py +9 -0
  8. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/provider.py +2 -0
  9. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/__init__.py +105 -0
  10. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/cloudtrail_tampering.py +195 -0
  11. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/cryptomining_role.py +193 -0
  12. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/datazone_overgrant.py +173 -0
  13. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/lambda_function_url.py +238 -0
  14. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/mmdsv1_in_use.py +258 -0
  15. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/quarantine_policy.py +191 -0
  16. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/roles_anywhere_abuse.py +166 -0
  17. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/ses_phishing.py +236 -0
  18. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/trufflehog_ua.py +217 -0
  19. cloud_audit-2.2.1/src/cloud_audit/providers/aws/threat_feed/whoami_confusion.py +230 -0
  20. cloud_audit-2.2.1/tests/aws/threat_feed/__init__.py +0 -0
  21. cloud_audit-2.2.1/tests/aws/threat_feed/test_cloudtrail_tampering.py +159 -0
  22. cloud_audit-2.2.1/tests/aws/threat_feed/test_cryptomining_role.py +169 -0
  23. cloud_audit-2.2.1/tests/aws/threat_feed/test_datazone_overgrant.py +178 -0
  24. cloud_audit-2.2.1/tests/aws/threat_feed/test_lambda_function_url.py +275 -0
  25. cloud_audit-2.2.1/tests/aws/threat_feed/test_mmdsv1_in_use.py +199 -0
  26. cloud_audit-2.2.1/tests/aws/threat_feed/test_quarantine_policy.py +287 -0
  27. cloud_audit-2.2.1/tests/aws/threat_feed/test_roles_anywhere_abuse.py +140 -0
  28. cloud_audit-2.2.1/tests/aws/threat_feed/test_ses_phishing.py +251 -0
  29. cloud_audit-2.2.1/tests/aws/threat_feed/test_trufflehog_ua.py +156 -0
  30. cloud_audit-2.2.1/tests/aws/threat_feed/test_whoami_confusion.py +181 -0
  31. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.cloud-audit.example.yml +0 -0
  32. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.github/FUNDING.yml +0 -0
  33. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  34. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  35. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  36. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.github/dependabot.yml +0 -0
  37. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.github/workflows/ci.yml +0 -0
  38. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.github/workflows/docs.yml +0 -0
  39. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.github/workflows/example-scan.yml +0 -0
  40. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.github/workflows/release.yml +0 -0
  41. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.gitignore +0 -0
  42. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.mcp.json +0 -0
  43. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/.pre-commit-hooks.yaml +0 -0
  44. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/CODEOWNERS +0 -0
  45. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/CODE_OF_CONDUCT.md +0 -0
  46. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/CONTRIBUTING.md +0 -0
  47. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/Dockerfile +0 -0
  48. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/LICENSE +0 -0
  49. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/Makefile +0 -0
  50. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/ROADMAP.md +0 -0
  51. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/SECURITY.md +0 -0
  52. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/action.yml +0 -0
  53. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/assets/demo.gif +0 -0
  54. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/assets/logo-nobg.png +0 -0
  55. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/assets/logo.png +0 -0
  56. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/assets/report-preview.png +0 -0
  57. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/assets/social-preview.png +0 -0
  58. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/examples/daily-scan-with-diff.yml +0 -0
  59. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/examples/github-actions.yml +0 -0
  60. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/examples/post-deploy-scan.yml +0 -0
  61. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/overrides/main.html +0 -0
  62. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/scripts/generate_demo_gif.py +0 -0
  63. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/scripts/generate_report_screenshot.py +0 -0
  64. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/server.json +0 -0
  65. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/__init__.py +0 -0
  66. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/__main__.py +0 -0
  67. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/compliance/__init__.py +0 -0
  68. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/compliance/engine.py +0 -0
  69. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/compliance/frameworks/bsi_c5_2020.json +0 -0
  70. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/compliance/frameworks/cis_aws_v3.json +0 -0
  71. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/compliance/frameworks/hipaa_security.json +0 -0
  72. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/compliance/frameworks/iso27001_2022.json +0 -0
  73. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/compliance/frameworks/nis2_directive.json +0 -0
  74. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/compliance/frameworks/soc2_type2.json +0 -0
  75. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/config.py +0 -0
  76. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/correlate.py +0 -0
  77. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/cost_model.py +0 -0
  78. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/diff.py +0 -0
  79. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/history.py +0 -0
  80. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/mcp_server.py +0 -0
  81. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/__init__.py +0 -0
  82. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/__init__.py +0 -0
  83. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/__init__.py +0 -0
  84. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/account.py +0 -0
  85. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/backup.py +0 -0
  86. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/bedrock.py +0 -0
  87. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/cloudtrail.py +0 -0
  88. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/cloudwatch.py +0 -0
  89. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/config_.py +0 -0
  90. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/ec2.py +0 -0
  91. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/ecs.py +0 -0
  92. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/efs.py +0 -0
  93. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/eip.py +0 -0
  94. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/guardduty.py +0 -0
  95. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/iam.py +0 -0
  96. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/inspector.py +0 -0
  97. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/kms.py +0 -0
  98. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/lambda_.py +0 -0
  99. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/rds.py +0 -0
  100. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/s3.py +0 -0
  101. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/sagemaker.py +0 -0
  102. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/secrets.py +0 -0
  103. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/securityhub.py +0 -0
  104. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/ssm.py +0 -0
  105. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/vpc.py +0 -0
  106. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/checks/waf.py +0 -0
  107. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/iam_analyzer.py +0 -0
  108. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/aws/iam_trust_graph.py +0 -0
  109. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/providers/base.py +0 -0
  110. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/py.typed +0 -0
  111. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/reports/__init__.py +0 -0
  112. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/reports/compliance_html.py +0 -0
  113. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/reports/compliance_markdown.py +0 -0
  114. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/reports/diff_markdown.py +0 -0
  115. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/reports/html.py +0 -0
  116. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/reports/markdown.py +0 -0
  117. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/reports/sarif.py +0 -0
  118. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/reports/templates/report.html.j2 +0 -0
  119. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/root_cause.py +0 -0
  120. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/scanner.py +0 -0
  121. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/src/cloud_audit/simulate.py +0 -0
  122. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/__init__.py +0 -0
  123. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/__init__.py +0 -0
  124. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_bedrock.py +0 -0
  125. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_cis_checks.py +0 -0
  126. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_cloudtrail.py +0 -0
  127. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_cloudwatch.py +0 -0
  128. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_config.py +0 -0
  129. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_ec2.py +0 -0
  130. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_ecs.py +0 -0
  131. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_eip.py +0 -0
  132. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_guardduty.py +0 -0
  133. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_iam.py +0 -0
  134. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_iam_analyzer.py +0 -0
  135. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_iam_trust_graph.py +0 -0
  136. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_kms.py +0 -0
  137. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_lambda.py +0 -0
  138. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_rds.py +0 -0
  139. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_s3.py +0 -0
  140. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_sagemaker.py +0 -0
  141. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_secrets.py +0 -0
  142. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_ssm.py +0 -0
  143. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/aws/test_vpc.py +0 -0
  144. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/conftest.py +0 -0
  145. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_cli.py +0 -0
  146. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_cli_scan.py +0 -0
  147. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_compliance_frameworks.py +0 -0
  148. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_config.py +0 -0
  149. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_correlate.py +0 -0
  150. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_cost_model.py +0 -0
  151. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_diff.py +0 -0
  152. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_history.py +0 -0
  153. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_html.py +0 -0
  154. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_markdown.py +0 -0
  155. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_mcp_server.py +0 -0
  156. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_models.py +0 -0
  157. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_provider.py +0 -0
  158. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_root_cause.py +0 -0
  159. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_sarif.py +0 -0
  160. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_scanner.py +0 -0
  161. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_simulate.py +0 -0
  162. {cloud_audit-2.1.0 → cloud_audit-2.2.1}/tests/test_soc2_framework.py +0 -0
@@ -7,6 +7,121 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.2.1] - 2026-05-12
11
+
12
+ ### Changed
13
+
14
+ - **TF-001 (SES phishing setup)** - severity escalation logic rewritten.
15
+ HIGH now requires BOTH out-of-sandbox AND a burst of >=2 recent
16
+ identity verifications in the same account scan. The previous
17
+ "email identity without matching domain" escalation has been removed:
18
+ it modeled the wrong attacker behaviour. Wiz's September 2025 research
19
+ documented attackers *"adding multiple domains as verified identities
20
+ using the CreateEmailIdentity API"* in quick succession - a burst
21
+ pattern, not a single typosquat email. The new logic matches what
22
+ the source incident actually documented.
23
+
24
+ - **TF-004 (leaked-creds scanner UA)** - removed `cloudgrappler` and
25
+ `detention-dodger` from the user-agent signature list. Both are
26
+ Permiso DEFENSIVE tools - their UA appearing in CloudTrail means a
27
+ defender is running them against the account, not that the account
28
+ is under attack. The detector now only matches OFFENSIVE scanner
29
+ signatures (`trufflehog`, `gitleaks`, `noseyparker`, `secretscanner`).
30
+ Module docstring updated with an explicit detection caveat: scanners
31
+ using stock AWS SDK / boto3 / aws-cli default user-agents look
32
+ identical to legitimate traffic and will not trigger this pattern.
33
+
34
+ - **TF-004 references** - replaced a fabricated TruffleHog blog URL in
35
+ the references list with the verified BleepingComputer / Kaspersky
36
+ May 2026 SES abuse coverage and the official TruffleHog GitHub repo.
37
+
38
+ ### Tests
39
+
40
+ - 742 -> 747 (+5 net). New regression tests:
41
+ - `test_email_no_matching_domain_does_not_escalate` (TF-001) proves
42
+ the removed typosquat heuristic does not return.
43
+ - `test_burst_out_of_sandbox_escalates_to_high` and
44
+ `test_burst_in_sandbox_stays_medium` cover the new escalation rule.
45
+ - `test_burst_only_counts_recent_identities` verifies the burst
46
+ counter respects the 14-day window.
47
+ - `test_cloudgrappler_ua_not_flagged` and
48
+ `test_detention_dodger_ua_not_flagged` (TF-004) prove defensive
49
+ tools are now excluded.
50
+
51
+ ## [2.2.0] - 2026-05-12
52
+
53
+ ### Added
54
+
55
+ - **Threat Feed v1** — new `cloud-audit threat-feed` command and a dedicated
56
+ detector pipeline (`providers/aws/threat_feed/`) that flags ACTIVE abuse
57
+ indicators rather than misconfiguration. Each pattern has a versioned
58
+ `TF-XXX` ID, maps to the new `Category.THREAT`, and carries external
59
+ references (research reports, CVE links) on every Finding for credibility.
60
+ Rules pack version: **2026-Q2**.
61
+
62
+ Ten patterns shipped:
63
+
64
+ - `TF-001-ses-phishing-setup` (MEDIUM/HIGH) — SES email/domain identities
65
+ verified within the last 14 days, with severity escalating when an
66
+ out-of-sandbox account hosts a typosquat-style email identity that has
67
+ no matching domain identity. Tracks the Wiz May 2025 + BleepingComputer
68
+ May 2026 SES abuse campaigns.
69
+ - `TF-002-lambda-function-url-persistence` (HIGH/CRITICAL) — Lambda
70
+ functions exposed via `AuthType=NONE` Function URLs, escalating to
71
+ CRITICAL when the execution role grants admin-class permissions
72
+ (matching the role profile of the Nov-Dec 2025 cryptomining campaign).
73
+ - `TF-003-quarantine-policy` (CRITICAL) — IAM principals with
74
+ `AWSCompromisedKeyQuarantineV1/V2/V3` attached. AWS auto-attaches these
75
+ after detecting credential exposure (typically a public GitHub commit).
76
+ - `TF-004-trufflehog-ua-cloudtrail` (CRITICAL) — `sts:GetCallerIdentity`
77
+ calls in the last 24h whose user-agent matches known leaked-credentials
78
+ discovery scanners (TruffleHog, gitleaks, CloudGrappler, DetentionDodger,
79
+ NoseyParker). Confirmed credential validation by an external scanner.
80
+ - `TF-005-cryptomining-role` (HIGH/CRITICAL) — IAM roles created within
81
+ the last 48 hours that carry broad compute managed policies (EC2 Full,
82
+ PowerUser, Admin, ECS Full, Lambda Full). Escalates to CRITICAL when
83
+ the same role also has SES sending permissions (mining + email-spam
84
+ combo from the documented late-2025 campaign cluster).
85
+ - `TF-006-mmdsv1-in-use` (HIGH/CRITICAL) — EC2 instances where
86
+ `HttpTokens != required` (IMDSv1 still callable) and Bedrock AgentCore
87
+ agents on `metadataVersion=v1` (CRITICAL — addresses Unit 42 'Cracks in
88
+ the Bedrock' research and the Feb 2026 MMDSv2 default).
89
+ - `TF-007-whoami-confusion` (MEDIUM) — IAM roles trusted by CI/CD
90
+ identities (codebuild service principals, GitHub OIDC, GitLab OIDC,
91
+ Buildkite federation) that have a broad EC2 managed policy attached —
92
+ the precondition for the Datadog Feb 2025 whoAMI confusion attack.
93
+ - `TF-008-cloudtrail-tampering` (HIGH/CRITICAL) — CloudTrail trails with
94
+ `IsLogging=False` (CRITICAL — canonical post-credential-theft attacker
95
+ behaviour, AiTM phishing follow-on per Datadog March 2026) or with a
96
+ populated `LatestDeliveryError` (HIGH — S3 destination broken).
97
+ - `TF-009-roles-anywhere-abuse` (HIGH/MEDIUM) — IAM Roles Anywhere trust
98
+ anchors with `sourceType=CERTIFICATE_BUNDLE` instead of the recommended
99
+ AWS_ACM_PCA. Anyone able to issue a chain-valid cert can mint AWS
100
+ credentials (fwd:cloudsec 2025 'Let's Encrypt for AWS Console').
101
+ - `TF-010-datazone-overgrant` (HIGH) — `AmazonDataZoneFullAccess` attached
102
+ to non-admin principals (the "easy" onboarding policy that bridges
103
+ identity, Glue catalog, and S3 storage in a single grant).
104
+
105
+ CLI: `cloud-audit threat-feed [--list] [--pattern <id>] [--regions ...]
106
+ [--profile ...] [--threat-feed-version 2026-Q2]`. Exits 1 when CRITICAL
107
+ or HIGH detected (CI gate friendly). Patterns also surface in standard
108
+ `cloud-audit scan --categories threat` output (JSON, SARIF, HTML).
109
+
110
+ ### Changed
111
+
112
+ - `Category` enum gains `THREAT` value for active-abuse findings (separate
113
+ from `SECURITY` misconfiguration).
114
+ - `Finding` model gains `threat_pattern_id: str | None` and
115
+ `references: list[str]` for backing research links.
116
+ - 23rd registered AWS check module (`threat_feed`) loaded by `AWSProvider`.
117
+
118
+ ### Tests
119
+
120
+ - 638 -> 742 (+104). Each pattern ships 9-12 unit tests covering positive
121
+ detection, negative cases, false-positive guards, severity escalation,
122
+ multi-resource aggregation, AccessDenied resilience, and metadata
123
+ exposure.
124
+
10
125
  ## [2.1.0] - 2026-04-28
11
126
 
12
127
  ### Added
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloud-audit
3
- Version: 2.1.0
4
- Summary: 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.
3
+ Version: 2.2.1
4
+ Summary: Open-source AWS security scanner. Threat Feed v1 (10 active-abuse patterns from 2025-2026 incidents), 64 IAM escalation methods, What-If simulator, security trends, AI-SPM (Bedrock/SageMaker), 6 compliance frameworks, 31 attack chain rules, breach cost estimation, and MCP server. Every finding includes CLI + Terraform remediation.
5
5
  Project-URL: Homepage, https://haitmg.pl/cloud-audit/
6
6
  Project-URL: Documentation, https://haitmg.pl/cloud-audit/
7
7
  Project-URL: Source, https://github.com/gebalamariusz/cloud-audit
@@ -83,6 +83,7 @@ Description-Content-Type: text/markdown
83
83
  <a href="https://haitmg.pl/cloud-audit/compliance/overview/">Compliance</a> -
84
84
  <a href="https://haitmg.pl/cloud-audit/features/attack-chains/">Attack Chains</a> -
85
85
  <a href="https://haitmg.pl/cloud-audit/features/iam-escalation/">IAM Escalation</a> -
86
+ <a href="https://haitmg.pl/cloud-audit/features/threat-feed/">Threat Feed</a> -
86
87
  <a href="https://haitmg.pl/cloud-audit/features/simulate/">Simulator</a> -
87
88
  <a href="https://haitmg.pl/cloud-audit/features/mcp-server/">MCP Server</a>
88
89
  </p>
@@ -100,6 +101,21 @@ Uses your default AWS credentials and region. Try without an AWS account:
100
101
  cloud-audit demo
101
102
  ```
102
103
 
104
+ ### NEW in v2.2: Threat Feed
105
+
106
+ Detect ACTIVE abuse patterns from 2025-2026 incidents (cryptomining campaigns,
107
+ SES phishing setup, leaked-credential scanner activity, AgentCore CVEs):
108
+
109
+ ```bash
110
+ cloud-audit threat-feed # scan all 10 patterns
111
+ cloud-audit threat-feed --list # show registered patterns
112
+ cloud-audit threat-feed --pattern aws-tf-003 # one pattern only
113
+ ```
114
+
115
+ Each pattern carries external research references (Wiz, Datadog Security Labs,
116
+ Unit 42, Permiso) on every finding. Exit code 1 when CRITICAL/HIGH detected
117
+ (CI gate friendly). See [Threat Feed docs](https://haitmg.pl/cloud-audit/features/threat-feed/).
118
+
103
119
  ---
104
120
 
105
121
  ## Why It's Different
@@ -36,6 +36,7 @@
36
36
  <a href="https://haitmg.pl/cloud-audit/compliance/overview/">Compliance</a> -
37
37
  <a href="https://haitmg.pl/cloud-audit/features/attack-chains/">Attack Chains</a> -
38
38
  <a href="https://haitmg.pl/cloud-audit/features/iam-escalation/">IAM Escalation</a> -
39
+ <a href="https://haitmg.pl/cloud-audit/features/threat-feed/">Threat Feed</a> -
39
40
  <a href="https://haitmg.pl/cloud-audit/features/simulate/">Simulator</a> -
40
41
  <a href="https://haitmg.pl/cloud-audit/features/mcp-server/">MCP Server</a>
41
42
  </p>
@@ -53,6 +54,21 @@ Uses your default AWS credentials and region. Try without an AWS account:
53
54
  cloud-audit demo
54
55
  ```
55
56
 
57
+ ### NEW in v2.2: Threat Feed
58
+
59
+ Detect ACTIVE abuse patterns from 2025-2026 incidents (cryptomining campaigns,
60
+ SES phishing setup, leaked-credential scanner activity, AgentCore CVEs):
61
+
62
+ ```bash
63
+ cloud-audit threat-feed # scan all 10 patterns
64
+ cloud-audit threat-feed --list # show registered patterns
65
+ cloud-audit threat-feed --pattern aws-tf-003 # one pattern only
66
+ ```
67
+
68
+ Each pattern carries external research references (Wiz, Datadog Security Labs,
69
+ Unit 42, Permiso) on every finding. Exit code 1 when CRITICAL/HIGH detected
70
+ (CI gate friendly). See [Threat Feed docs](https://haitmg.pl/cloud-audit/features/threat-feed/).
71
+
56
72
  ---
57
73
 
58
74
  ## Why It's Different
@@ -60,6 +60,7 @@ nav:
60
60
  - Features:
61
61
  - Attack Chains: features/attack-chains.md
62
62
  - IAM Privilege Escalation: features/iam-escalation.md
63
+ - Threat Feed: features/threat-feed.md
63
64
  - What-If Simulator: features/simulate.md
64
65
  - Security Posture Trend: features/trend.md
65
66
  - AI-SPM (Bedrock/SageMaker): features/ai-spm.md
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cloud-audit"
7
- version = "2.1.0"
8
- 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."
7
+ version = "2.2.1"
8
+ description = "Open-source AWS security scanner. Threat Feed v1 (10 active-abuse patterns from 2025-2026 incidents), 64 IAM escalation methods, What-If simulator, security trends, AI-SPM (Bedrock/SageMaker), 6 compliance frameworks, 31 attack chain rules, breach cost estimation, and MCP server. Every finding includes CLI + Terraform remediation."
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
11
  requires-python = ">=3.10"
@@ -81,6 +81,13 @@ select = ["E", "F", "I", "N", "W", "UP", "S", "B", "A", "C4", "SIM", "TCH", "RUF
81
81
  "src/cloud_audit/reports/compliance_markdown.py" = ["E501"]
82
82
  "src/cloud_audit/cli.py" = ["TC003"]
83
83
  "src/cloud_audit/mcp_server.py" = ["TC003"]
84
+ # Threat-feed modules and tests intentionally use boto3-style CamelCase
85
+ # kwargs (UserName, RoleName, FunctionName, EmailIdentity) to match the
86
+ # AWS API surface they wrap. N803 (lower_snake_case argument) is wrong here.
87
+ # Inner exception classes used to simulate boto3 errors don't need the
88
+ # Error suffix N818 mandates. Lambda/SES helpers also use Optional implicitly.
89
+ "src/cloud_audit/providers/aws/threat_feed/*.py" = ["N803", "N818", "RUF013", "E501", "S112"]
90
+ "tests/aws/threat_feed/*.py" = ["S101", "N803", "N806", "N818", "RUF013", "E501", "TC003", "E402"]
84
91
  "tests/**" = ["S101", "TC003", "E402"]
85
92
 
86
93
  [tool.mypy]
@@ -1448,6 +1448,145 @@ def simulate(
1448
1448
  console.print()
1449
1449
 
1450
1450
 
1451
+ @app.command(name="threat-feed")
1452
+ def threat_feed_cmd(
1453
+ profile: Annotated[str | None, typer.Option("--profile", help="AWS profile")] = None,
1454
+ regions: Annotated[
1455
+ str | None,
1456
+ typer.Option("--regions", "-r", help="Comma-separated regions, or 'all' for every enabled region"),
1457
+ ] = None,
1458
+ pattern: Annotated[
1459
+ str | None,
1460
+ typer.Option("--pattern", help="Run only one pattern (e.g. aws-tf-003); default = all"),
1461
+ ] = None,
1462
+ list_patterns: Annotated[
1463
+ bool,
1464
+ typer.Option("--list", help="List registered patterns and exit (no scan)"),
1465
+ ] = False,
1466
+ threat_feed_version: Annotated[
1467
+ str | None,
1468
+ typer.Option("--threat-feed-version", help="Pin a rules-pack version (informational, default = current)"),
1469
+ ] = None,
1470
+ ) -> None:
1471
+ """Detect ACTIVE abuse patterns from 2025-2026 threat reports.
1472
+
1473
+ Distinct from regular `scan`: looks for indicators that an attacker has ALREADY
1474
+ acted on the account (quarantine policies AWS attached after credential leak,
1475
+ public Lambda URLs created as persistence, DataZone over-grants, etc.) rather
1476
+ than mere misconfigurations.
1477
+
1478
+ Examples:
1479
+ cloud-audit threat-feed # scan all patterns
1480
+ cloud-audit threat-feed --pattern aws-tf-003 # one pattern only
1481
+ cloud-audit threat-feed --list # show registered patterns
1482
+ """
1483
+ from cloud_audit.providers.aws import threat_feed as tf_module
1484
+
1485
+ if list_patterns:
1486
+ table = Table(title=f"Registered threat patterns (rules pack {tf_module.THREAT_FEED_VERSION})")
1487
+ table.add_column("Pattern ID", style="bold")
1488
+ table.add_column("Check ID")
1489
+ table.add_column("Severity")
1490
+ table.add_column("Name")
1491
+ table.add_column("Doc")
1492
+ for p in tf_module.list_patterns():
1493
+ sev_color = SEVERITY_COLORS.get(Severity(p["severity"]), "white")
1494
+ table.add_row(
1495
+ p["pattern_id"],
1496
+ p["check_id"],
1497
+ f"[{sev_color}]{p['severity'].upper()}[/{sev_color}]",
1498
+ p["name"],
1499
+ p["doc_url"],
1500
+ )
1501
+ console.print(table)
1502
+ console.print(f"\n[dim]{len(tf_module.list_patterns())} patterns registered.[/dim]")
1503
+ return
1504
+
1505
+ active_version = threat_feed_version or tf_module.THREAT_FEED_VERSION
1506
+ if threat_feed_version and threat_feed_version != tf_module.THREAT_FEED_VERSION:
1507
+ console.print(
1508
+ f"[yellow]Note: requested rules pack '{threat_feed_version}' differs from installed "
1509
+ f"'{tf_module.THREAT_FEED_VERSION}'. Pinning is informational in this build.[/yellow]"
1510
+ )
1511
+
1512
+ from cloud_audit.providers.aws.provider import AWSProvider
1513
+
1514
+ region_list = None
1515
+ if regions:
1516
+ region_list = ["all"] if regions.strip() == "all" else [r.strip() for r in regions.split(",")]
1517
+
1518
+ try:
1519
+ provider = AWSProvider(profile=profile, regions=region_list)
1520
+ except Exception as exc:
1521
+ console.print(f"[red]Failed to initialize AWS provider: {exc}[/red]")
1522
+ raise typer.Exit(2) from exc
1523
+
1524
+ threat_checks = [c for c in provider.get_checks() if getattr(c, "category", None) and c.category.value == "threat"]
1525
+ if pattern:
1526
+ threat_checks = [c for c in threat_checks if c.check_id == pattern]
1527
+ if not threat_checks:
1528
+ console.print(f"[red]No registered threat pattern with check_id '{pattern}'.[/red]")
1529
+ console.print("Run [cyan]cloud-audit threat-feed --list[/cyan] to see available patterns.")
1530
+ raise typer.Exit(2)
1531
+
1532
+ console.print(
1533
+ Panel(
1534
+ f"Scanning [bold]{len(threat_checks)}[/bold] threat patterns (rules pack [cyan]{active_version}[/cyan])",
1535
+ title="[bold]Threat Feed[/bold]",
1536
+ border_style="magenta",
1537
+ )
1538
+ )
1539
+
1540
+ all_findings: list[Finding] = []
1541
+ errors: list[tuple[str, str]] = []
1542
+ for check in threat_checks:
1543
+ try:
1544
+ result = check()
1545
+ except Exception as exc: # defensive - check should already capture
1546
+ errors.append((check.check_id, str(exc)))
1547
+ continue
1548
+ if result.error:
1549
+ errors.append((check.check_id, result.error))
1550
+ all_findings.extend(result.findings)
1551
+
1552
+ if errors:
1553
+ console.print()
1554
+ for check_id, err in errors:
1555
+ console.print(f"[yellow]! {check_id}: {err}[/yellow]")
1556
+
1557
+ if not all_findings:
1558
+ console.print("\n[green]No active abuse patterns detected.[/green]\n")
1559
+ raise typer.Exit(0)
1560
+
1561
+ table = Table(title=f"Detected threat patterns ({len(all_findings)} findings)", show_lines=True)
1562
+ table.add_column("Severity", no_wrap=True)
1563
+ table.add_column("Pattern", style="bold")
1564
+ table.add_column("Resource")
1565
+ table.add_column("Region")
1566
+ table.add_column("References")
1567
+
1568
+ for f in sorted(all_findings, key=lambda x: list(SEVERITY_COLORS).index(x.severity)):
1569
+ sev_color = SEVERITY_COLORS[f.severity]
1570
+ refs = "\n".join(f.references[:2]) if f.references else "-"
1571
+ table.add_row(
1572
+ f"[{sev_color}]{f.severity.value.upper()}[/{sev_color}]",
1573
+ f"{f.threat_pattern_id or f.check_id}\n[dim]{rich_escape(f.title)}[/dim]",
1574
+ rich_escape(f.resource_id),
1575
+ f.region,
1576
+ refs,
1577
+ )
1578
+
1579
+ console.print(table)
1580
+ console.print(
1581
+ "\n[dim]Use [cyan]cloud-audit scan --categories threat -o json[/cyan] for machine-readable output "
1582
+ "(includes full remediation + references).[/dim]\n"
1583
+ )
1584
+
1585
+ # Exit 1 when CRITICAL/HIGH detected (CI gate)
1586
+ blocking = [f for f in all_findings if f.severity in (Severity.CRITICAL, Severity.HIGH)]
1587
+ raise typer.Exit(1 if blocking else 0)
1588
+
1589
+
1451
1590
  @app.command()
1452
1591
  def version() -> None:
1453
1592
  """Show version."""
@@ -22,6 +22,7 @@ class Category(str, Enum):
22
22
  COST = "cost"
23
23
  RELIABILITY = "reliability"
24
24
  PERFORMANCE = "performance"
25
+ THREAT = "threat"
25
26
 
26
27
 
27
28
  class Effort(str, Enum):
@@ -75,6 +76,14 @@ class Finding(BaseModel):
75
76
  remediation: Remediation | None = Field(default=None, description="Structured remediation details")
76
77
  compliance_refs: list[str] = Field(default_factory=list, description="Compliance references, e.g. ['CIS 1.5']")
77
78
  cost_estimate: CostEstimateData | None = Field(default=None, description="Estimated breach cost range")
79
+ threat_pattern_id: str | None = Field(
80
+ default=None,
81
+ description="Threat feed pattern identifier, e.g. 'TF-003-quarantine-policy' (None for regular checks)",
82
+ )
83
+ references: list[str] = Field(
84
+ default_factory=list,
85
+ description="External references (research reports, CVE links, blog posts) backing this finding",
86
+ )
78
87
 
79
88
 
80
89
  class CheckResult(BaseModel):
@@ -8,6 +8,7 @@ from typing import TYPE_CHECKING, Any
8
8
  import boto3
9
9
  from botocore.config import Config
10
10
 
11
+ from cloud_audit.providers.aws import threat_feed
11
12
  from cloud_audit.providers.aws.checks import (
12
13
  account,
13
14
  backup,
@@ -65,6 +66,7 @@ _CHECK_MODULES = [
65
66
  waf,
66
67
  bedrock,
67
68
  sagemaker,
69
+ threat_feed,
68
70
  ]
69
71
 
70
72
 
@@ -0,0 +1,105 @@
1
+ """Threat Feed - active abuse pattern detectors.
2
+
3
+ Each pattern in this package detects an attack technique observed in real-world
4
+ 2025-2026 incidents (cryptomining campaigns, SES phishing, leaked credentials,
5
+ AgentCore vulnerabilities). Patterns are versioned via THREAT_FEED_VERSION so
6
+ operators can pin a known rules pack.
7
+
8
+ Patterns vs regular checks:
9
+ - Regular checks (providers/aws/checks/) detect MISCONFIGURATION
10
+ - Threat patterns (this package) detect ACTIVE ABUSE INDICATORS or
11
+ conditions an attacker exploited in a documented incident.
12
+
13
+ Each pattern produces standard Finding objects with:
14
+ - category=Category.THREAT
15
+ - threat_pattern_id="TF-XXX-name"
16
+ - references=[<URL to research report or CVE>]
17
+
18
+ Adding a new pattern:
19
+ 1. Create src/cloud_audit/providers/aws/threat_feed/<name>.py
20
+ 2. Implement: def detect(provider) -> CheckResult
21
+ 3. Register in _PATTERN_MODULES below
22
+ 4. Add tests in tests/aws/threat_feed/test_<name>.py
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ from typing import TYPE_CHECKING
28
+
29
+ from cloud_audit.models import Category
30
+ from cloud_audit.providers.aws.threat_feed import (
31
+ cloudtrail_tampering,
32
+ cryptomining_role,
33
+ datazone_overgrant,
34
+ lambda_function_url,
35
+ mmdsv1_in_use,
36
+ quarantine_policy,
37
+ roles_anywhere_abuse,
38
+ ses_phishing,
39
+ trufflehog_ua,
40
+ whoami_confusion,
41
+ )
42
+ from cloud_audit.providers.base import make_check
43
+
44
+ if TYPE_CHECKING:
45
+ from cloud_audit.providers.aws.provider import AWSProvider
46
+ from cloud_audit.providers.base import CheckFn
47
+
48
+ THREAT_FEED_VERSION = "2026-Q2"
49
+ """Versioned rules pack identifier - bump when patterns added/removed/changed.
50
+
51
+ Operators pin via `cloud-audit threat-feed --threat-feed-version 2026-Q2`
52
+ to get reproducible scans across releases.
53
+ """
54
+
55
+ _PATTERN_MODULES = [
56
+ ses_phishing,
57
+ lambda_function_url,
58
+ quarantine_policy,
59
+ trufflehog_ua,
60
+ cryptomining_role,
61
+ mmdsv1_in_use,
62
+ whoami_confusion,
63
+ cloudtrail_tampering,
64
+ roles_anywhere_abuse,
65
+ datazone_overgrant,
66
+ ]
67
+ """Registry of all threat feed pattern modules.
68
+
69
+ Order matters for output stability - keep it deterministic.
70
+ New patterns: append to the end so existing TF-IDs remain stable.
71
+ """
72
+
73
+
74
+ def get_checks(provider: AWSProvider) -> list[CheckFn]:
75
+ """Return all threat feed pattern check functions bound to the provider.
76
+
77
+ Each pattern module exposes:
78
+ - detect(provider) -> CheckResult
79
+ - PATTERN_ID: str (e.g. "TF-003-quarantine-policy")
80
+ - CHECK_ID: str (e.g. "aws-tf-003")
81
+ """
82
+ checks: list[CheckFn] = []
83
+ for module in _PATTERN_MODULES:
84
+ check = make_check(
85
+ module.detect,
86
+ provider,
87
+ check_id=module.CHECK_ID,
88
+ category=Category.THREAT,
89
+ )
90
+ checks.append(check)
91
+ return checks
92
+
93
+
94
+ def list_patterns() -> list[dict[str, str]]:
95
+ """Return metadata for all registered patterns - used by CLI list/help."""
96
+ return [
97
+ {
98
+ "pattern_id": m.PATTERN_ID,
99
+ "check_id": m.CHECK_ID,
100
+ "name": m.PATTERN_NAME,
101
+ "severity": m.PATTERN_SEVERITY.value,
102
+ "doc_url": m.DOC_URL,
103
+ }
104
+ for m in _PATTERN_MODULES
105
+ ]