@blamejs/exceptd-skills 0.12.40 → 0.13.0

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 (97) hide show
  1. package/AGENTS.md +17 -0
  2. package/ARCHITECTURE.md +7 -4
  3. package/CHANGELOG.md +215 -248
  4. package/CONTEXT.md +2 -2
  5. package/README.md +2 -8
  6. package/agents/threat-researcher.md +2 -2
  7. package/bin/exceptd.js +179 -81
  8. package/data/_indexes/_meta.json +50 -50
  9. package/data/_indexes/activity-feed.json +1 -1
  10. package/data/_indexes/catalog-summaries.json +1 -1
  11. package/data/_indexes/chains.json +485 -13
  12. package/data/_indexes/frequency.json +4 -0
  13. package/data/_indexes/jurisdiction-map.json +15 -4
  14. package/data/_indexes/section-offsets.json +1224 -1224
  15. package/data/_indexes/token-budget.json +170 -170
  16. package/data/atlas-ttps.json +54 -11
  17. package/data/attack-techniques.json +113 -17
  18. package/data/cve-catalog.json +38 -52
  19. package/data/cwe-catalog.json +8 -2
  20. package/data/exploit-availability.json +1 -0
  21. package/data/framework-control-gaps.json +149 -6
  22. package/data/global-frameworks.json +1 -0
  23. package/data/playbooks/ai-api.json +5 -0
  24. package/data/playbooks/cicd-pipeline-compromise.json +970 -0
  25. package/data/playbooks/cloud-iam-incident.json +4 -1
  26. package/data/playbooks/cred-stores.json +10 -0
  27. package/data/playbooks/crypto-codebase.json +13 -0
  28. package/data/playbooks/framework.json +16 -0
  29. package/data/playbooks/hardening.json +4 -0
  30. package/data/playbooks/identity-sso-compromise.json +951 -0
  31. package/data/playbooks/idp-incident.json +3 -0
  32. package/data/playbooks/kernel.json +6 -0
  33. package/data/playbooks/llm-tool-use-exfil.json +963 -0
  34. package/data/playbooks/mcp.json +6 -0
  35. package/data/playbooks/runtime.json +4 -0
  36. package/data/playbooks/sbom.json +13 -0
  37. package/data/playbooks/secrets.json +6 -0
  38. package/data/playbooks/webhook-callback-abuse.json +916 -0
  39. package/data/zeroday-lessons.json +1 -0
  40. package/lib/cross-ref-api.js +33 -13
  41. package/lib/cve-curation.js +12 -1
  42. package/lib/exit-codes.js +29 -0
  43. package/lib/lint-skills.js +25 -3
  44. package/lib/playbook-runner.js +8 -4
  45. package/lib/refresh-external.js +10 -1
  46. package/lib/scoring.js +64 -1
  47. package/lib/sign.js +40 -7
  48. package/lib/verify.js +5 -5
  49. package/manifest.json +83 -83
  50. package/orchestrator/README.md +7 -7
  51. package/orchestrator/index.js +46 -25
  52. package/orchestrator/scheduler.js +2 -2
  53. package/package.json +1 -1
  54. package/sbom.cdx.json +135 -91
  55. package/scripts/check-test-coverage.js +6 -6
  56. package/scripts/predeploy.js +7 -13
  57. package/scripts/refresh-reverse-refs.js +107 -20
  58. package/scripts/refresh-sbom.js +21 -4
  59. package/skills/age-gates-child-safety/skill.md +1 -5
  60. package/skills/ai-attack-surface/skill.md +11 -4
  61. package/skills/ai-c2-detection/skill.md +11 -2
  62. package/skills/ai-risk-management/skill.md +4 -2
  63. package/skills/api-security/skill.md +7 -8
  64. package/skills/attack-surface-pentest/skill.md +2 -2
  65. package/skills/cloud-iam-incident/skill.md +1 -5
  66. package/skills/cloud-security/skill.md +0 -4
  67. package/skills/compliance-theater/skill.md +10 -2
  68. package/skills/container-runtime-security/skill.md +1 -3
  69. package/skills/dlp-gap-analysis/skill.md +3 -4
  70. package/skills/email-security-anti-phishing/skill.md +1 -8
  71. package/skills/exploit-scoring/skill.md +7 -2
  72. package/skills/framework-gap-analysis/skill.md +1 -1
  73. package/skills/fuzz-testing-strategy/skill.md +1 -2
  74. package/skills/global-grc/skill.md +3 -2
  75. package/skills/identity-assurance/skill.md +1 -3
  76. package/skills/idp-incident-response/skill.md +1 -4
  77. package/skills/incident-response-playbook/skill.md +1 -5
  78. package/skills/kernel-lpe-triage/skill.md +2 -2
  79. package/skills/mcp-agent-trust/skill.md +13 -3
  80. package/skills/mlops-security/skill.md +3 -4
  81. package/skills/ot-ics-security/skill.md +0 -3
  82. package/skills/policy-exception-gen/skill.md +11 -3
  83. package/skills/pqc-first/skill.md +4 -2
  84. package/skills/rag-pipeline-security/skill.md +2 -0
  85. package/skills/ransomware-response/skill.md +1 -5
  86. package/skills/researcher/skill.md +4 -3
  87. package/skills/sector-energy/skill.md +0 -4
  88. package/skills/sector-federal-government/skill.md +2 -3
  89. package/skills/sector-financial/skill.md +1 -4
  90. package/skills/sector-healthcare/skill.md +0 -5
  91. package/skills/sector-telecom/skill.md +0 -4
  92. package/skills/security-maturity-tiers/skill.md +1 -2
  93. package/skills/skill-update-loop/skill.md +4 -3
  94. package/skills/supply-chain-integrity/skill.md +4 -3
  95. package/skills/threat-model-currency/skill.md +1 -1
  96. package/skills/threat-modeling-methodology/skill.md +2 -1
  97. package/skills/webapp-security/skill.md +0 -5
@@ -0,0 +1,951 @@
1
+ {
2
+ "_meta": {
3
+ "id": "identity-sso-compromise",
4
+ "version": "1.0.0",
5
+ "last_threat_review": "2026-05-17",
6
+ "threat_currency_score": 94,
7
+ "changelog": [
8
+ {
9
+ "version": "1.0.0",
10
+ "date": "2026-05-17",
11
+ "summary": "Initial seven-phase in-progress IdP-compromise DETECTION playbook. Counterpart to idp-incident (post-incident response): this playbook walks the IdP control-plane for indicators that compromise IS happening now — tenant-admin-tier persistence (extra global-admin grants, new OAuth-application owner additions), OAuth refresh-token hoarding (anomalous refresh-token issuance volume per service principal), conditional-access policy tampering (newly-introduced bypass rules, weakened MFA requirements), Primary Refresh Token (PRT) theft signatures (TokenSigningCertificate exports, device-registration anomalies), and golden-SAML / AD FS signing-cert misuse. Detection-side counterpart to the post-incident response in idp-incident; escalates into idp-incident when detection confirms compromise.",
12
+ "framework_gaps_updated": [
13
+ "nist-800-53-AC-2(11)-anomaly-detection",
14
+ "nist-800-53-IA-5-token-hoarding",
15
+ "iso-27001-2022-A.8.16-monitoring-activity-IdP",
16
+ "soc2-CC7.2-detection-IdP-plane",
17
+ "uk-caf-C1-security-monitoring-IdP",
18
+ "au-essential-8-ML3-detection-event-logging"
19
+ ]
20
+ }
21
+ ],
22
+ "owner": "@blamejs/grc",
23
+ "air_gap_mode": false,
24
+ "scope": "service",
25
+ "preconditions": [
26
+ {
27
+ "id": "idp-audit-api-reachable",
28
+ "description": "The IdP tenant's audit-log API must be reachable for read-only enumeration (Okta /api/v1/logs, Entra ID /auditLogs/signIns + /auditLogs/directoryAudits via Graph, Auth0 /api/v2/logs, Ping /environments/{id}/auditTrails, OneLogin /api/2/events).",
29
+ "check": "idp_audit_api_reachable == true",
30
+ "on_fail": "halt"
31
+ },
32
+ {
33
+ "id": "read-only-admin-rbac",
34
+ "description": "Operator must hold at minimum a Read-only Admin / Reports Reader / Global Reader role sufficient to enumerate sign-ins, audit events, consent grants, federated-trust configuration, conditional-access policy state, and privileged-role assignments. A read-only role keeps the detection sweep from introducing additional attack surface.",
35
+ "check": "operator_has_idp_read_admin == true",
36
+ "on_fail": "halt"
37
+ },
38
+ {
39
+ "id": "tenant-ownership",
40
+ "description": "The operator must own the tenant under investigation (or hold explicit written authorisation from the tenant owner).",
41
+ "check": "tenant_ownership_attested == true",
42
+ "on_fail": "halt"
43
+ }
44
+ ],
45
+ "mutex": [],
46
+ "feeds_into": [
47
+ {
48
+ "playbook_id": "idp-incident",
49
+ "condition": "phases.detect.classification == 'detected'"
50
+ },
51
+ {
52
+ "playbook_id": "cred-stores",
53
+ "condition": "analyze.blast_radius_score >= 3"
54
+ },
55
+ {
56
+ "playbook_id": "cloud-iam-incident",
57
+ "condition": "finding.includes_cloud_role_assumption == true"
58
+ },
59
+ {
60
+ "playbook_id": "framework",
61
+ "condition": "analyze.compliance_theater_check.verdict == 'theater'"
62
+ }
63
+ ]
64
+ },
65
+ "domain": {
66
+ "name": "Identity-provider in-progress compromise detection (SSO / federated-trust plane)",
67
+ "attack_class": "identity-abuse",
68
+ "atlas_refs": [
69
+ "AML.T0048",
70
+ "AML.T0096"
71
+ ],
72
+ "attack_refs": [
73
+ "T1078.004",
74
+ "T1556.007",
75
+ "T1098.001",
76
+ "T1606.002",
77
+ "T1199",
78
+ "T1528"
79
+ ],
80
+ "cve_refs": [
81
+ "CVE-2024-1709"
82
+ ],
83
+ "cwe_refs": [
84
+ "CWE-287",
85
+ "CWE-269",
86
+ "CWE-284",
87
+ "CWE-522",
88
+ "CWE-345",
89
+ "CWE-863"
90
+ ],
91
+ "d3fend_refs": [
92
+ "D3-MFA",
93
+ "D3-NTA",
94
+ "D3-IOPR",
95
+ "D3-CBAN"
96
+ ],
97
+ "frameworks_in_scope": [
98
+ "nist-800-53",
99
+ "nist-csf-2",
100
+ "iso-27001-2022",
101
+ "soc2",
102
+ "nis2",
103
+ "dora",
104
+ "uk-caf",
105
+ "au-ism",
106
+ "au-essential-8",
107
+ "hipaa"
108
+ ]
109
+ },
110
+ "phases": {
111
+ "govern": {
112
+ "jurisdiction_obligations": [
113
+ {
114
+ "jurisdiction": "EU",
115
+ "regulation": "NIS2 Art.23",
116
+ "obligation": "notify_regulator",
117
+ "window_hours": 24,
118
+ "clock_starts": "detect_confirmed",
119
+ "evidence_required": [
120
+ "idp_audit_log_excerpt",
121
+ "exposure_window_estimate",
122
+ "rotation_status"
123
+ ]
124
+ },
125
+ {
126
+ "jurisdiction": "EU",
127
+ "regulation": "DORA Art.19",
128
+ "obligation": "notify_regulator",
129
+ "window_hours": 4,
130
+ "clock_starts": "detect_confirmed",
131
+ "evidence_required": [
132
+ "idp_audit_log_excerpt",
133
+ "affected_critical_or_important_functions",
134
+ "containment_record"
135
+ ]
136
+ },
137
+ {
138
+ "jurisdiction": "EU",
139
+ "regulation": "GDPR Art.33",
140
+ "obligation": "notify_regulator",
141
+ "window_hours": 72,
142
+ "clock_starts": "detect_confirmed",
143
+ "evidence_required": [
144
+ "idp_audit_log_excerpt",
145
+ "data_subject_impact_assessment"
146
+ ]
147
+ },
148
+ {
149
+ "jurisdiction": "UK",
150
+ "regulation": "UK GDPR Art.33",
151
+ "obligation": "notify_regulator",
152
+ "window_hours": 72,
153
+ "clock_starts": "detect_confirmed",
154
+ "evidence_required": [
155
+ "idp_audit_log_excerpt",
156
+ "data_subject_impact_assessment"
157
+ ]
158
+ },
159
+ {
160
+ "jurisdiction": "US-Federal",
161
+ "regulation": "SEC Item 1.05 (8-K)",
162
+ "obligation": "notify_regulator",
163
+ "window_hours": 96,
164
+ "clock_starts": "analyze_complete",
165
+ "evidence_required": [
166
+ "material_impact_determination",
167
+ "incident_description"
168
+ ]
169
+ },
170
+ {
171
+ "jurisdiction": "AU",
172
+ "regulation": "Privacy Act 1988 — Notifiable Data Breaches scheme (s26WK)",
173
+ "obligation": "notify_regulator",
174
+ "window_hours": 720,
175
+ "clock_starts": "analyze_complete",
176
+ "evidence_required": [
177
+ "australian_resident_records_affected",
178
+ "remediation_completed_evidence"
179
+ ]
180
+ }
181
+ ],
182
+ "theater_fingerprints": [
183
+ {
184
+ "pattern_id": "mfa-enrollment-as-detection",
185
+ "claim": "Every user has MFA enrolled and conditional access requires MFA on every sign-in, therefore IdP compromise is detectable from sign-in logs alone.",
186
+ "fast_detection_test": "Verify whether the conditional-access policy is actually IN ENFORCING state for the named tenant — not report-only — and whether there exist exclusion groups (Break-Glass accounts, sync accounts, app service principals) that bypass MFA in scope. MFA enrolled ≠ MFA enforced; conditional-access in report-only generates audit signals but does not BLOCK the attacker that has the password.",
187
+ "implicated_controls": [
188
+ "nist-800-53-IA-2(1)",
189
+ "iso-27001-2022-A.5.17",
190
+ "soc2-cc6.6"
191
+ ]
192
+ },
193
+ {
194
+ "pattern_id": "audit-log-collected-therefore-monitored",
195
+ "claim": "Sign-in + directory-audit logs are streamed to the SIEM, therefore IdP-plane compromise will be detected.",
196
+ "fast_detection_test": "Distinguish 'logs collected' from 'detection rules deployed'. Confirm the SIEM has active rules for: (a) new global-admin grant outside change-management window, (b) anomalous refresh-token issuance volume per service principal, (c) conditional-access policy modification, (d) federation signing-certificate addition or rotation. Logs without rules are storage, not detection."
197
+ },
198
+ {
199
+ "pattern_id": "okta-support-session-as-out-of-scope",
200
+ "claim": "Vendor support sessions (Okta, Microsoft FastTrack) are vendor responsibility, so we don't audit them.",
201
+ "fast_detection_test": "Enumerate any vendor-side admin access historically granted to the tenant. The 2023 Okta customer-support compromise was the canonical incident where attacker traffic looked like legitimate vendor sessions. Every vendor session should be audited as if it were a tenant-admin session, with timing + IP + RBAC scope cross-checked against the support case it claims to back."
202
+ }
203
+ ],
204
+ "framework_context": {
205
+ "gap_summary": "IdP-plane in-progress detection has structural gaps across NIST 800-53, ISO 27001:2022, SOC 2, NIS2, and APRA / Essential 8. The frameworks describe access management at the user-identity layer and detection at the SIEM-rule layer, but the IdP control plane sits between: who has tenant-admin? which app service principals have refresh-token hoarding patterns? which conditional-access policies have exclusion groups whose membership changes silently? NIST AC-2(11) names automated session monitoring but not IdP-control-plane-specific anomaly detection. ISO A.8.16 covers monitoring of system activity but does not bind to IdP-tenant-admin event semantics. SOC 2 CC7.2 covers system monitoring and CC6.6 covers logical access boundaries but not the IdP tenant-admin or OAuth-consent boundary. UK CAF C1 (Security monitoring) is outcome-based and does not specify IdP-control-plane detection rules. AU Essential 8 ML3 multi-factor authentication is about enforcement, not detection of bypass. The result: an IdP tenant where Salt Typhoon-class persistence or Scattered Spider-class consent abuse is in progress can satisfy literal framework controls while the attacker holds the IdP plane.",
206
+ "lag_score": 26,
207
+ "per_framework_gaps": [
208
+ {
209
+ "framework": "nist-800-53",
210
+ "control_id": "AC-2(11) — Account Management — Usage Conditions",
211
+ "designed_for": "Automated monitoring of account usage conditions and anomalies.",
212
+ "insufficient_because": "Does not specify IdP-control-plane-specific signals (admin-role-grant outside change window, refresh-token hoarding by service principal, federation-signing-cert addition). Generic anomaly-detection rules miss these unless explicitly authored."
213
+ },
214
+ {
215
+ "framework": "iso-27001-2022",
216
+ "control_id": "A.8.16 — Monitoring activities",
217
+ "designed_for": "Monitoring system activity for anomalies.",
218
+ "insufficient_because": "Does not bind to IdP-tenant-admin event semantics. The control passes with generic SIEM collection but does not require IdP-plane-specific detection rules."
219
+ },
220
+ {
221
+ "framework": "soc2",
222
+ "control_id": "CC7.2 — System monitoring",
223
+ "designed_for": "Monitoring system components and the operation of controls.",
224
+ "insufficient_because": "Treats the IdP as a vendor-managed component out of scope; in-progress detection in the IdP control plane is not assessed."
225
+ },
226
+ {
227
+ "framework": "nis2",
228
+ "control_id": "Art.21(2)(f) — Policies and procedures regarding the use of multi-factor authentication",
229
+ "designed_for": "MFA enforcement policy for essential entities.",
230
+ "insufficient_because": "Specifies enforcement; silent on detection of MFA-bypass patterns (conditional-access exclusion group changes, app-passwords issuance, legacy-auth re-enablement). MFA-enforced posture can coexist with active MFA-bypass."
231
+ },
232
+ {
233
+ "framework": "uk-caf",
234
+ "control_id": "C1 — Security monitoring",
235
+ "designed_for": "Outcome — the organisation monitors security-relevant activity.",
236
+ "insufficient_because": "Outcome-based, not IdP-control-plane-specific. Regulator interpretation varies; a SIEM with generic anomaly rules and no IdP-plane rules can defensibly satisfy C1."
237
+ },
238
+ {
239
+ "framework": "au-essential-8",
240
+ "control_id": "Strategy 6 — Multi-factor authentication",
241
+ "designed_for": "ASD mitigation strategy for MFA, with maturity levels 1-3.",
242
+ "insufficient_because": "Strategy 6 is about MFA enforcement scope and phishing-resistance; not about detection of in-progress IdP-plane compromise that bypasses MFA via the control plane (admin-tier grant, federation signing-cert misuse, golden-SAML)."
243
+ }
244
+ ]
245
+ },
246
+ "skill_preload": [
247
+ "identity-assurance",
248
+ "idp-incident-response",
249
+ "framework-gap-analysis",
250
+ "compliance-theater",
251
+ "policy-exception-gen"
252
+ ]
253
+ },
254
+ "direct": {
255
+ "threat_context": "Q1-Q2 2026 IdP-compromise-in-progress landscape. Salt Typhoon's telecom intrusions in 2024-2025 included tenant-admin-tier persistence inside Entra ID + Okta tenants belonging to critical-infrastructure carriers — the attacker held the IdP plane for weeks before lateral movement, and the detection signal that surfaced compromise was IdP-control-plane (admin-role grant out of normal change window) rather than endpoint or network. Scattered Spider's 2024-2025 SaaS-supply-chain attacks routinely abused OAuth-app-consent grants to access mailboxes + repositories + SaaS data without triggering MFA prompts on the victim user. The 2023 Okta customer-support session-theft incident remains a foundational reminder: vendor-tier admin access is in-scope for monitoring, and the attacker did not need to pass MFA at the customer tenant — they used vendor-side session material. Golden-SAML technique (signing-certificate theft from AD FS or Entra ID federation trust) is operational since 2020 (Solarigate origin) and remains in active use; the detection signature is federation-trust-config modification + sudden signed-assertion volume increase. Primary Refresh Token (PRT) theft, primarily via TokenBroker or seamless-SSO endpoints on a compromised endpoint, gives the attacker indefinite tenant access without re-authentication. The AI-attack dimension: AML.T0048 (model exfiltration) + AML.T0096 (LLM plugin compromise) cross into the IdP plane when an attacker abuses an LLM tool's OAuth grant against the IdP itself — refresh-token hoarding by an OAuth app is a credible AI-C2 fingerprint. This playbook detects compromise IN PROGRESS; the post-incident IR workflow lives in idp-incident.",
256
+ "rwep_threshold": {
257
+ "escalate": 85,
258
+ "monitor": 65,
259
+ "close": 30
260
+ },
261
+ "framework_lag_declaration": "NIST 800-53 AC-2(11) + IA-5, ISO 27001 A.8.16, SOC 2 CC7.2 + CC6.6, NIS2 Art.21(2)(f), UK CAF C1, AU Essential 8 ML3, AU ISM-1559 collectively underspecify in-progress IdP-control-plane compromise detection. None mandate the specific IdP-plane signals: admin-role grant outside change-management window, refresh-token hoarding per service principal, conditional-access exclusion-group membership changes, federation signing-certificate additions or rotations, OAuth-app-consent grants with high-impact scopes (Mail.ReadWrite, Files.ReadWrite.All, full_access_as_app). MFA enforcement (Art.21(2)(f), Strategy 6) coexists with active control-plane bypass. The Salt Typhoon, Scattered Spider, and 2023 Okta cases each satisfied literal framework readings while the attacker held the IdP plane.",
262
+ "skill_chain": [
263
+ {
264
+ "skill": "identity-assurance",
265
+ "purpose": "Establish baseline identity assurance state for the tenant: which auth methods are enforced, which exclusion groups exist, which OAuth apps have high-impact scopes.",
266
+ "required": true
267
+ },
268
+ {
269
+ "skill": "idp-incident-response",
270
+ "purpose": "Load IR context so that detected compromise can flow directly into the post-incident playbook without losing the detection-side evidence chain.",
271
+ "required": true
272
+ },
273
+ {
274
+ "skill": "framework-gap-analysis",
275
+ "purpose": "Map each detection finding to the framework control that should have caught it and why it didn't.",
276
+ "required": true
277
+ },
278
+ {
279
+ "skill": "compliance-theater",
280
+ "purpose": "Run the theater test — does the org's claimed IdP monitoring actually distinguish a normal admin-grant change-management window from an out-of-window grant?",
281
+ "required": true
282
+ },
283
+ {
284
+ "skill": "policy-exception-gen",
285
+ "purpose": "Generate auditor-ready exception language if a detection gap cannot be closed within the jurisdiction's window.",
286
+ "skip_if": "close.exception_generation.trigger_condition == false",
287
+ "required": false
288
+ }
289
+ ],
290
+ "token_budget": {
291
+ "estimated_total": 16500,
292
+ "breakdown": {
293
+ "govern": 2200,
294
+ "direct": 1700,
295
+ "look": 1700,
296
+ "detect": 2400,
297
+ "analyze": 3500,
298
+ "validate": 2800,
299
+ "close": 2200
300
+ }
301
+ }
302
+ },
303
+ "look": {
304
+ "artifacts": [
305
+ {
306
+ "id": "privileged-role-assignments",
307
+ "type": "api_response",
308
+ "source": "Entra ID: GET /directoryRoles + /directoryRoles/{id}/members via Graph (incl. PIM eligible AND active assignments). Okta: GET /api/v1/iam/assignees/users + roles inventory. Auth0: GET /api/v2/users-by-role.",
309
+ "description": "Current snapshot of every privileged-role assignment (Global Admin, Privileged Role Administrator, Tenant Owner, Super Admin, Application Administrator, Cloud Application Administrator, Conditional Access Administrator) with who holds it, since when, and via what assignment path.",
310
+ "required": true,
311
+ "air_gap_alternative": "Cached Graph / Okta JSON exports from the operator's SIEM if direct API is unreachable."
312
+ },
313
+ {
314
+ "id": "directory-audit-window",
315
+ "type": "audit_trail",
316
+ "source": "Entra ID: GET /auditLogs/directoryAudits?$filter=activityDateTime gt {now-30d} (Graph). Okta: GET /api/v1/logs?since={now-30d}. Auth0: GET /api/v2/logs with date filter.",
317
+ "description": "Last 30 days of directory-audit events, partitioned by category: role assignment, application registration, conditional-access policy change, federation-trust modification, certificate addition.",
318
+ "required": true,
319
+ "air_gap_alternative": "SIEM-side audit-log export covering the same 30-day window."
320
+ },
321
+ {
322
+ "id": "oauth-app-consent-inventory",
323
+ "type": "api_response",
324
+ "source": "Entra ID: GET /servicePrincipals + /oauth2PermissionGrants + /appRoleAssignments (Graph). Okta: GET /api/v1/apps and /api/v1/apps/{id}/grants. Per-service-principal capture: requested scopes, granted scopes, consenting user / admin, consent date.",
325
+ "description": "Every OAuth application granted access to the tenant, with the scopes consented and when.",
326
+ "required": true,
327
+ "air_gap_alternative": "Cached Graph / Okta JSON exports if API unreachable."
328
+ },
329
+ {
330
+ "id": "conditional-access-policy-state",
331
+ "type": "api_response",
332
+ "source": "Entra ID: GET /identity/conditionalAccess/policies (Graph). Okta: GET /api/v1/policies?type=ACCESS_POLICY. Per-policy capture: state (enabled/report-only/disabled), assignment scope, exclusion groups, MFA requirement, session controls.",
333
+ "description": "Every conditional-access (or equivalent access) policy with its current state and exclusion groups.",
334
+ "required": true,
335
+ "air_gap_alternative": "IaC source (Terraform azuread_conditional_access_policy / okta_policy resources) plus the last cached policy state from the SIEM."
336
+ },
337
+ {
338
+ "id": "refresh-token-issuance-baseline",
339
+ "type": "audit_trail",
340
+ "source": "Entra ID: GET /auditLogs/signIns?$filter=appId eq {sp-id} grouped by appId over 30d. Okta: /api/v1/logs with eventType=user.session.start filtered by client. Build a baseline of refresh-token issuance volume per service principal.",
341
+ "description": "30-day baseline of refresh-token issuance per service principal, used to surface refresh-token-hoarding patterns.",
342
+ "required": false,
343
+ "air_gap_alternative": "SIEM-aggregated baseline if reachable; if neither API nor SIEM is reachable, mark refresh-token-hoarding indicator as inconclusive."
344
+ },
345
+ {
346
+ "id": "federation-trust-config",
347
+ "type": "api_response",
348
+ "source": "Entra ID: GET /domains/{id}/federationConfiguration + /policies/tokenIssuancePolicies. AD FS: Get-AdfsRelyingPartyTrust + Get-AdfsCertificate -CertificateType Token-Signing. Okta: GET /api/v1/idps + signing-key metadata.",
349
+ "description": "Federation trust configuration, with token-signing certificate fingerprints and any recent additions.",
350
+ "required": false,
351
+ "air_gap_alternative": "Cached config export; if unavailable, mark golden-SAML-class indicators as inconclusive."
352
+ },
353
+ {
354
+ "id": "break-glass-and-sync-accounts",
355
+ "type": "api_response",
356
+ "source": "Inventory of tenant accounts excluded from conditional access (Entra ID Break Glass pattern, Okta super-admin override accounts, AD Connect / Cloud Sync service accounts).",
357
+ "description": "Accounts whose conditional-access exclusion is by design. Used to suppress noise on indicators that fire on legitimate excluded accounts.",
358
+ "required": false
359
+ }
360
+ ],
361
+ "collection_scope": {
362
+ "time_window": "30d",
363
+ "asset_scope": "single_idp_tenant",
364
+ "depth": "deep",
365
+ "sampling": "full tenant sweep, last 30 days of audit + sign-in events. Re-collect on every regression_trigger event."
366
+ },
367
+ "environment_assumptions": [
368
+ {
369
+ "assumption": "operator owns the tenant under investigation",
370
+ "if_false": "Halt with authorisation_required."
371
+ },
372
+ {
373
+ "assumption": "IdP admin API is reachable with read-only credentials",
374
+ "if_false": "Halt — IdP-plane visibility is load-bearing for this playbook."
375
+ },
376
+ {
377
+ "assumption": "audit retention covers at least the last 30 days",
378
+ "if_false": "Reduce time-window to actual retention; downgrade overall confidence to medium and emit a visibility note on the retention shortfall."
379
+ }
380
+ ],
381
+ "fallback_if_unavailable": [
382
+ {
383
+ "artifact_id": "refresh-token-issuance-baseline",
384
+ "fallback_action": "use_compensating_artifact",
385
+ "confidence_impact": "medium"
386
+ },
387
+ {
388
+ "artifact_id": "federation-trust-config",
389
+ "fallback_action": "mark_inconclusive",
390
+ "confidence_impact": "high"
391
+ },
392
+ {
393
+ "artifact_id": "oauth-app-consent-inventory",
394
+ "fallback_action": "escalate_to_human",
395
+ "confidence_impact": "high"
396
+ },
397
+ {
398
+ "artifact_id": "privileged-role-assignments",
399
+ "fallback_action": "escalate_to_human",
400
+ "confidence_impact": "high"
401
+ }
402
+ ]
403
+ },
404
+ "detect": {
405
+ "indicators": [
406
+ {
407
+ "id": "out-of-window-global-admin-grant",
408
+ "type": "log_pattern",
409
+ "value": "Directory-audit event 'Add member to role' or 'Activate role assignment' for a Tier-0 role (Global Admin, Privileged Role Administrator, Conditional Access Administrator, Application Administrator, Cloud Application Administrator, Tenant Owner) OUTSIDE the operator's documented change-management window.",
410
+ "description": "Tenant-admin-tier grant outside change-management = candidate persistence event. Salt Typhoon-class signature.",
411
+ "confidence": "deterministic",
412
+ "deterministic": true,
413
+ "attack_ref": "T1098.003",
414
+ "false_positive_checks_required": [
415
+ "Cross-check against the operator's change-management ticket system (Jira, ServiceNow, GitHub Issues) for a matching ticket within +/- 30 minutes. A matched ticket with appropriate approver downgrades to medium.",
416
+ "Confirm the actor identity is not a known break-glass account performing a legitimate emergency-access activation. Break-glass activations must STILL be reviewed but are not in themselves compromise indicators."
417
+ ]
418
+ },
419
+ {
420
+ "id": "high-impact-oauth-consent-grant",
421
+ "type": "log_pattern",
422
+ "value": "OAuth app consent grant with any of: Mail.ReadWrite, Mail.Send, Files.ReadWrite.All, Sites.FullControl.All, full_access_as_app, Application.ReadWrite.All, Directory.ReadWrite.All, RoleManagement.ReadWrite.Directory — granted to a service principal not on the operator's allowlist.",
423
+ "description": "Scattered Spider-class OAuth-consent abuse. High-impact scopes grant data + identity-plane reach without user-interactive MFA.",
424
+ "confidence": "deterministic",
425
+ "deterministic": true,
426
+ "attack_ref": "T1528",
427
+ "false_positive_checks_required": [
428
+ "Confirm the service principal is not a known first-party integration (Microsoft Teams, Power Automate, the operator's own AD app registrations). Allowlisting must be evidence-backed, not vibes.",
429
+ "Confirm the consenting actor was an admin (admin-consent flow) and that the admin's session itself is not already flagged on another indicator. Compromised admin granting consent counts twice — once as the grant, once as the admin-takeover."
430
+ ]
431
+ },
432
+ {
433
+ "id": "conditional-access-exclusion-membership-change",
434
+ "type": "log_pattern",
435
+ "value": "Group membership change adding a user to a group that is in the EXCLUSION list of one or more conditional-access policies (MFA bypass, location bypass, device-compliance bypass).",
436
+ "description": "Silent exclusion-group additions are a documented MFA-bypass primitive. The visible policy state doesn't change; only the membership does.",
437
+ "confidence": "deterministic",
438
+ "deterministic": true,
439
+ "attack_ref": "T1556.007",
440
+ "false_positive_checks_required": [
441
+ "Cross-check against the change-management ticket system. A matched ticket downgrades to medium.",
442
+ "Confirm the modified group IS in the exclusion list of at least one conditional-access policy currently in 'enabled' state. Exclusions on report-only or disabled policies are not active bypass paths."
443
+ ]
444
+ },
445
+ {
446
+ "id": "federation-signing-cert-added",
447
+ "type": "log_pattern",
448
+ "value": "Federation configuration event: TokenSigningCertificate added, federation-domain trust modified, or new token-issuance policy created.",
449
+ "description": "Golden-SAML signature — attacker adding a signing certificate they hold the private key for, enabling forged SAML assertions tenant-wide.",
450
+ "confidence": "deterministic",
451
+ "deterministic": true,
452
+ "attack_ref": "T1606.002",
453
+ "false_positive_checks_required": [
454
+ "Confirm the change was performed by a tenant-admin AND has a matching change-management ticket for token-signing rotation. Routine rotation is legitimate; unscheduled addition is the signal.",
455
+ "Confirm no concurrent unusual SAML-assertion volume from the affected federation domain. A real rotation produces a clean cutover; a malicious addition often coincides with parallel attacker-signed assertions."
456
+ ]
457
+ },
458
+ {
459
+ "id": "refresh-token-hoarding-by-sp",
460
+ "type": "log_pattern",
461
+ "value": "Service principal's 30-day refresh-token issuance volume exceeds baseline-mean + 4 * baseline-stddev OR exceeds 10x its 90-day median.",
462
+ "description": "OAuth-app refresh-token hoarding pattern — attacker accumulating long-lived access via repeated consent flows or sign-in induction.",
463
+ "confidence": "high",
464
+ "deterministic": false,
465
+ "attack_ref": "T1078.004",
466
+ "false_positive_checks_required": [
467
+ "Confirm the SP did not have a legitimate change in user-base scope (new rollout, new region launch). A growing user-base legitimately grows refresh-token volume; this is a step-change pattern not a slow growth.",
468
+ "Confirm the geographic distribution of refresh-token issuance matches the SP's expected user base. A surge of issuance from a single anomalous geography against a globally-distributed SP is higher-confidence than uniform growth."
469
+ ]
470
+ },
471
+ {
472
+ "id": "prt-claim-anomaly",
473
+ "type": "log_pattern",
474
+ "value": "Sign-in event with a Primary Refresh Token claim where the claim's device-id does not appear in the tenant's registered-devices inventory, OR the device-id was first-seen within the last 24h with no corresponding device-registration event.",
475
+ "description": "Primary Refresh Token theft signature — attacker presenting a PRT for a device the tenant never registered.",
476
+ "confidence": "deterministic",
477
+ "deterministic": true,
478
+ "attack_ref": "T1078.004",
479
+ "false_positive_checks_required": [
480
+ "Confirm the device-id is genuinely absent from the registered-devices inventory (Entra ID GET /devices?$filter=deviceId eq 'X'). API-pagination misses are a common false-negative on the registered-devices side; require a paginated full scan before classifying as hit.",
481
+ "Confirm the user's recent device-registration history. A user who legitimately re-registered a device within the 24h window can produce a transient indeterminate signal; require correlation with the registration audit event."
482
+ ]
483
+ },
484
+ {
485
+ "id": "okta-class-support-session",
486
+ "type": "log_pattern",
487
+ "value": "Tenant-admin action whose actor metadata indicates vendor-support session (Okta SuperAdmin via support impersonation, Microsoft FastTrack tenant access) OUTSIDE a documented support case.",
488
+ "description": "2023 Okta-class vendor-side compromise signature. Vendor-support session without a tracked support case is the canonical anomaly.",
489
+ "confidence": "deterministic",
490
+ "deterministic": true,
491
+ "attack_ref": "T1199",
492
+ "false_positive_checks_required": [
493
+ "Cross-check against the operator's vendor-support case tracker for a matching open case in the same time window. A matched case downgrades to medium (still review the case-vs-action scope match).",
494
+ "Confirm the vendor-support session's RBAC scope was the minimum required for the support case. Excess RBAC on a legitimate support case is itself a finding even when the case is real."
495
+ ]
496
+ }
497
+ ],
498
+ "false_positive_profile": [
499
+ {
500
+ "indicator_id": "out-of-window-global-admin-grant",
501
+ "benign_pattern": "Documented emergency-access activation by a break-glass account.",
502
+ "distinguishing_test": "Cross-reference the actor against the inventoried break-glass accounts (look.artifacts.break-glass-and-sync-accounts). If matched AND the activation has a post-hoc incident review record, downgrade to medium. Still require human review."
503
+ },
504
+ {
505
+ "indicator_id": "high-impact-oauth-consent-grant",
506
+ "benign_pattern": "First-party Microsoft / Google / Okta integration consented with documented business need.",
507
+ "distinguishing_test": "Compare the publisher domain + AppId against the published Microsoft/Google/Okta first-party publisher list. Spoofed publishers with similar-looking domains are not first-party; require canonical-publisher-ID match."
508
+ }
509
+ ],
510
+ "minimum_signal": {
511
+ "detected": "Any single deterministic indicator fires AND its false_positive_checks_required step does not produce an unambiguous benign explanation. For deterministic-true indicators (golden-SAML class, PRT-anomaly class), single-fire = detected. For high-confidence indicators (refresh-token-hoarding), require two corroborating indicators OR cross-correlation with the operator's IR team.",
512
+ "inconclusive": "Inventory complete but indicators fire on accounts / SPs whose status cannot be resolved without admin intervention (e.g. service-principal owner unreachable). Cannot deny without escalation.",
513
+ "not_detected": "All inventory complete, no indicator fires, all admin grants traceable to change-management tickets, all OAuth high-impact scopes on allowlisted first-party SPs, no exclusion-group membership changes outside change windows, refresh-token issuance within baseline."
514
+ }
515
+ },
516
+ "analyze": {
517
+ "rwep_inputs": [
518
+ {
519
+ "signal_id": "out-of-window-global-admin-grant",
520
+ "rwep_factor": "active_exploitation",
521
+ "weight": 25,
522
+ "notes": "Salt Typhoon-class persistence pattern — confirmed active exploitation against critical-infrastructure tenants."
523
+ },
524
+ {
525
+ "signal_id": "high-impact-oauth-consent-grant",
526
+ "rwep_factor": "active_exploitation",
527
+ "weight": 25,
528
+ "notes": "Scattered Spider-class OAuth-app abuse — confirmed active exploitation against SaaS-dependent enterprises."
529
+ },
530
+ {
531
+ "signal_id": "federation-signing-cert-added",
532
+ "rwep_factor": "active_exploitation",
533
+ "weight": 25,
534
+ "notes": "Golden-SAML technique in active use since 2020; routinely confirmed in nation-state intrusions."
535
+ },
536
+ {
537
+ "signal_id": "okta-class-support-session",
538
+ "rwep_factor": "cisa_kev",
539
+ "weight": 20,
540
+ "notes": "Vendor-tier compromise has CISA-published advisories tying to the 2023 Okta incident class."
541
+ },
542
+ {
543
+ "signal_id": "conditional-access-exclusion-membership-change",
544
+ "rwep_factor": "public_poc",
545
+ "weight": 15,
546
+ "notes": "Exclusion-group abuse is well-documented in researcher write-ups and red-team playbooks."
547
+ },
548
+ {
549
+ "signal_id": "refresh-token-hoarding-by-sp",
550
+ "rwep_factor": "ai_weaponization",
551
+ "weight": 10,
552
+ "notes": "AI-tool OAuth-grant abuse is operational; refresh-token hoarding is the credible AI-C2 fingerprint."
553
+ },
554
+ {
555
+ "signal_id": "prt-claim-anomaly",
556
+ "rwep_factor": "public_poc",
557
+ "weight": 15,
558
+ "notes": "PRT-theft tooling (TokenBroker abuse, ROADtools) is publicly documented."
559
+ },
560
+ {
561
+ "signal_id": "out-of-window-global-admin-grant",
562
+ "rwep_factor": "blast_radius",
563
+ "weight": 5,
564
+ "notes": "Tier-0 grant = tenant-wide blast radius."
565
+ }
566
+ ],
567
+ "blast_radius_model": {
568
+ "scope_question": "If the in-progress IdP-plane compromise is confirmed, what scope of downstream compromise does the IdP control plane deliver?",
569
+ "scoring_rubric": [
570
+ {
571
+ "condition": "Indicator scoped to a single non-admin user with only personal-data scope.",
572
+ "blast_radius_score": 1,
573
+ "description": "Single user-scope compromise; revoke session + reset credentials."
574
+ },
575
+ {
576
+ "condition": "Indicator scoped to an OAuth app with read-only data access.",
577
+ "blast_radius_score": 2,
578
+ "description": "Data-exfiltration scope; revoke consent + audit data accessed."
579
+ },
580
+ {
581
+ "condition": "Indicator scoped to an OAuth app with high-impact data scope (Mail.ReadWrite, Files.ReadWrite.All) or a non-Tier-0 admin role.",
582
+ "blast_radius_score": 3,
583
+ "description": "Multi-user mailbox / file / app-scope compromise; revoke + full data-access audit."
584
+ },
585
+ {
586
+ "condition": "Indicator scoped to a Tier-0 admin role grant OR conditional-access exclusion-group membership change OR PRT-claim-anomaly on an admin account.",
587
+ "blast_radius_score": 4,
588
+ "description": "Tenant-admin scope compromise; full tenant-wide reset + downstream cloud-IAM rotation."
589
+ },
590
+ {
591
+ "condition": "Indicator scoped to federation-signing-cert-added OR golden-SAML signature OR vendor-support-session abuse.",
592
+ "blast_radius_score": 5,
593
+ "description": "Federation-trust-root compromise OR vendor-tier compromise; full federation rotation + cross-tenant audit."
594
+ }
595
+ ]
596
+ },
597
+ "compliance_theater_check": {
598
+ "claim": "IdP audit logs are streamed to the SIEM and reviewed continuously, therefore IdP-plane compromise is detected.",
599
+ "audit_evidence": "SIEM data-ingest configuration showing IdP audit logs forwarded; on-call rotation reviewing alerts.",
600
+ "reality_test": "For a sample audit period (last 90 days), enumerate the SIEM rules active against the IdP audit data. Confirm rules exist for: (a) Tier-0 role grant outside change window, (b) high-impact OAuth consent grant to non-allowlisted SP, (c) conditional-access exclusion-group membership change, (d) federation signing-cert addition, (e) refresh-token issuance anomaly per SP. Theater verdict if any of (a)-(e) lacks an active rule: paper compliance (logs collected, on-call rotation) coexists with no actual detection for the IdP-plane signals.",
601
+ "theater_verdict_if_gap": "Org demonstrates SIEM ingestion + on-call review, but no active rules cover the IdP-control-plane signals. Either (a) deploy the missing IdP-plane SIEM rules with documented response runbooks, (b) move the IdP audit log to a dedicated detection platform with IdP-aware rule packs, OR (c) generate a defensible exception via policy-exception-gen with enhanced manual review cadence as the compensating control."
602
+ },
603
+ "framework_gap_mapping": [
604
+ {
605
+ "finding_id": "idp-control-plane-detection-gap",
606
+ "framework": "nist-800-53",
607
+ "claimed_control": "AC-2(11) — Account Management — Usage Conditions",
608
+ "actual_gap": "Generic anomaly-detection without IdP-control-plane-specific signals. Tier-0 grants outside change window, refresh-token hoarding by SP, federation-signing-cert addition are not in scope.",
609
+ "required_control": "Add IdP-control-plane-specific signal enumeration to AC-2(11): documented rules for each of the seven indicator classes in this playbook, with per-rule response runbooks."
610
+ },
611
+ {
612
+ "finding_id": "idp-control-plane-detection-gap",
613
+ "framework": "iso-27001-2022",
614
+ "claimed_control": "A.8.16 — Monitoring activities",
615
+ "actual_gap": "Generic SIEM collection satisfies the control without IdP-plane-specific detection rules.",
616
+ "required_control": "Bind A.8.16 to IdP-tenant-admin event semantics: require documented IdP-plane detection rules with quarterly conformance testing."
617
+ },
618
+ {
619
+ "finding_id": "idp-control-plane-detection-gap",
620
+ "framework": "soc2",
621
+ "claimed_control": "CC7.2 — System monitoring",
622
+ "actual_gap": "Treats IdP as vendor-managed and out of scope; in-progress IdP-plane detection not assessed.",
623
+ "required_control": "Bring IdP-control-plane into CC7.2 scope. Require evidence of IdP-plane detection rules + tested response procedures."
624
+ },
625
+ {
626
+ "finding_id": "idp-control-plane-detection-gap",
627
+ "framework": "nis2",
628
+ "claimed_control": "Art.21(2)(f) — Multi-factor authentication",
629
+ "actual_gap": "Specifies enforcement; silent on detection of MFA-bypass patterns (conditional-access exclusion group changes, app-passwords issuance, legacy-auth re-enablement).",
630
+ "required_control": "Pair MFA-enforcement requirement with MFA-bypass-detection requirement covering exclusion-group changes, legacy-auth re-enablement, federation-bypass."
631
+ },
632
+ {
633
+ "finding_id": "idp-control-plane-detection-gap",
634
+ "framework": "uk-caf",
635
+ "claimed_control": "C1 — Security monitoring",
636
+ "actual_gap": "Outcome-based; regulator interpretation varies. SIEM with generic anomaly rules can defensibly satisfy C1.",
637
+ "required_control": "CAF C1 guidance should enumerate IdP-control-plane signals as required for any operator with a federated identity dependency."
638
+ }
639
+ ],
640
+ "escalation_criteria": [
641
+ {
642
+ "condition": "phases.detect.classification == 'detected'",
643
+ "action": "trigger_playbook",
644
+ "target_playbook": "idp-incident"
645
+ },
646
+ {
647
+ "condition": "rwep >= 85 AND blast_radius_score >= 4",
648
+ "action": "page_on_call"
649
+ },
650
+ {
651
+ "condition": "federation-signing-cert-added == fired",
652
+ "action": "page_on_call"
653
+ },
654
+ {
655
+ "condition": "blast_radius_score >= 3 AND finding.includes_cloud_role_assumption == true",
656
+ "action": "trigger_playbook",
657
+ "target_playbook": "cloud-iam-incident"
658
+ },
659
+ {
660
+ "condition": "compliance_theater_check.verdict == 'theater' AND jurisdiction_obligations contains 'EU'",
661
+ "action": "notify_legal"
662
+ }
663
+ ]
664
+ },
665
+ "validate": {
666
+ "remediation_paths": [
667
+ {
668
+ "id": "deploy-missing-detection-rules",
669
+ "description": "Author the missing SIEM detection rules for each of the seven indicator classes. Document per-rule response runbooks and on-call escalation paths.",
670
+ "preconditions": [
671
+ "siem_admin_authority == true",
672
+ "rule_authoring_capacity_within_72h == true"
673
+ ],
674
+ "priority": 1,
675
+ "compensating_controls": [
676
+ "rule_set_recorded_in_iac",
677
+ "rule_test_suite_in_ci"
678
+ ],
679
+ "estimated_time_hours": 16
680
+ },
681
+ {
682
+ "id": "tighten-conditional-access-exclusions",
683
+ "description": "Audit every conditional-access exclusion group. Remove any account that does not have a documented break-glass / sync-account / vendor-integration justification. For remaining exclusions, require quarterly attestation by the role-owner.",
684
+ "preconditions": [
685
+ "ca_policy_admin_authority == true",
686
+ "break_glass_inventory_complete == true"
687
+ ],
688
+ "priority": 2,
689
+ "compensating_controls": [
690
+ "exclusion_group_membership_alert_active",
691
+ "quarterly_attestation_recorded"
692
+ ],
693
+ "estimated_time_hours": 8
694
+ },
695
+ {
696
+ "id": "revoke-stale-high-impact-oauth-consents",
697
+ "description": "Revoke OAuth consents for service principals on the high-impact-scope list that no longer have documented business justification. Require admin-consent re-approval with named scope justification for any re-grant.",
698
+ "preconditions": [
699
+ "oauth_admin_authority == true",
700
+ "business_owner_engagement_secured == true"
701
+ ],
702
+ "priority": 2,
703
+ "compensating_controls": [
704
+ "consent_revocation_recorded",
705
+ "re_grant_requires_documented_justification"
706
+ ],
707
+ "estimated_time_hours": 6
708
+ },
709
+ {
710
+ "id": "rotate-federation-signing-certs",
711
+ "description": "If federation-signing-cert-added fired or any signing-cert is older than the rotation window, rotate. Confirm rotation by verifying only the new cert produces valid SAML assertions.",
712
+ "preconditions": [
713
+ "federation_admin_authority == true",
714
+ "downstream_dependent_apps_can_tolerate_rotation_window == true"
715
+ ],
716
+ "priority": 1,
717
+ "compensating_controls": [
718
+ "rotation_recorded_in_change_management",
719
+ "old_cert_signed_assertions_quarantined_for_review"
720
+ ],
721
+ "estimated_time_hours": 12
722
+ },
723
+ {
724
+ "id": "policy-exception",
725
+ "description": "Generate auditor-ready policy exception when faster paths are blocked.",
726
+ "preconditions": [
727
+ "remediation_paths[1..4] partially blocked",
728
+ "ciso_acceptance_obtainable == true"
729
+ ],
730
+ "priority": 5,
731
+ "compensating_controls": [
732
+ "enhanced_manual_audit_log_review_daily",
733
+ "weekly_oauth_app_inventory_review"
734
+ ],
735
+ "estimated_time_hours": 6
736
+ }
737
+ ],
738
+ "validation_tests": [
739
+ {
740
+ "id": "detection-rule-fires-on-synthetic-event",
741
+ "test": "For each deployed rule, generate a synthetic event in the test tenant matching the indicator pattern. Confirm the rule fires + escalates per runbook.",
742
+ "expected_result": "Each rule fires on the synthetic event with the expected severity + on-call paged.",
743
+ "test_type": "functional"
744
+ },
745
+ {
746
+ "id": "conditional-access-exclusion-attestation",
747
+ "test": "Enumerate every CA exclusion group post-remediation. Cross-check membership against the attestation record.",
748
+ "expected_result": "Every excluded member has a current attestation record naming the role-owner.",
749
+ "test_type": "functional"
750
+ },
751
+ {
752
+ "id": "high-impact-oauth-allowlist-conformance",
753
+ "test": "For every SP with a high-impact scope, confirm it appears on the documented allowlist with named business owner.",
754
+ "expected_result": "100% of high-impact SPs on the allowlist; no orphan SPs.",
755
+ "test_type": "functional"
756
+ },
757
+ {
758
+ "id": "federation-rotation-cutover",
759
+ "test": "After federation-signing-cert rotation, attempt a SAML assertion signed by the old cert. Confirm rejection.",
760
+ "expected_result": "Old-cert SAML rejected; only new-cert SAML accepted.",
761
+ "test_type": "negative"
762
+ },
763
+ {
764
+ "id": "no-regression-on-legitimate-admin-workflows",
765
+ "test": "Run the operator's standard admin workflow suite (legitimate role grant via PIM, legitimate OAuth consent for a new first-party integration) and confirm rules do not fire (rules treat these as benign).",
766
+ "expected_result": "Legitimate admin workflows complete without rule fires.",
767
+ "test_type": "regression"
768
+ }
769
+ ],
770
+ "residual_risk_statement": {
771
+ "risk": "IdP-control-plane detection coverage has gaps that cannot be closed within the jurisdiction's notification window.",
772
+ "why_remains": "Either (a) SIEM rule-authoring capacity is constrained, (b) a vendor-support session pattern lacks a programmatic API to query case status, OR (c) baseline-data history is too short to set a refresh-token-issuance baseline with required confidence.",
773
+ "acceptance_level": "ciso",
774
+ "compensating_controls_in_place": [
775
+ "enhanced_manual_audit_log_review_daily",
776
+ "weekly_oauth_app_inventory_review",
777
+ "vendor_support_case_cross_check_runbook"
778
+ ]
779
+ },
780
+ "evidence_requirements": [
781
+ {
782
+ "evidence_type": "config_diff",
783
+ "description": "Diff of SIEM rule set pre / post remediation, plus per-rule runbook documents.",
784
+ "retention_period": "audit_cycle",
785
+ "framework_satisfied": [
786
+ "nist-800-53-AC-2(11)",
787
+ "iso-27001-2022-A.8.16",
788
+ "soc2-cc7.2"
789
+ ]
790
+ },
791
+ {
792
+ "evidence_type": "log_excerpt",
793
+ "description": "Audit-log excerpts for each fired indicator, with the false_positive_checks_required resolution outcome documented per fire.",
794
+ "retention_period": "1_year",
795
+ "framework_satisfied": [
796
+ "soc2-cc7.2",
797
+ "iso-27001-2022-A.8.16"
798
+ ]
799
+ },
800
+ {
801
+ "evidence_type": "scan_report",
802
+ "description": "Snapshot of privileged-role assignments + OAuth-app consents + conditional-access policy state + federation-trust config pre + post remediation.",
803
+ "retention_period": "1_year",
804
+ "framework_satisfied": [
805
+ "nist-800-53-AC-2",
806
+ "iso-27001-2022-A.5.16"
807
+ ]
808
+ },
809
+ {
810
+ "evidence_type": "attestation",
811
+ "description": "Signed exceptd attestation file with evidence_hash, fired indicators, RWEP at detection, residual risk acceptance.",
812
+ "retention_period": "7_years",
813
+ "framework_satisfied": [
814
+ "nist-800-53-CA-7",
815
+ "iso-27001-2022-A.5.36",
816
+ "nis2-art21-2f"
817
+ ]
818
+ }
819
+ ],
820
+ "regression_trigger": [
821
+ {
822
+ "condition": "new_tenant_admin_grant == true",
823
+ "interval": "on_event"
824
+ },
825
+ {
826
+ "condition": "new_high_impact_oauth_consent == true",
827
+ "interval": "on_event"
828
+ },
829
+ {
830
+ "condition": "conditional_access_policy_modified == true",
831
+ "interval": "on_event"
832
+ },
833
+ {
834
+ "condition": "federation_config_modified == true",
835
+ "interval": "on_event"
836
+ },
837
+ {
838
+ "condition": "weekly",
839
+ "interval": "7d"
840
+ }
841
+ ]
842
+ },
843
+ "close": {
844
+ "evidence_package": {
845
+ "bundle_format": "csaf-2.0",
846
+ "contents": [
847
+ "all_validation_tests_passed",
848
+ "siem_rule_set_diff",
849
+ "fired_indicator_log_excerpts",
850
+ "idp_tenant_snapshot_pre_post",
851
+ "residual_risk_statement",
852
+ "framework_gap_mapping",
853
+ "compliance_theater_verdict",
854
+ "attestation"
855
+ ],
856
+ "destination": "local_only",
857
+ "signed": true
858
+ },
859
+ "learning_loop": {
860
+ "enabled": true,
861
+ "lesson_template": {
862
+ "attack_vector": "IdP-control-plane in-progress compromise — $finding_class (e.g. out-of-window-global-admin-grant, high-impact-oauth-consent-grant, federation-signing-cert-added, conditional-access-exclusion-membership-change).",
863
+ "control_gap": "SIEM ingestion of IdP audit logs satisfied the literal monitoring control but lacked IdP-plane-specific detection rules. MFA enforcement coexisted with active MFA-bypass.",
864
+ "framework_gap": "NIST AC-2(11), ISO A.8.16, SOC 2 CC7.2, NIS2 Art.21(2)(f), UK CAF C1, AU Essential 8 ML3 collectively underspecify IdP-control-plane detection. Generic anomaly rules pass without binding to IdP-tenant-admin event semantics.",
865
+ "new_control_requirement": "Each framework's relevant monitoring or MFA control must enumerate IdP-control-plane signals as in-scope: Tier-0 role grant outside change window, high-impact OAuth consent to non-allowlisted SP, conditional-access exclusion-group membership change, federation signing-cert addition, refresh-token hoarding per SP, PRT-claim anomaly, vendor-support session outside documented case."
866
+ },
867
+ "feeds_back_to_skills": [
868
+ "identity-assurance",
869
+ "idp-incident-response",
870
+ "framework-gap-analysis",
871
+ "zeroday-gap-learn"
872
+ ]
873
+ },
874
+ "notification_actions": [
875
+ {
876
+ "obligation_ref": "EU/NIS2 Art.23 24h",
877
+ "deadline": "computed_at_runtime",
878
+ "recipient": "internal_legal",
879
+ "evidence_attached": [
880
+ "idp_audit_log_excerpt",
881
+ "exposure_window_estimate",
882
+ "rotation_status"
883
+ ],
884
+ "draft_notification": "Initial NIS2 Art.23 24-hour early-warning notification: in-progress IdP-control-plane compromise detection. Indicators fired: ${fired_indicator_ids}. Affected scope: ${affected_scope}. Containment in place: ${containment_record}. Detection-side investigation now escalating to IR via idp-incident. Full incident assessment to follow within 72 hours per Art.23(4)."
885
+ },
886
+ {
887
+ "obligation_ref": "EU/DORA Art.19 4h",
888
+ "deadline": "computed_at_runtime",
889
+ "recipient": "internal_legal",
890
+ "evidence_attached": [
891
+ "idp_audit_log_excerpt",
892
+ "affected_critical_or_important_functions",
893
+ "containment_record"
894
+ ],
895
+ "draft_notification": "DORA Art.19 initial notification: Major ICT-related incident — IdP-tenant compromise indicators active. Critical or important functions reliant on this IdP: ${affected_critical_or_important_functions}. Containment in progress; full classification + impact assessment to follow within statutory windows."
896
+ }
897
+ ],
898
+ "exception_generation": {
899
+ "trigger_condition": "siem_rule_authoring_capacity_blocked == true OR (federation_admin_authority_unavailable == true AND signing_cert_rotation_blocked_until_next_change_window == true)",
900
+ "exception_template": {
901
+ "scope": "IdP-control-plane detection-coverage residual risk for tenant ${tenant_id}; remediation paths 1-4 partially blocked.",
902
+ "duration": "until_capacity_available_or_30d",
903
+ "compensating_controls": [
904
+ "enhanced_manual_audit_log_review_daily",
905
+ "weekly_oauth_app_inventory_review",
906
+ "vendor_support_case_cross_check_runbook"
907
+ ],
908
+ "risk_acceptance_owner": "ciso",
909
+ "auditor_ready_language": "Pursuant to ${framework_id} ${control_id}, the organisation documents a time-bound risk acceptance for IdP-control-plane detection-coverage gaps in tenant ${tenant_id}. Missing rule classes: ${missing_rule_classes}. Compensating controls in place: ${compensating_controls}. Residual RWEP post-compensation: ${rwep_post_compensation}. Risk accepted by ${ciso_name} on ${acceptance_date}. Time-bound until ${duration_expiry}. The exception will be re-evaluated on (a) rule-authoring capacity availability, (b) the listed expiry date, OR (c) a new indicator firing under the manual-review compensating control — whichever is first."
910
+ }
911
+ },
912
+ "regression_schedule": {
913
+ "next_run": "computed_at_runtime",
914
+ "trigger": "both",
915
+ "notify_on_skip": true
916
+ }
917
+ }
918
+ },
919
+ "directives": [
920
+ {
921
+ "id": "all-idp-control-plane-signals",
922
+ "title": "Run the full IdP-control-plane in-progress detection sweep",
923
+ "applies_to": {
924
+ "always": true
925
+ }
926
+ },
927
+ {
928
+ "id": "golden-saml-targeted",
929
+ "title": "Targeted golden-SAML / federation-signing-cert sweep",
930
+ "applies_to": {
931
+ "attack_technique": "T1606.002"
932
+ },
933
+ "phase_overrides": {
934
+ "direct": {
935
+ "rwep_threshold": {
936
+ "escalate": 75,
937
+ "monitor": 50,
938
+ "close": 25
939
+ }
940
+ }
941
+ }
942
+ },
943
+ {
944
+ "id": "scattered-spider-class-oauth-consent",
945
+ "title": "Targeted high-impact OAuth-consent abuse sweep (Scattered Spider class)",
946
+ "applies_to": {
947
+ "attack_technique": "T1528"
948
+ }
949
+ }
950
+ ]
951
+ }