@blamejs/exceptd-skills 0.12.27 → 0.12.28

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.
@@ -0,0 +1,1351 @@
1
+ {
2
+ "_meta": {
3
+ "id": "cloud-iam-incident",
4
+ "version": "1.0.0",
5
+ "last_threat_review": "2026-05-15",
6
+ "threat_currency_score": 94,
7
+ "changelog": [
8
+ {
9
+ "version": "1.0.0",
10
+ "date": "2026-05-15",
11
+ "summary": "Initial seven-phase cloud-IAM incident-response playbook covering AWS / GCP / Azure account takeover, IAM role assumption abuse, access-key compromise, cross-account assume-role chains, federated-trust attacks (IAM Identity Center / AWS SSO, Azure managed identity, GCP Workload Identity Federation), and IMDS v1 metadata abuse. Walks cloud audit logs (CloudTrail / Cloud Audit Logs / Activity Logs), IAM principal inventory, recently-issued access keys, cross-account assume-role events, federated identity provider configuration, IMDS access patterns, SCP / Org Policy / Management Group state, KMS / S3 / bucket-policy modifications, and billing anomalies (crypto-mining signal). Closes the GRC loop with cloud-IAM-specific framework-gap mapping + multi-jurisdiction notification drafts.",
12
+ "framework_gaps_updated": [
13
+ "FedRAMP-IL5-IAM-Federated",
14
+ "CISA-Snowflake-AA24-IdP-Cloud",
15
+ "NIST-800-53-AC-2-Cross-Account",
16
+ "ISO-27017-Cloud-IAM",
17
+ "SOC2-CC6-Access-Key-Leak-Public-Repo",
18
+ "AWS-Security-Hub-Coverage-Gap",
19
+ "UK-CAF-B2-Cloud-IAM",
20
+ "AU-ISM-1546-Cloud-Service-Account"
21
+ ]
22
+ }
23
+ ],
24
+ "owner": "@blamejs/grc",
25
+ "air_gap_mode": false,
26
+ "scope": "service",
27
+ "preconditions": [
28
+ {
29
+ "id": "csp-audit-log-api-reachable",
30
+ "description": "Cloud provider audit-log API (AWS CloudTrail Lookup / GCP Cloud Audit Logs API / Azure Activity Log API) must be reachable from the host AI's execution environment. The runner reads these APIs to materialise the look phase artifacts.",
31
+ "check": "csp_audit_log_api_reachable == true",
32
+ "on_fail": "halt"
33
+ },
34
+ {
35
+ "id": "iam-read-only-access",
36
+ "description": "Investigator must hold IAM read-only equivalent (AWS IAMReadOnlyAccess / GCP roles/iam.securityReviewer / Azure Reader + User Access Administrator-read) on every account in scope. Write access is explicitly NOT required and not desired during the look/detect phases.",
37
+ "check": "iam_read_only_access == true",
38
+ "on_fail": "halt"
39
+ },
40
+ {
41
+ "id": "account-ownership",
42
+ "description": "Operator owns the cloud account(s) being investigated or holds explicit written authorisation from the account owner. Querying audit logs on a third-party tenant without authorisation is a CFAA / Computer Misuse Act / equivalent violation regardless of intent.",
43
+ "check": "operator_owns_account == true OR written_authorisation_on_file == true",
44
+ "on_fail": "halt"
45
+ }
46
+ ],
47
+ "mutex": [],
48
+ "feeds_into": [
49
+ {
50
+ "playbook_id": "cred-stores",
51
+ "condition": "analyze.blast_radius_score >= 4"
52
+ },
53
+ {
54
+ "playbook_id": "framework",
55
+ "condition": "analyze.compliance_theater_check.verdict == 'theater'"
56
+ },
57
+ {
58
+ "playbook_id": "sbom",
59
+ "condition": "compromised_account_has_published_assets == true"
60
+ }
61
+ ]
62
+ },
63
+ "domain": {
64
+ "name": "Cloud IAM account takeover, key compromise, and federated-trust abuse",
65
+ "attack_class": "identity-abuse",
66
+ "atlas_refs": [
67
+ "AML.T0051"
68
+ ],
69
+ "attack_refs": [
70
+ "T1078.004",
71
+ "T1098.001",
72
+ "T1552.005",
73
+ "T1580",
74
+ "T1538",
75
+ "T1078"
76
+ ],
77
+ "cve_refs": [
78
+ "CVE-2024-1709",
79
+ "CVE-2024-21626",
80
+ "CVE-2024-3094",
81
+ "CVE-2026-20182",
82
+ "CVE-2026-30623"
83
+ ],
84
+ "cwe_refs": [
85
+ "CWE-287",
86
+ "CWE-522",
87
+ "CWE-798",
88
+ "CWE-863",
89
+ "CWE-732",
90
+ "CWE-269"
91
+ ],
92
+ "d3fend_refs": [
93
+ "D3-MFA",
94
+ "D3-CBAN",
95
+ "D3-NTA",
96
+ "D3-IOPR",
97
+ "D3-CAA"
98
+ ],
99
+ "frameworks_in_scope": [
100
+ "nist-800-53",
101
+ "iso-27001-2022",
102
+ "soc2",
103
+ "nis2",
104
+ "dora",
105
+ "uk-caf",
106
+ "au-ism",
107
+ "au-essential-8",
108
+ "hipaa",
109
+ "pci-dss-4"
110
+ ]
111
+ },
112
+ "phases": {
113
+ "govern": {
114
+ "jurisdiction_obligations": [
115
+ {
116
+ "jurisdiction": "EU",
117
+ "regulation": "GDPR Art.33",
118
+ "obligation": "notify_regulator",
119
+ "window_hours": 72,
120
+ "clock_starts": "detect_confirmed",
121
+ "evidence_required": [
122
+ "compromised_principal_inventory",
123
+ "data_subject_impact_assessment",
124
+ "containment_record"
125
+ ]
126
+ },
127
+ {
128
+ "jurisdiction": "EU",
129
+ "regulation": "GDPR Art.34",
130
+ "obligation": "notify_affected_individuals",
131
+ "window_hours": 72,
132
+ "clock_starts": "analyze_complete",
133
+ "evidence_required": [
134
+ "data_subject_categories_affected",
135
+ "containment_record"
136
+ ]
137
+ },
138
+ {
139
+ "jurisdiction": "EU",
140
+ "regulation": "NIS2 Art.23",
141
+ "obligation": "notify_regulator",
142
+ "window_hours": 24,
143
+ "clock_starts": "detect_confirmed",
144
+ "evidence_required": [
145
+ "compromised_principal_inventory",
146
+ "exposure_window_estimate",
147
+ "rotation_status"
148
+ ]
149
+ },
150
+ {
151
+ "jurisdiction": "EU",
152
+ "regulation": "DORA Art.19",
153
+ "obligation": "notify_regulator",
154
+ "window_hours": 4,
155
+ "clock_starts": "detect_confirmed",
156
+ "evidence_required": [
157
+ "major_ict_incident_classification",
158
+ "affected_critical_or_important_function",
159
+ "initial_containment_record"
160
+ ]
161
+ },
162
+ {
163
+ "jurisdiction": "UK",
164
+ "regulation": "UK GDPR Art.33",
165
+ "obligation": "notify_regulator",
166
+ "window_hours": 72,
167
+ "clock_starts": "detect_confirmed",
168
+ "evidence_required": [
169
+ "compromised_principal_inventory",
170
+ "data_subject_impact_assessment"
171
+ ]
172
+ },
173
+ {
174
+ "jurisdiction": "US-CA",
175
+ "regulation": "CCPA / CPRA Sec.1798.82",
176
+ "obligation": "notify_affected_individuals",
177
+ "window_hours": 1440,
178
+ "clock_starts": "analyze_complete",
179
+ "evidence_required": [
180
+ "california_resident_records_affected",
181
+ "containment_record"
182
+ ]
183
+ },
184
+ {
185
+ "jurisdiction": "US-NY",
186
+ "regulation": "23 NYCRR 500.17 cyber event notification",
187
+ "obligation": "notify_regulator",
188
+ "window_hours": 72,
189
+ "clock_starts": "detect_confirmed",
190
+ "evidence_required": [
191
+ "cyber_event_classification",
192
+ "ciso_acknowledgement"
193
+ ]
194
+ },
195
+ {
196
+ "jurisdiction": "AU",
197
+ "regulation": "Privacy Act 1988 — Notifiable Data Breaches scheme (s26WK)",
198
+ "obligation": "notify_regulator",
199
+ "window_hours": 720,
200
+ "clock_starts": "analyze_complete",
201
+ "evidence_required": [
202
+ "compromised_principal_inventory",
203
+ "australian_resident_records_affected",
204
+ "remediation_completed_evidence"
205
+ ]
206
+ },
207
+ {
208
+ "jurisdiction": "JP",
209
+ "regulation": "APPI Art.26",
210
+ "obligation": "notify_regulator",
211
+ "window_hours": 24,
212
+ "clock_starts": "detect_confirmed",
213
+ "evidence_required": [
214
+ "compromised_principal_inventory",
215
+ "japanese_resident_records_affected"
216
+ ]
217
+ },
218
+ {
219
+ "jurisdiction": "SG",
220
+ "regulation": "PDPA Notification Obligation s26D",
221
+ "obligation": "notify_regulator",
222
+ "window_hours": 72,
223
+ "clock_starts": "analyze_complete",
224
+ "evidence_required": [
225
+ "singapore_resident_records_affected",
226
+ "containment_record"
227
+ ]
228
+ }
229
+ ],
230
+ "theater_fingerprints": [
231
+ {
232
+ "pattern_id": "scp-as-prevention",
233
+ "claim": "We have Service Control Policies / Org Policies / Management Group policies — account compromise has bounded blast radius.",
234
+ "fast_detection_test": "List the most recent 90 days of `AssumeRole` / `AssumeRoleWithSAML` / `AssumeRoleWithWebIdentity` events that succeeded against SCP-restricted accounts. SCPs constrain principals within the account but do not block cross-account assume-role chains initiated from a compromised principal in an account where the SCP allows broad role assumption. Count assume-role chains that crossed >= 2 account boundaries within 24h of a single source principal — SCPs do not see this pattern.",
235
+ "implicated_controls": [
236
+ "nist-800-53-AC-2",
237
+ "iso-27001-2022-A.5.18",
238
+ "soc2-cc6.1"
239
+ ]
240
+ },
241
+ {
242
+ "pattern_id": "root-mfa-as-identity-hygiene",
243
+ "claim": "Root accounts have MFA enabled — identity hygiene is complete.",
244
+ "fast_detection_test": "Inventory every IAM user, service account, managed identity, and federated principal in the tenant. Count those with active long-lived access keys (last_used <= 90 days) AND no MFA on the underlying principal. Root MFA is a 1-of-N control; the dominant 2024-2026 compromise vector is long-lived access keys on non-root IAM users (Snowflake-class AA24 advisory) and stolen federated SAML assertions, neither of which root MFA touches.",
245
+ "implicated_controls": [
246
+ "nist-800-53-AC-2",
247
+ "iso-27001-2022-A.5.15",
248
+ "au-ism-1546"
249
+ ]
250
+ },
251
+ {
252
+ "pattern_id": "security-hub-green-as-secure",
253
+ "claim": "AWS Security Hub / GCP Security Command Center / Azure Defender for Cloud is all-green — the account is secure.",
254
+ "fast_detection_test": "Each CSP-native posture tool is coverage-based, not breach-detection. Diff the Security Hub findings inventory against (a) GuardDuty / Cloud IDS / Defender findings, (b) CloudTrail anomaly indicators (root login from new ASN, mass IAM user creation outside IaC, unused-region resource creation), (c) billing anomalies. Any divergence between 'green posture score' and 'open behavioural anomaly' means the green score is a coverage attestation, not a security attestation.",
255
+ "implicated_controls": [
256
+ "soc2-cc7.2",
257
+ "iso-27001-2022-A.8.16",
258
+ "nist-800-53-SI-4"
259
+ ]
260
+ },
261
+ {
262
+ "pattern_id": "access-analyzer-as-detective",
263
+ "claim": "IAM Access Analyzer / GCP Policy Analyzer / Azure Access Reviews catches anomalous IAM grants.",
264
+ "fast_detection_test": "Access Analyzer is a static-analysis tool that flags resource-policy reachability from external principals; it does not detect the IAM principal-side actions that precede a public grant (the attacker creating their own access key on a compromised user; the attacker assuming a role into a target account via legitimate SAML). Show 90 days of Access Analyzer findings AND 90 days of CloudTrail `CreateAccessKey` events outside the org's IaC apply window. Any CreateAccessKey event that Access Analyzer does not surface is a detection gap, not a tool failure.",
265
+ "implicated_controls": [
266
+ "nist-800-53-AC-6",
267
+ "soc2-cc6.3",
268
+ "iso-27001-2022-A.5.18"
269
+ ]
270
+ },
271
+ {
272
+ "pattern_id": "oidc-ci-as-no-static-keys",
273
+ "claim": "We use OIDC federation for CI (GitHub Actions / GitLab / CircleCI) — there are no static cloud credentials in the org.",
274
+ "fast_detection_test": "OIDC federation eliminates static keys on the CI side but creates a federated-trust attack surface (audience claim manipulation, branch-condition bypass, repo:* wildcard trust). Inventory every IAM role with a trust policy referencing token.actions.githubusercontent.com (or GitLab / CircleCI equivalent). Count those with (a) wildcard `repo:*` subject claim, (b) no `:ref:refs/heads/main` constraint, (c) audience set to `sts.amazonaws.com` (default). Each is a fork-PR-to-takeover primitive that the 'no static keys' attestation does not cover.",
275
+ "implicated_controls": [
276
+ "nist-800-53-AC-2",
277
+ "soc2-cc6.1",
278
+ "uk-caf-b2"
279
+ ]
280
+ }
281
+ ],
282
+ "framework_context": {
283
+ "gap_summary": "Cloud-IAM frameworks (NIST 800-53 AC-2 Account Management, ISO/IEC 27017 cloud-services controls, SOC 2 CC6 logical-access criteria, FedRAMP IL5 baseline, AWS Security Hub control library, GCP CIS, Azure Security Benchmark) target conventional account lifecycle and resource-policy posture. They were authored against single-account, single-principal models. The dominant 2024-2026 cloud-account-compromise vectors — cross-account assume-role chains initiated from a compromised principal, federated SAML / OIDC trust abuse, long-lived access-key exfiltration from public repositories, managed-identity token replay against the metadata API — are session-based and cross-boundary. Account-lifecycle controls cannot see them. CISA's Snowflake AA24 advisory (June 2024) documented the third-party-IdP-to-cloud-IAM credential reuse chain as a class of compromise; no framework names this chain as a distinct control class. FedRAMP IL5 baseline assumes single-cloud-tenant deployments and does not contemplate federated IL6 sovereign-cloud trust patterns. UK CAF Principle B2 (Identity and Access Control) is outcome-based on credential lifecycle and treats cloud-IAM as a sub-case of conventional IAM. AU ISM-1546 covers MFA on privileged human users; cloud service-account access keys (which now hold the actual operational privileges) are out of scope. SCOPE: this playbook investigates a specific cloud account (or account-set) for IAM-compromise indicators in CloudTrail / Cloud Audit Logs / Activity Logs over the last 90 days, plus current IAM-principal posture (long-lived keys, federated trust configuration, SCP/Org-Policy state, recently-modified resource policies).",
284
+ "lag_score": 60,
285
+ "per_framework_gaps": [
286
+ {
287
+ "framework": "nist-800-53",
288
+ "control_id": "AC-2",
289
+ "designed_for": "Account Management — establish, activate, modify, review, disable, and remove accounts.",
290
+ "insufficient_because": "AC-2 lifecycle controls assume the principal lives within a single security boundary. Cross-account assume-role abuse uses legitimate principals in legitimate states — every assume-role event in the chain is a valid AC-2-compliant action by an AC-2-compliant principal. The compromise is the chain, not any individual link. AC-2 has no concept of chain-of-assumptions monitoring."
291
+ },
292
+ {
293
+ "framework": "iso-27001-2022",
294
+ "control_id": "A.5.15",
295
+ "designed_for": "Access control — rules for physical and logical access established and reviewed.",
296
+ "insufficient_because": "A.5.15 governs the access-rules baseline. Federated trust configurations (SAML / OIDC / Workload Identity Federation) are technically access rules but their security depends on claim-validation and trust-policy condition specificity that A.5.15 does not enumerate. Audit evidence is a documented access policy + periodic review; neither catches a wildcard `repo:*` OIDC trust policy."
297
+ },
298
+ {
299
+ "framework": "iso-27001-2022",
300
+ "control_id": "A.5.23",
301
+ "designed_for": "Information security for use of cloud services — processes for acquisition, use, management, and exit.",
302
+ "insufficient_because": "Generic cloud-services control. Does not enumerate provider-specific IAM constructs (cross-account role assumption, managed-identity tokens, IMDS access patterns). Evidence is typically a cloud-provider risk assessment, not behavioural telemetry."
303
+ },
304
+ {
305
+ "framework": "soc2",
306
+ "control_id": "CC6.1",
307
+ "designed_for": "Logical access controls — restrict logical access to data and system resources.",
308
+ "insufficient_because": "Authentication-shaped. Treats the authenticated session as the access boundary. Access keys leaked to public repositories produce fully-authenticated sessions; CC6.1 evidence is satisfied regardless. Captured in `data/framework-control-gaps.json#SOC2-CC6-Access-Key-Leak-Public-Repo`."
309
+ },
310
+ {
311
+ "framework": "soc2",
312
+ "control_id": "CC6.3",
313
+ "designed_for": "Logical and physical access — managing access throughout the entire access lifecycle.",
314
+ "insufficient_because": "Lifecycle-focused. Audit evidence is the access-review cadence (typically quarterly). The dominant cloud-IAM compromise window is hours-to-days; quarterly review cannot close it."
315
+ },
316
+ {
317
+ "framework": "uk-caf",
318
+ "control_id": "B2 — Identity and Access Control",
319
+ "designed_for": "NCSC CAF outcome that access to networks and information systems is controlled in line with the essential function's risk.",
320
+ "insufficient_because": "Outcome-based on credential-lifecycle hygiene. Cloud-IAM specifics (federated trust, cross-account assume-role chains, managed-identity tokens) are not enumerated against B2 evidence. Captured in `data/framework-control-gaps.json#UK-CAF-B2-Cloud-IAM`."
321
+ },
322
+ {
323
+ "framework": "au-ism",
324
+ "control_id": "ISM-1546",
325
+ "designed_for": "Multi-factor authentication for privileged users and remote access.",
326
+ "insufficient_because": "ISM-1546 covers human-principal authentication. Cloud service-account access keys, IAM-role assume-role chains initiated by service principals, and managed-identity tokens never cross the human-MFA gate. Captured in `data/framework-control-gaps.json#AU-ISM-1546-Cloud-Service-Account`."
327
+ },
328
+ {
329
+ "framework": "au-essential-8",
330
+ "control_id": "Strategy 4 — Multi-factor authentication (E8 M.4)",
331
+ "designed_for": "MFA on privileged + internet-facing accounts.",
332
+ "insufficient_because": "MFA defends interactive auth. Cloud access keys, OIDC federation tokens, and SAML assertions are bearer credentials that bypass MFA entirely once issued. Compliance-theater test: count the last 90 days of admin-equivalent cloud actions executed by service-principal tokens vs human-MFA sessions — if service tokens dominate (typical for IaC-managed accounts), Strategy 4 compliance is paper for cloud-IAM scope."
333
+ },
334
+ {
335
+ "framework": "nis2",
336
+ "control_id": "Art.21(2)(d) — supply chain security",
337
+ "designed_for": "Risk management measures including supply-chain security and the relationships between entities and direct suppliers / service providers.",
338
+ "insufficient_because": "NIS2 names cloud-service providers as supply-chain dependencies and requires risk-management measures, but does not enumerate cloud-IAM trust-policy hygiene as a sub-control. Federated trust between an entity's IdP and its cloud provider is in scope conceptually; the specific gap (wildcard subject claims, audience-only validation) is not enumerated."
339
+ },
340
+ {
341
+ "framework": "dora",
342
+ "control_id": "Art.6-9 ICT risk-management framework",
343
+ "designed_for": "ICT risk-management framework for financial entities including identification, protection, detection, response, and recovery.",
344
+ "insufficient_because": "Principle-based. Cloud-IAM specifics are not enumerated in the binding articles; ESAs may publish Level-2/3 guidance over time. Audit evidence is the ICT risk-management framework documentation; behavioural telemetry on cloud-IAM is not a binding sub-requirement."
345
+ }
346
+ ]
347
+ },
348
+ "skill_preload": [
349
+ "cloud-security",
350
+ "cred-stores",
351
+ "incident-response-playbook",
352
+ "identity-assurance",
353
+ "framework-gap-analysis",
354
+ "compliance-theater"
355
+ ]
356
+ },
357
+ "direct": {
358
+ "threat_context": "Cloud-IAM compromise is the dominant 2024-2026 cloud-breach root cause across all three major hyperscalers. Reference cases driving this playbook: (1) Snowflake customer-credential compromises (CISA advisory AA24-174A, June 2024) hit AT&T, Ticketmaster, Santander, Advance Auto Parts, Neiman Marcus, LendingTree, Pure Storage — pattern was stolen Okta/SSO credentials reused against the customer's Snowflake tenant, lateral movement into the AWS/Azure/GCP estate where the same federated IdP held cloud trust. (2) 2024-2025 AWS-key-in-public-repo crypto-mining campaigns: scraper bots monetize within ~5 minutes of public exposure, typical spend is 50-500 USD/hour of GPU instances in unused regions. (3) 2026 Azure managed-identity token-replay against the IMDS endpoint (CVE-2026-21370 advisory-adjacent class) — attackers with limited code execution on an Azure VM steal the managed-identity token from 169.254.169.254 and use it from an attacker-controlled endpoint within the token's TTL. (4) Scattered Spider AWS-MFA-bypass via help-desk social engineering (continuous 2023-2026): voice-clone or SE'd help-desk agent resets MFA, attacker logs in, escalates by creating their own IAM user with AdministratorAccess. (5) IMDS v1 to v2 transition incidents — instances still on IMDSv1 are queried by SSRF / metadata-exfil primitives, the cloud-provider warnings to migrate are 18 months old and migration is incomplete in most large estates. (6) Federated-trust attacks: GitHub Actions OIDC trust policies with wildcard `repo:*` subject claims allow any fork PR's workflow to assume the role; AWS SSO / IAM Identity Center misconfigured permission sets granting Org-Admin via SAML assertion replay; Azure AD application impersonation via expired-cert reuse. Mid-2026 reality: any cloud-IAM compromise must assume cross-account assume-role chains by default, federated-trust as the dominant lateral-movement primitive, and managed-identity tokens as the dominant first-stage credential.",
359
+ "rwep_threshold": {
360
+ "escalate": 90,
361
+ "monitor": 70,
362
+ "close": 30
363
+ },
364
+ "framework_lag_declaration": "NIST 800-53 AC-2 (Account Management) does not model cross-account assume-role chains — each link is a valid AC-2-compliant action; the compromise is the chain. ISO/IEC 27001:2022 A.5.15-A.5.18 cover account lifecycle, not session-based IAM observability. ISO/IEC 27017 cloud-specific controls (A.5.23 equivalent) lag on managed-identity token replay — A.9.2.1 'Managing user registration and de-registration' and Annex A cloud controls do not enumerate token-binding to instance identity. SOC 2 CC6 logical-access criteria treat the authenticated session as the access boundary; access-key-leak-to-public-repo produces a fully-authenticated session whose CC6 evidence is satisfied. CISA's Snowflake AA24 advisory documented the third-party-IdP-to-cloud-IAM credential-reuse chain as a class; no framework names this chain as a distinct control class — captured in `data/framework-control-gaps.json#CISA-Snowflake-AA24-IdP-Cloud`. AWS Security Hub / GCP Security Command Center / Azure Defender for Cloud are coverage-based posture tools, not breach detection; 'all green' attestations have ~0 correlation with absence of behavioural anomalies (captured in `data/framework-control-gaps.json#AWS-Security-Hub-Coverage-Gap`). UK CAF Principle B2 is outcome-based on credential-lifecycle hygiene and lacks cloud-IAM specificity (captured in `UK-CAF-B2-Cloud-IAM`). AU Essential 8 ML2 Strategy 4 (MFA) covers human MFA; cloud service-account access keys, OIDC federation tokens, SAML assertions are bearer credentials that bypass MFA entirely (captured in `AU-ISM-1546-Cloud-Service-Account`). FedRAMP IL5 baseline is insufficient for federated cloud / IL6 sovereign-trust patterns (captured in `FedRAMP-IL5-IAM-Federated`). CIS Controls v8 align conceptually but lack a cloud-specific maturity ladder. PCI DSS 4.0 Req.7-8 cover access-control objectives generically; cloud-IAM-specific requirements are not enumerated. Practical gap = ~90 days between audit-cycle evidence (quarterly access review) and adversary timeline (hours-to-days). Every framework in scope assumes the audit cadence; the threat model assumes continuous behavioural monitoring.",
365
+ "skill_chain": [
366
+ {
367
+ "skill": "cloud-security",
368
+ "purpose": "Cloud-provider-specific IAM construct inventory and trust-policy hygiene assessment (AWS IAM + STS, GCP IAM + Workload Identity Federation, Azure AD + managed identities).",
369
+ "required": true
370
+ },
371
+ {
372
+ "skill": "cred-stores",
373
+ "purpose": "Cloud-provider key-store posture (KMS / Cloud KMS / Key Vault) and access-key rotation hygiene; cross-walk with credential-store playbook for any compromised principal whose blast radius >= 4.",
374
+ "required": true
375
+ },
376
+ {
377
+ "skill": "identity-assurance",
378
+ "purpose": "AAL/IAL/FAL assessment of human-principal MFA posture, federated-identity assurance levels, and step-up authentication coverage on cloud admin actions.",
379
+ "required": true
380
+ },
381
+ {
382
+ "skill": "framework-gap-analysis",
383
+ "purpose": "Map findings to which framework controls claim to address cloud-IAM hygiene and where the gap is (NIST AC-2 cross-account, ISO 27017, SOC 2 CC6, FedRAMP IL5, UK CAF B2, AU ISM-1546).",
384
+ "required": true
385
+ },
386
+ {
387
+ "skill": "compliance-theater",
388
+ "purpose": "Run the theater tests on SCPs / root MFA / Security Hub green / Access Analyzer / OIDC-CI attestations.",
389
+ "required": true
390
+ },
391
+ {
392
+ "skill": "incident-response-playbook",
393
+ "purpose": "Multi-jurisdiction notification orchestration (GDPR Art.33 72h, NIS2 24h, DORA 4h, NYDFS 72h, APRA / MAS / PDPA / APPI windows) plus CSP-specific support-ticket drafting (AWS Health Dashboard, GCP support case, Azure Service Health).",
394
+ "required": true
395
+ },
396
+ {
397
+ "skill": "policy-exception-gen",
398
+ "purpose": "Generate auditor-ready exception language for any cloud-IAM remediation that cannot complete within the obligation window (e.g. coordinated rotation across 100+ federated principals).",
399
+ "skip_if": "close.exception_generation.trigger_condition == false",
400
+ "required": false
401
+ }
402
+ ],
403
+ "token_budget": {
404
+ "estimated_total": 22000,
405
+ "breakdown": {
406
+ "govern": 3000,
407
+ "direct": 2000,
408
+ "look": 3000,
409
+ "detect": 3500,
410
+ "analyze": 4500,
411
+ "validate": 3500,
412
+ "close": 2500
413
+ }
414
+ }
415
+ },
416
+ "look": {
417
+ "artifacts": [
418
+ {
419
+ "id": "cloudtrail-audit-log-90d",
420
+ "type": "audit_trail",
421
+ "source": "AWS: aws cloudtrail lookup-events --start-time <now-90d> ; GCP: gcloud logging read 'resource.type=audited_resource' --freshness=90d ; Azure: az monitor activity-log list --start-time <now-90d>",
422
+ "description": "Cloud audit log over the last 90 days. Primary behavioural-evidence source for all subsequent indicators. The 90-day window is the longest commonly-available default retention; if the operator has longer retention configured (CloudTrail Lake, GCP _Default bucket extended, Azure Diagnostic Settings to Log Analytics), extend accordingly.",
423
+ "required": true,
424
+ "air_gap_alternative": "Operator pre-extracts the audit log to a local JSON/JSONL file and supplies the file path via signal_overrides. The runner reads the local file instead of calling the CSP API."
425
+ },
426
+ {
427
+ "id": "iam-principal-inventory",
428
+ "type": "api_response",
429
+ "source": "AWS: aws iam list-users + list-roles + list-groups + iam get-account-authorization-details ; GCP: gcloud iam service-accounts list + gcloud projects get-iam-policy ; Azure: az ad user list + az ad sp list + az role assignment list",
430
+ "description": "Current inventory of all IAM principals (human users, service accounts, managed identities, federated principals) with last-used timestamps, attached policies, and group/role memberships.",
431
+ "required": true,
432
+ "air_gap_alternative": "Operator pre-extracts the IAM inventory to a local JSON file."
433
+ },
434
+ {
435
+ "id": "recently-created-access-keys",
436
+ "type": "api_response",
437
+ "source": "AWS: aws iam list-access-keys per-user filtered to CreateDate >= now-90d ; GCP: gcloud iam service-accounts keys list per-SA filtered to validAfterTime >= now-90d ; Azure: az ad sp credential list per-SP filtered to startDate >= now-90d",
438
+ "description": "Access keys / service-account keys / client secrets created in the last 90 days. Cross-referenced against the IaC apply window (Terraform/Pulumi/CloudFormation/Bicep apply events) to surface out-of-band creation.",
439
+ "required": true,
440
+ "air_gap_alternative": "Operator pre-extracts the access-key inventory to a local JSON file."
441
+ },
442
+ {
443
+ "id": "cross-account-assume-role-events",
444
+ "type": "audit_trail",
445
+ "source": "AWS: cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRole AttributeKey=EventName,AttributeValue=AssumeRoleWithSAML AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity ; GCP: gcloud logging read 'protoPayload.methodName=GenerateAccessToken OR protoPayload.methodName=SignBlob' ; Azure: az monitor activity-log list filtered to operationName matching role-assumption equivalents",
446
+ "description": "All cross-account / cross-project role-assumption events in the last 90 days. Each event carries the source principal, target role, session-policy, and external-id (where applicable). Chains of >= 2 assume-role events with a common source principal within a 24h window are the primary cross-account-compromise signal.",
447
+ "required": true,
448
+ "air_gap_alternative": "Operator pre-extracts the assume-role events from the audit log to a local JSON file."
449
+ },
450
+ {
451
+ "id": "console-login-events",
452
+ "type": "audit_trail",
453
+ "source": "AWS: cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=ConsoleLogin ; GCP: gcloud logging read 'protoPayload.methodName=google.login.LoginService.login' ; Azure: az monitor activity-log list filtered to category=SignIn (or Sign-In Logs via Microsoft Graph)",
454
+ "description": "Interactive console / portal logins. ASN, region, and User-Agent fields drive the anomaly indicators (root login from new ASN, console login from impossible-travel geography).",
455
+ "required": true,
456
+ "air_gap_alternative": "Operator pre-extracts the console-login events to a local JSON file."
457
+ },
458
+ {
459
+ "id": "service-account-managed-identity-inventory",
460
+ "type": "api_response",
461
+ "source": "AWS: aws iam list-roles + list-instance-profiles ; GCP: gcloud iam service-accounts list (with `disabled` flag) ; Azure: az identity list (user-assigned managed identities) + system-assigned managed identities via az vm identity show / az functionapp identity show / az aks show",
462
+ "description": "Full inventory of non-human principals with token lifetimes, attached policies, last-used timestamps, and the resource(s) the principal is bound to.",
463
+ "required": true,
464
+ "air_gap_alternative": "Operator pre-extracts the service-account / managed-identity inventory to a local JSON file."
465
+ },
466
+ {
467
+ "id": "imds-access-patterns",
468
+ "type": "audit_trail",
469
+ "source": "AWS: VPC Flow Logs filtered to dstaddr=169.254.169.254 + EC2 instance-metadata access events from CloudTrail Insights ; GCP: VPC Flow Logs filtered to dstaddr=metadata.google.internal (169.254.169.254) ; Azure: NSG Flow Logs filtered to dstaddr=169.254.169.254",
470
+ "description": "Pattern of access to the instance-metadata service. Bursts of access from unexpected processes, IMDSv1 access on instances that have IMDSv2 available, and metadata access from non-localhost sources (SSRF indicator) are the signals here.",
471
+ "required": false,
472
+ "air_gap_alternative": "Operator pre-extracts the relevant VPC / NSG Flow Logs to a local JSONL file."
473
+ },
474
+ {
475
+ "id": "federated-idp-configuration",
476
+ "type": "config_file",
477
+ "source": "AWS: aws iam list-saml-providers + list-open-id-connect-providers + per-role get-role trust-policy ; GCP: gcloud iam workload-identity-pools list + per-pool get-iam-policy ; Azure: az ad app list + per-app az ad app credential list + Conditional Access policies via Graph",
478
+ "description": "Federated identity-provider configuration (SAML, OIDC, Workload Identity Federation) including trust policies, subject-claim conditions, audience constraints, and signing-key thumbprints.",
479
+ "required": true,
480
+ "air_gap_alternative": "Operator pre-extracts the federated IdP configuration to a local JSON file."
481
+ },
482
+ {
483
+ "id": "scp-org-policy-state",
484
+ "type": "config_file",
485
+ "source": "AWS: aws organizations list-policies --filter SERVICE_CONTROL_POLICY + describe-policy ; GCP: gcloud org-policies list --organization=<id> + describe ; Azure: az policy assignment list --scope <management-group>",
486
+ "description": "Current Service Control Policy / Org Policy / Management Group policy state and recent change history. Detects loosening of guardrails preceding or during a compromise.",
487
+ "required": true,
488
+ "air_gap_alternative": "Operator pre-extracts the SCP / Org Policy state to a local JSON file."
489
+ },
490
+ {
491
+ "id": "access-analyzer-findings",
492
+ "type": "api_response",
493
+ "source": "AWS: aws accessanalyzer list-findings ; GCP: gcloud policy-intelligence query-activity (Policy Analyzer) ; Azure: az graph query for Microsoft.Security/assessments resource-type",
494
+ "description": "External-exposure findings from the CSP's resource-policy analyser over the last 90 days. Surfaces resource policies (S3 buckets, KMS keys, Lambda functions) granting access to external principals.",
495
+ "required": false,
496
+ "air_gap_alternative": "Operator pre-extracts the Access Analyzer findings to a local JSON file."
497
+ },
498
+ {
499
+ "id": "recently-modified-resource-policies",
500
+ "type": "audit_trail",
501
+ "source": "AWS: cloudtrail filter by EventName in {PutBucketPolicy, PutKeyPolicy, PutFunctionPolicy, PutResourcePolicy} ; GCP: cloud audit logs filter by methodName matching setIamPolicy on storage / kms / cloudfunctions ; Azure: activity-log filter by operationName matching Microsoft.Storage/storageAccounts/blobServices/containers/write, Microsoft.KeyVault/vaults/accessPolicies/write",
502
+ "description": "Resource-policy modifications over the last 90 days. Cross-referenced against the IaC apply window to surface out-of-band policy changes.",
503
+ "required": true,
504
+ "air_gap_alternative": "Operator pre-extracts the resource-policy modification events to a local JSON file."
505
+ },
506
+ {
507
+ "id": "billing-anomalies",
508
+ "type": "api_response",
509
+ "source": "AWS: aws ce get-cost-and-usage --granularity DAILY --time-period Start=<now-30d>,End=<now> --group-by Type=DIMENSION,Key=REGION + Key=USAGE_TYPE ; GCP: gcloud billing accounts get-iam-policy + Cloud Billing BigQuery export ; Azure: az consumption usage list --start-date <now-30d>",
510
+ "description": "30-day cost-and-usage signal grouped by region + instance-family + service. Detects crypto-mining workloads (sudden spike in GPU / accelerated-compute instance hours in an unused region), data-egress spikes, and unexpected service-enablement events.",
511
+ "required": true,
512
+ "air_gap_alternative": "Operator pre-extracts the billing data to a local JSON / CSV file."
513
+ }
514
+ ],
515
+ "collection_scope": {
516
+ "time_window": "90d",
517
+ "asset_scope": "cloud_accounts_in_scope",
518
+ "depth": "deep",
519
+ "sampling": "full enumeration of all in-scope accounts; no sampling within the 90-day window; cross-referenced against the operator-supplied IaC apply window to suppress IaC-originated noise"
520
+ },
521
+ "environment_assumptions": [
522
+ {
523
+ "assumption": "Cloud audit logging is enabled and configured to log all management-plane events for the full 90-day window",
524
+ "if_false": "If CloudTrail / Cloud Audit Logs / Activity Log is disabled, partially enabled, or short-retention, the look phase is structurally incomplete. Mark `audit-log-coverage-gap` and emit a `cloudtrail_logging_disabled_event` indicator regardless of whether a specific disable event was found — absence is the finding."
525
+ },
526
+ {
527
+ "assumption": "The investigator's IAM read-only access covers every account in the org / project / management group",
528
+ "if_false": "Some accounts unreadable. Mark per-account inconclusive; emit a coverage note in the close phase rather than treating absence of evidence as evidence of absence."
529
+ },
530
+ {
531
+ "assumption": "Each account in scope has been operated for at least 90 days (so the time window is meaningful)",
532
+ "if_false": "For accounts younger than 90 days, narrow the window to account age + 7 days of pre-account-creation org-level events. Emit a `short-history` visibility note."
533
+ },
534
+ {
535
+ "assumption": "IaC apply windows are documented or recoverable from CI history (Terraform / Pulumi / CloudFormation / Bicep state)",
536
+ "if_false": "Without an IaC apply baseline, every IAM mutation event becomes a high-noise indicator. Demote `mass_iam_user_creation_outside_iac` to inconclusive and emit a `iac-baseline-missing` visibility note in close."
537
+ }
538
+ ],
539
+ "fallback_if_unavailable": [
540
+ {
541
+ "artifact_id": "cloudtrail-audit-log-90d",
542
+ "fallback_action": "escalate_to_human",
543
+ "confidence_impact": "high"
544
+ },
545
+ {
546
+ "artifact_id": "iam-principal-inventory",
547
+ "fallback_action": "escalate_to_human",
548
+ "confidence_impact": "high"
549
+ },
550
+ {
551
+ "artifact_id": "recently-created-access-keys",
552
+ "fallback_action": "mark_inconclusive",
553
+ "confidence_impact": "high"
554
+ },
555
+ {
556
+ "artifact_id": "cross-account-assume-role-events",
557
+ "fallback_action": "mark_inconclusive",
558
+ "confidence_impact": "high"
559
+ },
560
+ {
561
+ "artifact_id": "console-login-events",
562
+ "fallback_action": "mark_inconclusive",
563
+ "confidence_impact": "medium"
564
+ },
565
+ {
566
+ "artifact_id": "service-account-managed-identity-inventory",
567
+ "fallback_action": "mark_inconclusive",
568
+ "confidence_impact": "medium"
569
+ },
570
+ {
571
+ "artifact_id": "imds-access-patterns",
572
+ "fallback_action": "mark_inconclusive",
573
+ "confidence_impact": "medium"
574
+ },
575
+ {
576
+ "artifact_id": "federated-idp-configuration",
577
+ "fallback_action": "mark_inconclusive",
578
+ "confidence_impact": "high"
579
+ },
580
+ {
581
+ "artifact_id": "scp-org-policy-state",
582
+ "fallback_action": "mark_inconclusive",
583
+ "confidence_impact": "medium"
584
+ },
585
+ {
586
+ "artifact_id": "access-analyzer-findings",
587
+ "fallback_action": "mark_inconclusive",
588
+ "confidence_impact": "low"
589
+ },
590
+ {
591
+ "artifact_id": "recently-modified-resource-policies",
592
+ "fallback_action": "mark_inconclusive",
593
+ "confidence_impact": "high"
594
+ },
595
+ {
596
+ "artifact_id": "billing-anomalies",
597
+ "fallback_action": "mark_inconclusive",
598
+ "confidence_impact": "medium"
599
+ }
600
+ ]
601
+ },
602
+ "detect": {
603
+ "indicators": [
604
+ {
605
+ "id": "root_login_from_new_asn",
606
+ "type": "log_pattern",
607
+ "value": "Within the console-login-events artifact, filter to principal == root (AWS) / org-admin (GCP) / Global Administrator (Azure). For each, derive the historical-ASN baseline from the prior 365 days (or full account history if shorter). Flag any login whose source-IP ASN is not in the baseline.",
608
+ "description": "Root / global-admin login from a previously-unseen ASN. Highest-severity behavioural signal across all three CSPs.",
609
+ "confidence": "high",
610
+ "deterministic": false,
611
+ "attack_ref": "T1078",
612
+ "false_positive_checks_required": [
613
+ "Rule out documented operator travel: cross-reference the login timestamp + source-IP geolocation against operator travel calendar / VPN exit-node inventory.",
614
+ "Rule out a legitimate ASN change (operator's ISP changed; corporate VPN aggregator routed via new transit provider) by checking whether the new ASN appears in subsequent days for the same principal without other anomalies.",
615
+ "Demote to medium if the login was followed within 30 minutes by a documented incident-response action (the operator logged in to investigate)."
616
+ ]
617
+ },
618
+ {
619
+ "id": "mass_iam_user_creation_outside_iac",
620
+ "type": "log_pattern",
621
+ "value": "Within the cloudtrail-audit-log-90d artifact, filter to EventName in {CreateUser, CreateServiceAccount, CreateManagedIdentity, CreateApplication}. Group by source principal + 1-hour window. Flag any window containing >= 3 creation events where the source principal is not in the IaC-runner allowlist (Terraform/Pulumi/CloudFormation/Bicep service principals).",
622
+ "description": "Burst of IAM-principal creation events outside the documented IaC apply window. Common post-compromise persistence pattern.",
623
+ "confidence": "high",
624
+ "deterministic": false,
625
+ "attack_ref": "T1098.001",
626
+ "false_positive_checks_required": [
627
+ "Rule out an IaC apply window that was not in the documented baseline (new pipeline, manual `terraform apply` from operator workstation) by cross-referencing CI run history.",
628
+ "Rule out a documented bulk-onboarding event (new team / acquired-company onboarding) by checking for a corresponding ticket / change request.",
629
+ "Demote to medium if the creating principal is a known operator (human, not service) and the created principals are tagged with a project label matching an active project."
630
+ ]
631
+ },
632
+ {
633
+ "id": "unused_region_resource_creation",
634
+ "type": "log_pattern",
635
+ "value": "Within the cloudtrail-audit-log-90d artifact, filter to resource-creation events (RunInstances, CreateInstance, az vm create equivalents). Derive the historical region-set used by the account over the prior 365 days. Flag any creation event in a region not in the baseline set.",
636
+ "description": "Resource creation in a region the account has never used. Strong crypto-mining-campaign signal when combined with GPU-instance-family selection.",
637
+ "confidence": "high",
638
+ "deterministic": false,
639
+ "attack_ref": "T1580",
640
+ "false_positive_checks_required": [
641
+ "Rule out a documented new-region rollout (operator announced expansion into the region; corresponding governance ticket exists).",
642
+ "Rule out a legitimate cross-region replication setup (KMS key replica, S3 cross-region replication target) where the destination region was newly authorised.",
643
+ "Demote to medium if the created resource is tagged with a project label and the project has documented expansion plans."
644
+ ]
645
+ },
646
+ {
647
+ "id": "gpu_instance_creation_spike",
648
+ "type": "log_pattern",
649
+ "value": "Within the billing-anomalies artifact, filter to GPU / accelerated-compute instance families (AWS: p* / g* / inf* / trn* / dl1.* ; GCP: a2-* / a3-* / g2-* ; Azure: NC* / ND* / NV* / NG*). Flag any 24h window where instance-hours exceed the 30-day rolling average by >= 5x AND the account is not tagged as ml-workload / training-workload.",
650
+ "description": "Sudden spike in GPU instance hours. Almost always crypto-mining when uncorrelated with a documented ML training run.",
651
+ "confidence": "high",
652
+ "deterministic": false,
653
+ "attack_ref": "T1580",
654
+ "false_positive_checks_required": [
655
+ "Rule out a documented ML training run: cross-reference with the ML platform's training-job inventory (SageMaker training jobs, Vertex AI training jobs, Azure ML jobs) AND with the corresponding project tag.",
656
+ "Rule out a documented capacity-reservation purchase (Savings Plan / committed-use / reserved-capacity event preceding the spike).",
657
+ "Demote to medium if the creating principal is a documented ML-platform service principal AND the destination region is in the account's baseline region set."
658
+ ]
659
+ },
660
+ {
661
+ "id": "iam_access_key_created_no_iac_ticket",
662
+ "type": "log_pattern",
663
+ "value": "Within the recently-created-access-keys artifact, filter to keys whose creating principal is not in the IaC-runner allowlist AND no corresponding break-glass / access-key-request ticket is referenced in the create event's request-context.",
664
+ "description": "Long-lived access key created outside both IaC and break-glass workflows. Snowflake-AA24-class post-compromise persistence.",
665
+ "confidence": "high",
666
+ "deterministic": false,
667
+ "attack_ref": "T1098.001",
668
+ "false_positive_checks_required": [
669
+ "Rule out a break-glass / emergency-access event: cross-reference with the break-glass log and confirm a corresponding incident ticket exists.",
670
+ "Rule out a documented developer-onboarding event where access-key issuance is part of the workflow.",
671
+ "Demote to medium if the created key is tagged with an expiration date <= 30 days and a documented rotation owner."
672
+ ]
673
+ },
674
+ {
675
+ "id": "cross_account_assume_role_anomaly",
676
+ "type": "log_pattern",
677
+ "value": "Within the cross-account-assume-role-events artifact, build a graph of (source_principal, target_account, target_role). Flag any chain of >= 2 assume-role events with a common source principal traversing >= 2 account boundaries within a 24h window where the chain does not match a documented integration pattern.",
678
+ "description": "Cross-account assume-role chain that does not match a documented integration. Primary cross-account-compromise indicator; not visible to AC-2 / CC6 lifecycle controls.",
679
+ "confidence": "high",
680
+ "deterministic": false,
681
+ "attack_ref": "T1078.004",
682
+ "false_positive_checks_required": [
683
+ "Rule out a documented partner integration (3rd-party SaaS connecting to multiple accounts via assume-role — Datadog, Wiz, Lacework, Snowflake, BigQuery cross-project) by cross-referencing the integration inventory.",
684
+ "Rule out a documented multi-account deployment pipeline (e.g. a release pipeline that assumes-role into each environment account sequentially).",
685
+ "Demote to medium if every hop carries a non-wildcard external-id AND the source principal is a documented integration service-principal."
686
+ ]
687
+ },
688
+ {
689
+ "id": "imds_v1_legacy_access",
690
+ "type": "log_pattern",
691
+ "value": "Within the imds-access-patterns artifact, filter to events where the IMDS request used the unauthenticated v1 endpoint (no `X-aws-ec2-metadata-token` header on AWS; no `Metadata-Flavor: Google` enforcement on GCP; equivalent on Azure). Flag any instance that has IMDSv2 available but where v1 access occurred.",
692
+ "description": "IMDSv1 access on instances where IMDSv2 is available. SSRF / token-exfil primitive — IMDSv1 has no defence against server-side request forgery from the instance's exposed services.",
693
+ "confidence": "medium",
694
+ "deterministic": false,
695
+ "attack_ref": "T1552.005",
696
+ "false_positive_checks_required": [
697
+ "Rule out a documented IMDSv1-to-v2 migration phase where a defined inventory of instances is intentionally on v1 with a documented migration ETA.",
698
+ "Rule out a legacy-application allowlist where the v1 caller is a documented system-process that cannot be upgraded.",
699
+ "Demote to low if the v1 access source-IP is localhost (127.0.0.1) and the instance has IMDSv2 hop-limit configured to 1."
700
+ ]
701
+ },
702
+ {
703
+ "id": "kms_key_policy_self_grant",
704
+ "type": "log_pattern",
705
+ "value": "Within the recently-modified-resource-policies artifact, filter to KMS key-policy / Cloud KMS IAM-policy / Key Vault access-policy modifications. Flag any change where the principal granted access is the same principal that made the change (self-grant) AND the modification is not part of a documented IaC apply.",
706
+ "description": "KMS key-policy self-grant. Common post-compromise persistence — attacker grants their assumed-role access to a previously-restricted key.",
707
+ "confidence": "high",
708
+ "deterministic": false,
709
+ "attack_ref": "T1098.001",
710
+ "false_positive_checks_required": [
711
+ "Rule out a documented CMK migration where ownership was transferred to a new principal as part of an approved change.",
712
+ "Rule out a documented developer self-service workflow where service-account self-grants are part of an approved pattern.",
713
+ "Demote to medium if the granting principal is a documented platform-admin role AND the granted access is non-decryption (Describe / GetPublicKey only)."
714
+ ]
715
+ },
716
+ {
717
+ "id": "s3_bucket_policy_public_grant",
718
+ "type": "log_pattern",
719
+ "value": "Within the recently-modified-resource-policies artifact, filter to S3 PutBucketPolicy / GCS setIamPolicy / Azure Blob access-policy modifications where the new policy grants Principal = `*` or `allUsers` / `allAuthenticatedUsers`.",
720
+ "description": "Public-grant on object-storage resource. May be intentional (CDN backing bucket) or accidental data-exposure post-compromise.",
721
+ "confidence": "medium",
722
+ "deterministic": false,
723
+ "attack_ref": "T1098.001",
724
+ "false_positive_checks_required": [
725
+ "Rule out a documented CDN-backing bucket (CloudFront / Cloud CDN / Azure CDN origin) where public-read is the intended posture.",
726
+ "Rule out a documented static-website-hosting bucket where public-read is the intended posture.",
727
+ "Demote to low if the bucket carries a `Public: true` tag AND the granted action set is `s3:GetObject` only (no list / write)."
728
+ ]
729
+ },
730
+ {
731
+ "id": "cloudtrail_logging_disabled_event",
732
+ "type": "log_pattern",
733
+ "value": "Within the cloudtrail-audit-log-90d artifact, filter to EventName in {StopLogging, DeleteTrail, PutEventSelectors with empty selectors, DisableLogging, UpdateSink with disabled state, DiagnosticSettingsDelete}. Also flag any account where audit logging is currently disabled regardless of an explicit disable event (absence-is-evidence).",
734
+ "description": "Cloud audit logging disabled. Adversary defence-evasion primitive; almost never legitimate post-deployment.",
735
+ "confidence": "high",
736
+ "deterministic": false,
737
+ "attack_ref": "T1098.001",
738
+ "false_positive_checks_required": [
739
+ "Rule out a documented logging-service-update window (CloudTrail trail-recreation, Log Sink migration) by cross-referencing the change-management log.",
740
+ "Rule out an account-decommissioning workflow where logging was intentionally disabled as part of the decommission.",
741
+ "Demote to medium if the disable event was followed within 1 hour by a re-enable event AND no other anomalous activity occurred in the gap."
742
+ ]
743
+ }
744
+ ],
745
+ "false_positive_profile": [
746
+ {
747
+ "indicator_id": "root_login_from_new_asn",
748
+ "benign_pattern": "Operator travel; corporate VPN re-routing; ISP topology change.",
749
+ "distinguishing_test": "Cross-reference the login timestamp against documented operator travel; check whether the new ASN persists in benign-looking sessions over subsequent days. Persistent new ASN with operator-shaped action pattern is benign; one-off new ASN followed by IAM-mutation actions stays high."
750
+ },
751
+ {
752
+ "indicator_id": "mass_iam_user_creation_outside_iac",
753
+ "benign_pattern": "Manual `terraform apply` from operator workstation outside the documented CI pipeline; bulk-onboarding event for a new team.",
754
+ "distinguishing_test": "Check the creating principal's session context: workstation IAM Identity Center session with documented operator identity is benign-shaped; assumed-role from an unexpected source is not."
755
+ },
756
+ {
757
+ "indicator_id": "cross_account_assume_role_anomaly",
758
+ "benign_pattern": "Documented multi-account deployment pipelines; 3rd-party SaaS integrations (Datadog, Wiz, Lacework) that assume-role into multiple accounts.",
759
+ "distinguishing_test": "Check the external-id on each hop: documented integrations use a per-integration external-id; attacker chains typically inherit a single external-id or no external-id. Wildcard external-id on a cross-account chain is the cleanest distinguishing test."
760
+ },
761
+ {
762
+ "indicator_id": "imds_v1_legacy_access",
763
+ "benign_pattern": "Documented legacy-application allowlist; in-progress IMDSv1-to-v2 migration.",
764
+ "distinguishing_test": "Check whether the source process making the v1 call is in the operator's documented v1-allowlist. Off-allowlist v1 callers stay medium; SSRF-shaped patterns (multiple distinct user-agents within seconds) raise to high."
765
+ },
766
+ {
767
+ "indicator_id": "s3_bucket_policy_public_grant",
768
+ "benign_pattern": "CDN-backing bucket; documented static-website-hosting bucket.",
769
+ "distinguishing_test": "Check the bucket's tag set and the action-set granted. `s3:GetObject`-only on a `Public: true`-tagged bucket is benign; `s3:*` on an untagged bucket is not."
770
+ }
771
+ ],
772
+ "minimum_signal": {
773
+ "detected": "At least one high-confidence indicator fires AND the false-positive distinguishing test does not clear it AND the indicator's RWEP exceeds direct.rwep_threshold.escalate.",
774
+ "inconclusive": "An indicator fired but the audit-log retention or IAM read-only-access coverage gap prevents distinguishing-test completion. Mark detected-with-caveat and escalate.",
775
+ "not_detected": "Full 90-day audit-log walk completed AND zero high-confidence indicators fired AND IAM-principal posture is hygienic (no long-lived access keys without owner+expiration, no wildcard OIDC trust policies, IMDSv2 enforced on >= 95% of instances)."
776
+ }
777
+ },
778
+ "analyze": {
779
+ "rwep_inputs": [
780
+ {
781
+ "signal_id": "root_login_from_new_asn",
782
+ "rwep_factor": "active_exploitation",
783
+ "weight": 30,
784
+ "notes": "Root / global-admin from new ASN is post-compromise-shaped. Treat as exploitation-imminent regardless of subsequent action observed within the audit-log window."
785
+ },
786
+ {
787
+ "signal_id": "root_login_from_new_asn",
788
+ "rwep_factor": "blast_radius",
789
+ "weight": 25,
790
+ "notes": "Root-equivalent principal blast radius is account-wide minimum, org-wide on multi-account orgs without segmentation."
791
+ },
792
+ {
793
+ "signal_id": "cross_account_assume_role_anomaly",
794
+ "rwep_factor": "active_exploitation",
795
+ "weight": 30,
796
+ "notes": "Cross-account chains are post-compromise lateral movement; 2024-2026 IR data shows this as the dominant lateral-movement vector in cloud-IAM compromise."
797
+ },
798
+ {
799
+ "signal_id": "cross_account_assume_role_anomaly",
800
+ "rwep_factor": "blast_radius",
801
+ "weight": 25,
802
+ "notes": "Chain length and account-boundary count scale blast radius. >= 2 boundaries crossed = blast_radius >= 4."
803
+ },
804
+ {
805
+ "signal_id": "iam_access_key_created_no_iac_ticket",
806
+ "rwep_factor": "active_exploitation",
807
+ "weight": 25,
808
+ "notes": "Snowflake-AA24-class persistence. Long-lived keys outside IaC are post-compromise-shaped."
809
+ },
810
+ {
811
+ "signal_id": "mass_iam_user_creation_outside_iac",
812
+ "rwep_factor": "active_exploitation",
813
+ "weight": 25,
814
+ "notes": "Burst-creation outside IaC is the textbook persistence-establishment pattern."
815
+ },
816
+ {
817
+ "signal_id": "gpu_instance_creation_spike",
818
+ "rwep_factor": "active_exploitation",
819
+ "weight": 20,
820
+ "notes": "Crypto-mining campaigns monetize within hours; spike + unused-region + no ML-tag is high-confidence."
821
+ },
822
+ {
823
+ "signal_id": "imds_v1_legacy_access",
824
+ "rwep_factor": "blast_radius",
825
+ "weight": 15,
826
+ "notes": "Token-exfil primitive; blast radius is the assumed-role scope of the instance profile / managed identity."
827
+ },
828
+ {
829
+ "signal_id": "kms_key_policy_self_grant",
830
+ "rwep_factor": "blast_radius",
831
+ "weight": 20,
832
+ "notes": "Self-grant on KMS = data-exfil capability + decryption persistence."
833
+ },
834
+ {
835
+ "signal_id": "cloudtrail_logging_disabled_event",
836
+ "rwep_factor": "active_exploitation",
837
+ "weight": 25,
838
+ "notes": "Defence-evasion primitive; almost never legitimate post-deployment."
839
+ },
840
+ {
841
+ "signal_id": "s3_bucket_policy_public_grant",
842
+ "rwep_factor": "active_exploitation",
843
+ "weight": 15,
844
+ "notes": "Public-grant is medium-baseline because of CDN false-positive rate; raise when combined with other indicators."
845
+ },
846
+ {
847
+ "signal_id": "unused_region_resource_creation",
848
+ "rwep_factor": "active_exploitation",
849
+ "weight": 15,
850
+ "notes": "Unused-region creation is medium-baseline; combine with GPU spike for high."
851
+ }
852
+ ],
853
+ "blast_radius_model": {
854
+ "scope_question": "Given the compromised principal(s) and the cross-account / federated trust posture, what is the blast radius if the attacker fully exploits every chain reachable from the compromised principal within 24h?",
855
+ "scoring_rubric": [
856
+ {
857
+ "condition": "Single non-production principal (sandbox account, ephemeral CI account) confirmed compromised; no cross-account reach",
858
+ "blast_radius_score": 1,
859
+ "description": "Sandbox-scope compromise."
860
+ },
861
+ {
862
+ "condition": "Single production principal compromised within a single account; no cross-account reach",
863
+ "blast_radius_score": 2,
864
+ "description": "Single-account compromise; spend + data-exfil within that account's IAM scope."
865
+ },
866
+ {
867
+ "condition": "Single production principal compromised AND the principal has broad IAM scope (admin / wildcard) within the account",
868
+ "blast_radius_score": 3,
869
+ "description": "Account-wide compromise; full data exfil + resource creation within the account."
870
+ },
871
+ {
872
+ "condition": "Compromised principal has cross-account assume-role reach into >= 1 other account in the org AND/OR has admin scope in a federated-trust target",
873
+ "blast_radius_score": 4,
874
+ "description": "Multi-account compromise; org-boundary risk; chain into cred-stores playbook required."
875
+ },
876
+ {
877
+ "condition": "Compromised principal reaches >= 3 accounts OR reaches the org root OR has published assets (npm / PyPI / Docker Hub / container registry write) AND the chain includes at least one identity-layer outside the cloud (federated IdP, third-party SaaS holding cloud credentials)",
878
+ "blast_radius_score": 5,
879
+ "description": "Org-wide identity-boundary collapse. Treat as confirmed incident; chain into sbom playbook for supply-chain blast assessment."
880
+ }
881
+ ]
882
+ },
883
+ "compliance_theater_check": {
884
+ "claim": "Org has SCPs / Org Policies / Management Group policies + root MFA + AWS Security Hub (or equivalent) all-green + IAM Access Analyzer findings closed -> cloud-IAM is secure.",
885
+ "audit_evidence": "SCP / Org Policy state showing guardrails; root MFA enabled on every account; Security Hub posture score; Access Analyzer findings inventory.",
886
+ "reality_test": "Run the working-tree look phase against the 90-day audit log AND the IAM principal inventory. Count: (a) long-lived access keys on non-root principals with no documented expiration, (b) federated trust policies with wildcard subject claims, (c) cross-account assume-role chains traversing >= 2 boundaries without an external-id, (d) instances on IMDSv1 with IMDSv2 available, (e) IAM mutation events outside the IaC apply window in the last 90 days, (f) unused-region resource creation events, (g) periods of audit-log disablement. Any count > 0 is gap between the paper-attested 'secure' state and the actual behavioural surface.",
887
+ "theater_verdict_if_gap": "SCPs constrain principals within an account but do not see cross-account chains. Root MFA covers 1 principal class. Security Hub is coverage-based, not breach-detection. Access Analyzer is reachability-based, not principal-action-based. The 'paper-secure' attestation captures none of the dominant 2024-2026 compromise vectors. Either (a) extend monitoring to behavioural CloudTrail / audit-log analytics with the indicator set in this playbook, (b) tighten federated-trust policies to non-wildcard subject claims with audience constraints, (c) enforce IMDSv2 globally, OR (d) generate policy exception documenting the scope gap + compensating controls + remediation timeline."
888
+ },
889
+ "framework_gap_mapping": [
890
+ {
891
+ "finding_id": "cross-account-chain",
892
+ "framework": "nist-800-53",
893
+ "claimed_control": "AC-2 — Account Management",
894
+ "actual_gap": "AC-2 lifecycle treats principals individually. Cross-account assume-role chains are valid AC-2-compliant actions individually; the compromise is the chain across boundaries, which AC-2 cannot see.",
895
+ "required_control": "Extend AC-2 with a chain-of-assumptions sub-control requiring continuous monitoring of cross-account / cross-project / cross-management-group role-assumption graphs over rolling 24h windows. Captured in `data/framework-control-gaps.json#NIST-800-53-AC-2-Cross-Account`."
896
+ },
897
+ {
898
+ "finding_id": "access-key-leak-public-repo",
899
+ "framework": "soc2",
900
+ "claimed_control": "CC6.1 — Logical Access Controls",
901
+ "actual_gap": "Authentication-shaped. A leaked access key produces a fully-authenticated session whose CC6 evidence is satisfied. The leak point (public repository) is outside CC6 scope.",
902
+ "required_control": "Add CC6 sub-criterion requiring continuous monitoring of credential exposure on public-code-search surfaces (GitHub, GitLab, Bitbucket public). Captured in `data/framework-control-gaps.json#SOC2-CC6-Access-Key-Leak-Public-Repo`."
903
+ },
904
+ {
905
+ "finding_id": "snowflake-aa24-class",
906
+ "framework": "iso-27001-2022",
907
+ "claimed_control": "A.5.18 — Access rights",
908
+ "actual_gap": "Access-rights review treats credentials as fungible — federated IdP credentials and cloud-IAM credentials are reviewed independently. Compromise via cross-system credential reuse (Okta-to-cloud, GitHub-to-cloud, Snowflake-to-cloud) is invisible.",
909
+ "required_control": "Extend A.5.18 with explicit cross-system credential-reuse mapping: every federated trust must enumerate which downstream systems honour the IdP, with continuous attestation. Captured in `data/framework-control-gaps.json#CISA-Snowflake-AA24-IdP-Cloud`."
910
+ },
911
+ {
912
+ "finding_id": "imds-v1-legacy",
913
+ "framework": "iso-27001-2022",
914
+ "claimed_control": "A.5.23 — Information security for use of cloud services",
915
+ "actual_gap": "Generic cloud-services control. Instance-metadata-service hardening is not enumerated; the v1-to-v2 transition is provider-specific guidance that has no A.5.23 evidence equivalent.",
916
+ "required_control": "ISO/IEC 27017-extension: cloud-instance-metadata-service hardening with provider-specific enforcement attestations (IMDSv2 hop-limit, token TTL, deny-by-default). Captured in `data/framework-control-gaps.json#ISO-27017-Cloud-IAM`."
917
+ },
918
+ {
919
+ "finding_id": "federated-il5-il6-gap",
920
+ "framework": "fedramp",
921
+ "claimed_control": "FedRAMP IL5 baseline — IA-2, AC-2, AC-3, IA-5",
922
+ "actual_gap": "IL5 baseline assumes single-cloud-tenant deployment. IL6 sovereign-cloud federated-trust patterns are not contemplated; cross-IL trust policies are out of scope.",
923
+ "required_control": "FedRAMP IL5-Federated extension explicitly enumerating cross-IL trust-policy requirements with sovereign-cloud audience-claim constraints. Captured in `data/framework-control-gaps.json#FedRAMP-IL5-IAM-Federated`."
924
+ },
925
+ {
926
+ "finding_id": "security-hub-coverage",
927
+ "framework": "soc2",
928
+ "claimed_control": "CC7.2 — System monitoring",
929
+ "actual_gap": "AWS Security Hub / GCP Security Command Center / Azure Defender for Cloud findings are coverage-based posture scores, not breach-detection. CC7.2 evidence is satisfied by 'monitoring system deployed' without verifying that the monitoring system can see the relevant behavioural signals.",
930
+ "required_control": "CC7.2 sub-criterion requiring that monitoring coverage be measured against a behavioural-indicator inventory (e.g. this playbook's detect.indicators), not against posture-tool deployment. Captured in `data/framework-control-gaps.json#AWS-Security-Hub-Coverage-Gap`."
931
+ },
932
+ {
933
+ "finding_id": "cloud-service-account-mfa-gap",
934
+ "framework": "au-ism",
935
+ "claimed_control": "ISM-1546 — Multi-factor authentication for privileged users",
936
+ "actual_gap": "ISM-1546 covers human-principal MFA. Cloud service-account access keys, IAM-role assume-role chains initiated by service principals, and managed-identity tokens bypass MFA entirely.",
937
+ "required_control": "ISM-1546 extension enumerating cloud non-human-principal credential hygiene with explicit bearer-token TTL ceilings + audience binding + per-action audit logging. Captured in `data/framework-control-gaps.json#AU-ISM-1546-Cloud-Service-Account`."
938
+ },
939
+ {
940
+ "finding_id": "uk-caf-b2-cloud-iam",
941
+ "framework": "uk-caf",
942
+ "claimed_control": "B2 — Identity and Access Control",
943
+ "actual_gap": "Outcome-based on credential-lifecycle hygiene. Cloud-IAM specifics (federated trust, cross-account assume-role chains, managed-identity tokens) are not enumerated against B2 evidence.",
944
+ "required_control": "B2 contributing-outcomes refresh enumerating cloud-IAM-specific trust-policy hygiene + cross-account chain monitoring. Captured in `data/framework-control-gaps.json#UK-CAF-B2-Cloud-IAM`."
945
+ }
946
+ ],
947
+ "escalation_criteria": [
948
+ {
949
+ "condition": "rwep >= 90 AND credential_appears_live == true",
950
+ "action": "page_on_call"
951
+ },
952
+ {
953
+ "condition": "blast_radius_score >= 4",
954
+ "action": "trigger_playbook",
955
+ "target_playbook": "cred-stores"
956
+ },
957
+ {
958
+ "condition": "compromised_account_has_published_assets == true",
959
+ "action": "trigger_playbook",
960
+ "target_playbook": "sbom"
961
+ },
962
+ {
963
+ "condition": "analyze.compliance_theater_check.verdict == 'theater'",
964
+ "action": "notify_legal"
965
+ },
966
+ {
967
+ "condition": "cloudtrail_logging_disabled_event == true AND cloudtrail_re_enabled_within_1h == false",
968
+ "action": "raise_severity"
969
+ }
970
+ ]
971
+ },
972
+ "validate": {
973
+ "remediation_paths": [
974
+ {
975
+ "id": "rotate-root-and-revoke-sessions",
976
+ "description": "(1) Rotate root credentials on every compromised account; (2) revoke all active sessions via aws iam get-credential-report + aws iam delete-access-key + global sign-out (GCP: gcloud iam service-accounts disable + revoke OAuth grants; Azure: revoke all refresh tokens via az ad user revoke-sign-in-sessions + Conditional Access disable-token-issuance); (3) rotate every IAM access key on the compromised principal AND every principal reachable via the cross-account chain; (4) audit IaC drift via terraform plan / pulumi preview / az deployment what-if against the current state and quarantine any out-of-band resources; (5) quarantine compromised resources by attaching deny-all SCP / Org Policy / Management Group deny-assignment.",
977
+ "preconditions": [
978
+ "provider_supports_session_revocation == true",
979
+ "rotation_ownership_identified == true"
980
+ ],
981
+ "priority": 1,
982
+ "compensating_controls": [
983
+ "session-revocation",
984
+ "audit-log-review-for-misuse-window",
985
+ "deny-all-scp-attached-to-quarantine-ou"
986
+ ],
987
+ "estimated_time_hours": 4
988
+ },
989
+ {
990
+ "id": "review-90d-iam-events",
991
+ "description": "Review the last 90 days of IAM events on every account in the org reachable from the compromised principal. Revoke unrecognised cross-account trusts, tighten SCPs / Org Policies / Management Group policies, rotate KMS keys with policy changes in the window, review billing anomalies for crypto-mining footprint, decommission any out-of-band-created resources.",
992
+ "preconditions": [
993
+ "audit_log_coverage_days >= 90",
994
+ "iam_read_only_across_org == true"
995
+ ],
996
+ "priority": 2,
997
+ "compensating_controls": [
998
+ "iam-event-review-completed",
999
+ "scp-tightened",
1000
+ "kms-keys-rotated"
1001
+ ],
1002
+ "estimated_time_hours": 12
1003
+ },
1004
+ {
1005
+ "id": "enforce-imds-v2-globally",
1006
+ "description": "Enforce IMDSv2 on every EC2 instance / equivalent on GCE and Azure VM (hop-limit 1, tokens required); audit instance launch templates / instance groups / VMSS to ensure new instances default to v2; deprecate IMDSv1 via SCP / Org Policy denying RunInstances with HttpTokens=optional.",
1007
+ "preconditions": [
1008
+ "imdsv2_migration_blocker_inventory_complete == true"
1009
+ ],
1010
+ "priority": 2,
1011
+ "compensating_controls": [
1012
+ "imdsv2-enforced-org-wide",
1013
+ "scp-deny-imdsv1-launch"
1014
+ ],
1015
+ "estimated_time_hours": 8
1016
+ },
1017
+ {
1018
+ "id": "tighten-federated-trust",
1019
+ "description": "Audit every IAM role with a SAML / OIDC / Workload Identity Federation trust policy. Replace wildcard subject claims (`repo:*`, `*` audience) with explicit subject constraints (`repo:owner/repo:ref:refs/heads/main`, audience pinned to per-integration value). Add MFA-required Conditional Access on federated admin sessions. Rotate any federated signing keys older than the documented rotation cadence.",
1020
+ "preconditions": [
1021
+ "federated_trust_inventory_complete == true"
1022
+ ],
1023
+ "priority": 2,
1024
+ "compensating_controls": [
1025
+ "federated-trust-tightened",
1026
+ "conditional-access-mfa-required-on-admin"
1027
+ ],
1028
+ "estimated_time_hours": 6
1029
+ },
1030
+ {
1031
+ "id": "policy-exception",
1032
+ "description": "If rotation requires coordinated multi-system rollout (federated IdP touches 50+ downstream consumers, or the compromised principal is consumed by a critical-or-important function whose rotation requires change-board approval), generate exception with bounded duration + enhanced audit-log alerting on the unrotated credential.",
1033
+ "preconditions": [
1034
+ "coordinated_rotation_required == true",
1035
+ "credential_misuse_monitoring_in_place == true"
1036
+ ],
1037
+ "priority": 4,
1038
+ "compensating_controls": [
1039
+ "enhanced-audit-log-alerting-on-principal",
1040
+ "incident-response-team-on-standby",
1041
+ "ip-allowlist-tightened-on-principal"
1042
+ ],
1043
+ "estimated_time_hours": 48
1044
+ }
1045
+ ],
1046
+ "validation_tests": [
1047
+ {
1048
+ "id": "indicator-rescan-clean",
1049
+ "test": "Re-run the detect-phase indicator set against the post-remediation audit log + IAM inventory. Expect zero high-confidence indicators firing in the post-remediation window.",
1050
+ "expected_result": "No high-confidence indicators fire; any remaining medium / low indicators pass false-positive distinguishing tests.",
1051
+ "test_type": "negative"
1052
+ },
1053
+ {
1054
+ "id": "principal-revoked-at-provider",
1055
+ "test": "On every rotated principal, confirm via the CSP API that (a) old access keys are deleted / disabled, (b) old sessions are revoked, (c) new credentials are active. AWS: aws iam list-access-keys per-user, expect zero Active keys older than rotation timestamp. GCP: gcloud iam service-accounts keys list, expect zero non-system keys older than rotation timestamp. Azure: az ad sp credential list, expect zero credentials older than rotation timestamp.",
1056
+ "expected_result": "Old credentials inactive; new credentials active; session-revocation confirmed.",
1057
+ "test_type": "functional"
1058
+ },
1059
+ {
1060
+ "id": "audit-log-shows-no-misuse-post-rotation",
1061
+ "test": "Review the post-rotation audit log for the rotated principals. Confirm no anomalous activity (no logins from the prior compromise-window source IPs, no IAM mutations outside the IaC apply window, no cross-account assume-role chains).",
1062
+ "expected_result": "No anomalous activity in the post-rotation window.",
1063
+ "test_type": "functional"
1064
+ },
1065
+ {
1066
+ "id": "imds-v2-enforcement-coverage",
1067
+ "test": "Inventory all instances; compute percentage on IMDSv2-required posture. Expect >= 99% in production, 100% in critical-or-important-function-supporting accounts.",
1068
+ "expected_result": "IMDSv2-required posture coverage >= 99%.",
1069
+ "test_type": "negative"
1070
+ },
1071
+ {
1072
+ "id": "federated-trust-no-wildcards",
1073
+ "test": "Re-audit every IAM role with a federated trust policy. Expect zero policies with wildcard subject claims (`repo:*`, `*` audience).",
1074
+ "expected_result": "Zero wildcard subject-claim trust policies.",
1075
+ "test_type": "negative"
1076
+ },
1077
+ {
1078
+ "id": "scp-quarantine-effective",
1079
+ "test": "Attempt a deny-able action from a principal in the quarantine OU. Expect the SCP / Org Policy / Management Group deny to fire.",
1080
+ "expected_result": "Deny-all SCP / Org Policy / deny-assignment blocks the test action.",
1081
+ "test_type": "functional"
1082
+ }
1083
+ ],
1084
+ "residual_risk_statement": {
1085
+ "risk": "Even after rotation + revocation + SCP tightening + IMDSv2 enforcement + federated-trust hardening, the attacker may have exfiltrated data during the compromise window OR established persistence in artefacts not reachable from the IAM principal inventory (compromised package published to npm / PyPI / Docker Hub, compromised SaaS-integration credential held outside the cloud, compromised CI pipeline that re-introduces a backdoor on next apply).",
1086
+ "why_remains": "Cloud-IAM compromise is irreversible at the data-exfil level. Revocation prevents future misuse but does not undo prior misuse. Audit log review establishes upper bound on misuse but cannot prove a negative for all classes (e.g. covert exfil within normal-looking egress patterns, supply-chain backdoors that activate later).",
1087
+ "acceptance_level": "ciso",
1088
+ "compensating_controls_in_place": [
1089
+ "credentials-rotated",
1090
+ "sessions-revoked",
1091
+ "imds-v2-enforced",
1092
+ "federated-trust-tightened",
1093
+ "scp-quarantine-attached",
1094
+ "audit-log-baseline-captured",
1095
+ "egress-dlp-monitoring-extended"
1096
+ ]
1097
+ },
1098
+ "evidence_requirements": [
1099
+ {
1100
+ "evidence_type": "scan_report",
1101
+ "description": "Pre-remediation 90-day audit-log scan output with indicator firings + RWEP per finding + blast-radius computation. Plus post-remediation rescan showing clean state.",
1102
+ "retention_period": "7_years",
1103
+ "framework_satisfied": [
1104
+ "nist-800-53-AC-2",
1105
+ "iso-27001-2022-A.5.15",
1106
+ "soc2-cc6.1",
1107
+ "fedramp-il5-ac-2"
1108
+ ]
1109
+ },
1110
+ {
1111
+ "evidence_type": "log_excerpt",
1112
+ "description": "Cloud audit-log excerpt for the compromise window for each rotated principal.",
1113
+ "retention_period": "7_years",
1114
+ "framework_satisfied": [
1115
+ "gdpr-art-33",
1116
+ "soc2-cc7.2",
1117
+ "nis2-art21-2c",
1118
+ "dora-art-19"
1119
+ ]
1120
+ },
1121
+ {
1122
+ "evidence_type": "ticket_reference",
1123
+ "description": "Rotation ticket(s) with timestamps, approvers, CSP rotation-confirmation IDs (AWS IAM new key-id, GCP new key fingerprint, Azure new credential object-id).",
1124
+ "retention_period": "7_years",
1125
+ "framework_satisfied": [
1126
+ "soc2-cc8.1",
1127
+ "iso-27001-2022-A.8.32"
1128
+ ]
1129
+ },
1130
+ {
1131
+ "evidence_type": "config_diff",
1132
+ "description": "Before/after diff of SCP / Org Policy / Management Group state; federated-trust-policy diff; IMDS enforcement state diff.",
1133
+ "retention_period": "7_years",
1134
+ "framework_satisfied": [
1135
+ "iso-27001-2022-A.5.23",
1136
+ "nist-800-53-CM-3",
1137
+ "soc2-cc8.1"
1138
+ ]
1139
+ },
1140
+ {
1141
+ "evidence_type": "attestation",
1142
+ "description": "Signed exceptd attestation: account identity, scan timestamp, indicator firings, RWEP at detection, RWEP post-remediation, rotated principal IDs (hashed).",
1143
+ "retention_period": "7_years",
1144
+ "framework_satisfied": [
1145
+ "nist-800-53-CA-7",
1146
+ "iso-27001-2022-A.5.36",
1147
+ "nis2-art21-2c"
1148
+ ]
1149
+ }
1150
+ ],
1151
+ "regression_trigger": [
1152
+ {
1153
+ "condition": "post_iam_change",
1154
+ "interval": "on_event"
1155
+ },
1156
+ {
1157
+ "condition": "weekly_audit_log_review",
1158
+ "interval": "7d"
1159
+ },
1160
+ {
1161
+ "condition": "post_federated_idp_change",
1162
+ "interval": "on_event"
1163
+ },
1164
+ {
1165
+ "condition": "monthly_full_rescan",
1166
+ "interval": "30d"
1167
+ }
1168
+ ]
1169
+ },
1170
+ "close": {
1171
+ "evidence_package": {
1172
+ "bundle_format": "csaf-2.0",
1173
+ "contents": [
1174
+ "scan_report",
1175
+ "log_excerpt",
1176
+ "config_diff",
1177
+ "ticket_reference",
1178
+ "attestation",
1179
+ "framework_gap_mapping",
1180
+ "compliance_theater_verdict",
1181
+ "residual_risk_statement",
1182
+ "incident_response_timeline"
1183
+ ],
1184
+ "destination": "local_only",
1185
+ "signed": true
1186
+ },
1187
+ "learning_loop": {
1188
+ "enabled": true,
1189
+ "lesson_template": {
1190
+ "attack_vector": "Cloud-IAM compromise via $vector ($csp): root-login-from-new-ASN / cross-account-assume-role-chain / leaked-access-key-from-public-repo / managed-identity-token-replay / federated-trust-wildcard-subject / IMDSv1-SSRF / mass-IAM-creation-outside-IaC.",
1191
+ "control_gap": "Account-lifecycle controls (NIST AC-2, ISO A.5.15, SOC 2 CC6) treat principals individually and miss cross-boundary chains. Posture tools (Security Hub / SCC / Defender for Cloud) are coverage-based and miss behavioural anomalies. Federated-trust hygiene is not enumerated in any framework's evidence surface.",
1192
+ "framework_gap": "NIST 800-53 AC-2 + ISO/IEC 27001:2022 A.5.15-A.5.18 + SOC 2 CC6 + FedRAMP IL5 baseline + UK CAF B2 + AU ISM-1546 + AU Essential 8 Strategy 4 collectively cover account lifecycle + human MFA + posture-tool deployment. None name cross-account assume-role chains, federated-trust wildcard-subject claims, managed-identity token replay, or IMDS-version-hardening as distinct control classes.",
1193
+ "new_control_requirement": "Continuous behavioural CloudTrail / audit-log analytics keyed off the detect.indicators in this playbook; federated-trust hygiene attestation (non-wildcard subject claims, audience-pinned); IMDSv2-required SCP / Org Policy enforced org-wide; cross-account assume-role graph monitoring over rolling 24h windows; managed-identity / service-account credential TTL ceilings with audience binding; cross-system credential-reuse mapping for every federated IdP."
1194
+ },
1195
+ "feeds_back_to_skills": [
1196
+ "cloud-security",
1197
+ "cred-stores",
1198
+ "framework-gap-analysis",
1199
+ "compliance-theater",
1200
+ "incident-response-playbook"
1201
+ ]
1202
+ },
1203
+ "notification_actions": [
1204
+ {
1205
+ "obligation_ref": "EU/GDPR Art.33 72h",
1206
+ "deadline": "computed_at_runtime",
1207
+ "recipient": "internal_legal",
1208
+ "evidence_attached": [
1209
+ "compromised_principal_inventory",
1210
+ "data_subject_impact_assessment",
1211
+ "containment_record"
1212
+ ],
1213
+ "draft_notification": "GDPR Art.33 72-hour notification: Cloud-IAM compromise event affecting ${principal_count} principal(s) across ${account_count} ${csp_name} account(s). Compromise window: ${exposure_window}. Affected processing operations: ${processing_operations}. Categories of data subjects potentially affected: ${data_subject_categories}. Containment actions: credentials rotated, sessions revoked, SCP quarantine attached, IMDSv2 enforced, federated trust tightened. Risk assessment: ${risk_level}. No notification to data subjects required because ${art34_reasoning} OR notification to data subjects required and being prepared. Contact: ${dpo_contact}."
1214
+ },
1215
+ {
1216
+ "obligation_ref": "EU/GDPR Art.34 72h",
1217
+ "deadline": "computed_at_runtime",
1218
+ "recipient": "data_subjects",
1219
+ "evidence_attached": [
1220
+ "data_subject_categories_affected",
1221
+ "containment_record"
1222
+ ],
1223
+ "draft_notification": "GDPR Art.34 notification to data subjects (draft for review): We are writing to inform you of a cloud-account compromise incident affecting systems that process your personal data. Affected systems: ${affected_systems}. Compromise window: ${exposure_window}. Containment actions completed: credentials rotated and revoked, sessions revoked, account quarantine attached, audit logs reviewed. Steps you can take: ${recommended_actions}. Our DPO can be reached at ${dpo_contact}."
1224
+ },
1225
+ {
1226
+ "obligation_ref": "EU/NIS2 Art.23 24h",
1227
+ "deadline": "computed_at_runtime",
1228
+ "recipient": "internal_legal",
1229
+ "evidence_attached": [
1230
+ "compromised_principal_inventory",
1231
+ "exposure_window_estimate",
1232
+ "rotation_status"
1233
+ ],
1234
+ "draft_notification": "NIS2 Art.23 early-warning notification: Cloud-IAM compromise on ${account_count} ${csp_name} account(s); ${principal_count} principal(s) involved. Suspected window of exposure: ${exposure_window}. Initial containment: credentials rotated, sessions revoked, SCP quarantine attached. Full incident assessment within 72h per Art.23(4)."
1235
+ },
1236
+ {
1237
+ "obligation_ref": "EU/DORA Art.19 4h",
1238
+ "deadline": "computed_at_runtime",
1239
+ "recipient": "internal_legal",
1240
+ "evidence_attached": [
1241
+ "major_ict_incident_classification",
1242
+ "affected_critical_or_important_function",
1243
+ "initial_containment_record"
1244
+ ],
1245
+ "draft_notification": "DORA Art.19 initial notification (4h): Major ICT incident classification — cloud-IAM compromise. Affected critical-or-important function(s): ${affected_ciofs}. CSP: ${csp_name}. Initial containment: credentials rotated, sessions revoked, account quarantine attached. Further reports per Art.19(4) at 72h and 1 month."
1246
+ },
1247
+ {
1248
+ "obligation_ref": "UK/UK GDPR Art.33 72h",
1249
+ "deadline": "computed_at_runtime",
1250
+ "recipient": "internal_legal",
1251
+ "evidence_attached": [
1252
+ "compromised_principal_inventory",
1253
+ "data_subject_impact_assessment"
1254
+ ],
1255
+ "draft_notification": "UK GDPR Art.33 72-hour notification to ICO: Cloud-IAM compromise event. Mirror of GDPR Art.33 notification body, addressed to ICO casework team."
1256
+ },
1257
+ {
1258
+ "obligation_ref": "US-NY/23 NYCRR 500.17 cyber event notification 72h",
1259
+ "deadline": "computed_at_runtime",
1260
+ "recipient": "internal_legal",
1261
+ "evidence_attached": [
1262
+ "cyber_event_classification",
1263
+ "ciso_acknowledgement"
1264
+ ],
1265
+ "draft_notification": "23 NYCRR 500.17 cyber event notification: Cloud-IAM compromise on ${account_count} ${csp_name} account(s). CISO acknowledgement: ${ciso_name}. Initial containment: credentials rotated, sessions revoked, account quarantine attached. Written explanation within 30 days per 500.17(c)."
1266
+ },
1267
+ {
1268
+ "obligation_ref": "US-CA/CCPA / CPRA Sec.1798.82 1440h",
1269
+ "deadline": "computed_at_runtime",
1270
+ "recipient": "data_subjects",
1271
+ "evidence_attached": [
1272
+ "california_resident_records_affected",
1273
+ "containment_record"
1274
+ ],
1275
+ "draft_notification": "California breach notification: We are writing to notify you of a security incident that may have affected your personal information. ${incident_description}. ${types_of_information_affected}. ${steps_taken}. ${steps_individuals_can_take}. ${contact_information}."
1276
+ },
1277
+ {
1278
+ "obligation_ref": "JP/APPI Art.26 24h",
1279
+ "deadline": "computed_at_runtime",
1280
+ "recipient": "internal_legal",
1281
+ "evidence_attached": [
1282
+ "compromised_principal_inventory",
1283
+ "japanese_resident_records_affected"
1284
+ ],
1285
+ "draft_notification": "APPI Art.26 notification to PPC: Cloud-IAM compromise affecting ${japanese_record_count} Japanese resident records. Containment actions: ${containment_actions}. Reporter: ${ppc_contact}."
1286
+ },
1287
+ {
1288
+ "obligation_ref": "SG/PDPA Notification Obligation s26D 72h",
1289
+ "deadline": "computed_at_runtime",
1290
+ "recipient": "internal_legal",
1291
+ "evidence_attached": [
1292
+ "singapore_resident_records_affected",
1293
+ "containment_record"
1294
+ ],
1295
+ "draft_notification": "PDPA s26D notification to PDPC: Cloud-IAM compromise affecting ${singapore_record_count} Singapore resident records. Containment actions: ${containment_actions}. Reporter: ${dpo_contact}."
1296
+ }
1297
+ ],
1298
+ "exception_generation": {
1299
+ "trigger_condition": "coordinated_rotation_required == true OR (compromised_principal_class == 'federated_idp_root' AND rotation_eta > obligation_window)",
1300
+ "exception_template": {
1301
+ "scope": "Cloud-IAM principal of class ${principal_class} (${principal_id_hash}) cannot be rotated within ${obligation_window} due to ${blocking_reason}.",
1302
+ "duration": "until_vendor_patch",
1303
+ "compensating_controls": [
1304
+ "enhanced-audit-log-alerting-on-principal-use",
1305
+ "incident-response-team-on-standby",
1306
+ "ip-allowlist-tightened-on-principal",
1307
+ "rate-limit-on-principal-tightened",
1308
+ "scp-deny-non-essential-actions-on-principal"
1309
+ ],
1310
+ "risk_acceptance_owner": "ciso",
1311
+ "auditor_ready_language": "Pursuant to ${framework_id} ${control_id}, the organization documents a time-bound risk acceptance for unrotated cloud-IAM principal ${principal_class} (${principal_id_hash}) across ${affected_account_count} account(s). Blocking reason: ${blocking_reason_narrative}. Rotation ETA: ${rotation_eta}. Compensating controls in place: ${compensating_controls}. Residual exposure: principal remains valid; CSP audit logs are reviewed daily during the exception window for misuse indicators. Risk accepted by ${ciso_name} on ${acceptance_date}. Time-bound until ${duration_expiry} OR rotation completion, whichever is first. Detection coverage is provided by ${detection_controls}. The exception will be re-evaluated on (a) rotation completion, (b) listed expiry date, (c) any audit-log anomaly on the principal — whichever is first."
1312
+ }
1313
+ },
1314
+ "regression_schedule": {
1315
+ "next_run": "computed_at_runtime",
1316
+ "trigger": "both",
1317
+ "notify_on_skip": true
1318
+ }
1319
+ }
1320
+ },
1321
+ "directives": [
1322
+ {
1323
+ "id": "aws-root-account-compromise",
1324
+ "title": "AWS root-account compromise — root-login-from-new-ASN response",
1325
+ "applies_to": {
1326
+ "attack_technique": "T1078.004"
1327
+ }
1328
+ },
1329
+ {
1330
+ "id": "gcp-service-account-key-leak",
1331
+ "title": "GCP service-account key leak — JSON key found on public-code-search surface",
1332
+ "applies_to": {
1333
+ "attack_technique": "T1552.005"
1334
+ }
1335
+ },
1336
+ {
1337
+ "id": "azure-managed-identity-replay",
1338
+ "title": "Azure managed-identity token replay — IMDS-exfilled token used from non-instance source",
1339
+ "applies_to": {
1340
+ "attack_technique": "T1552.005"
1341
+ }
1342
+ },
1343
+ {
1344
+ "id": "cross-account-assume-role-chain",
1345
+ "title": "Cross-account assume-role chain anomaly — chains >= 2 boundaries with common source principal",
1346
+ "applies_to": {
1347
+ "attack_technique": "T1078.004"
1348
+ }
1349
+ }
1350
+ ]
1351
+ }