@blamejs/exceptd-skills 0.16.17 → 0.16.19
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.
- package/AGENTS.md +3 -1
- package/CHANGELOG.md +8 -0
- package/README.md +5 -5
- package/bin/exceptd.js +3 -1
- package/data/_indexes/_meta.json +17 -15
- package/data/_indexes/activity-feed.json +17 -3
- package/data/_indexes/catalog-summaries.json +1 -1
- package/data/_indexes/chains.json +14784 -1833
- package/data/_indexes/currency.json +19 -1
- package/data/_indexes/frequency.json +138 -86
- package/data/_indexes/handoff-dag.json +9 -1
- package/data/_indexes/jurisdiction-map.json +9 -3
- package/data/_indexes/section-offsets.json +170 -0
- package/data/_indexes/stale-content.json +1 -1
- package/data/_indexes/summary-cards.json +77 -0
- package/data/_indexes/token-budget.json +103 -3
- package/data/_indexes/trigger-table.json +93 -0
- package/data/_indexes/xref.json +38 -7
- package/data/cwe-catalog.json +35 -4
- package/data/playbooks/audit-log-integrity.json +3 -0
- package/data/playbooks/framework.json +2 -0
- package/data/playbooks/log-injection-telemetry.json +619 -0
- package/data/playbooks/privacy-consent-ops.json +605 -0
- package/data/playbooks/secrets.json +1 -0
- package/manifest-snapshot.json +104 -2
- package/manifest-snapshot.sha256 +1 -1
- package/manifest.json +161 -51
- package/package.json +2 -2
- package/sbom.cdx.json +92 -32
- package/skills/log-injection-telemetry/skill.md +80 -0
- package/skills/privacy-consent-ops/skill.md +80 -0
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta": {
|
|
3
|
+
"id": "privacy-consent-ops",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"last_threat_review": "2026-06-02",
|
|
6
|
+
"threat_currency_score": 92,
|
|
7
|
+
"changelog": [
|
|
8
|
+
{
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"date": "2026-06-02",
|
|
11
|
+
"summary": "Initial seven-phase privacy / consent / sanctions operational-integrity playbook. Covers where these controls become paper despite existing: sanctions screening that does not normalize confusable / homoglyph Unicode (or lacks alias + transliteration + fuzzy matching) so a lookalike-spelled listed name evades it; IAB TCF / MSPA consent signals acted on without an integrity binding to the consent_log of record (forgeable/tamperable) and not re-validated against withdrawal/expiry at processing time; DSR / right-to-erasure requests marked complete without per-store proof and not propagated to downstream copies and processors; and a GDPR ROPA that drifts from actual processing. Distinct from global-grc (advisory mapping) and the framework correlation playbook. Maps to ATT&CK T1036 / T1565.001 / T1070 and CWE-807/345/778/672, and to NIST 800-53 SI-10, ISO 27001 A.5.34, NIS2 Art.21, UK CAF B4, and AU ISM. The sanctions-normalization check reuses the vendored Unicode confusable / codepoint-class tooling."
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"owner": "@blamejs/platform-security",
|
|
15
|
+
"air_gap_mode": false,
|
|
16
|
+
"scope": "service",
|
|
17
|
+
"preconditions": [
|
|
18
|
+
{
|
|
19
|
+
"id": "privacy-source-or-config-read",
|
|
20
|
+
"description": "Agent must read the operator's sanctions-screening, consent, and DSR/erasure source and/or configuration to inspect normalization, integrity binding, re-validation, erasure-completion evidence, and ROPA reconciliation. A host with neither marks the playbook visibility_gap=no_privacy_inventory.",
|
|
21
|
+
"check": "agent_has_filesystem_read == true OR agent_has_privacy_config == true",
|
|
22
|
+
"on_fail": "halt"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"mutex": [],
|
|
26
|
+
"feeds_into": [
|
|
27
|
+
{
|
|
28
|
+
"playbook_id": "framework",
|
|
29
|
+
"condition": "analyze.compliance_theater_check.verdict == 'theater'"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"domain": {
|
|
34
|
+
"name": "Privacy / consent / sanctions operational integrity",
|
|
35
|
+
"attack_class": "compliance-theater",
|
|
36
|
+
"atlas_refs": [],
|
|
37
|
+
"attack_refs": [
|
|
38
|
+
"T1036",
|
|
39
|
+
"T1565.001",
|
|
40
|
+
"T1070"
|
|
41
|
+
],
|
|
42
|
+
"cve_refs": [],
|
|
43
|
+
"cwe_refs": [
|
|
44
|
+
"CWE-807",
|
|
45
|
+
"CWE-345",
|
|
46
|
+
"CWE-778",
|
|
47
|
+
"CWE-672"
|
|
48
|
+
],
|
|
49
|
+
"frameworks_in_scope": [
|
|
50
|
+
"nist-800-53",
|
|
51
|
+
"iso-27001-2022",
|
|
52
|
+
"nis2",
|
|
53
|
+
"uk-caf",
|
|
54
|
+
"au-ism"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"phases": {
|
|
58
|
+
"govern": {
|
|
59
|
+
"jurisdiction_obligations": [
|
|
60
|
+
{
|
|
61
|
+
"jurisdiction": "EU",
|
|
62
|
+
"regulation": "GDPR Art.17 / Art.33",
|
|
63
|
+
"obligation": "notify_regulator",
|
|
64
|
+
"window_hours": 72,
|
|
65
|
+
"clock_starts": "detect_confirmed",
|
|
66
|
+
"evidence_required": [
|
|
67
|
+
"affected_data_subjects",
|
|
68
|
+
"incomplete_erasure_or_consent_scope"
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"jurisdiction": "US",
|
|
73
|
+
"regulation": "OFAC sanctions reporting",
|
|
74
|
+
"obligation": "notify_regulator",
|
|
75
|
+
"window_hours": 240,
|
|
76
|
+
"clock_starts": "detect_confirmed",
|
|
77
|
+
"evidence_required": [
|
|
78
|
+
"screening_bypass_evidence",
|
|
79
|
+
"prohibited_party_exposure"
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"theater_fingerprints": [
|
|
84
|
+
{
|
|
85
|
+
"pattern_id": "we-screen-against-ofac",
|
|
86
|
+
"claim": "We screen all parties against the OFAC list.",
|
|
87
|
+
"fast_detection_test": "Test it with a homoglyph (Cyrillic-lookalike) spelling of a listed name. If it passes, the screen compares raw strings without confusable normalization — the screening is bypassable."
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"pattern_id": "we-capture-consent",
|
|
91
|
+
"claim": "We capture user consent.",
|
|
92
|
+
"fast_detection_test": "Ask whether the consent signal is integrity-bound to a server-side consent_log and re-checked at processing time. A client-presented consent string with no server record is forgeable and stale-by-default."
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"pattern_id": "erasure-is-completed",
|
|
96
|
+
"claim": "Erasure requests are completed.",
|
|
97
|
+
"fast_detection_test": "Ask for the per-store completion evidence and the downstream-propagation map. A \"completed\" flag with no proof leaves records live in indexes, backups, and processors."
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"framework_context": {
|
|
101
|
+
"gap_summary": "Org privacy/sanctions controls are attested by having the process — a screen, a consent capture, a DSR workflow, a ROPA. None require the operational integrity that makes them real: confusable normalization before screening, an integrity-bound and re-validated consent record, evidence-backed and propagated erasure, and a ROPA reconciled against reality.",
|
|
102
|
+
"lag_score": 71,
|
|
103
|
+
"per_framework_gaps": [
|
|
104
|
+
{
|
|
105
|
+
"framework": "iso-27001-2022",
|
|
106
|
+
"control_id": "A.5.34",
|
|
107
|
+
"designed_for": "privacy and protection of PII",
|
|
108
|
+
"insufficient_because": "attested by having consent + DSR processes; does not require the consent signal be integrity-bound or the erasure be evidence-backed and propagated."
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"framework": "nist-800-53",
|
|
112
|
+
"control_id": "SI-10",
|
|
113
|
+
"designed_for": "input validation",
|
|
114
|
+
"insufficient_because": "does not require Unicode confusable normalization before a sanctions-screening decision, so a homoglyph-spelled name evades it."
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
"skill_preload": [
|
|
119
|
+
"privacy-consent-ops",
|
|
120
|
+
"global-grc",
|
|
121
|
+
"sector-financial",
|
|
122
|
+
"framework-gap-analysis",
|
|
123
|
+
"compliance-theater",
|
|
124
|
+
"policy-exception-gen"
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
"direct": {
|
|
128
|
+
"threat_context": "Privacy and sanctions controls fail operationally even when they exist on paper. A sanctions screen that compares raw strings is evaded by a homoglyph-spelled listed name; a consent signal trusted from the client with no server-bound record is forgeable and stale; an erasure marked \"completed\" without per-store evidence and downstream propagation leaves live personal data behind; a ROPA that drifts hides undocumented processing. The adversary masquerades (T1036) or manipulates the stored compliance record (T1565.001) — the control reports success while the obligation is unmet.",
|
|
129
|
+
"rwep_threshold": {
|
|
130
|
+
"escalate": 50,
|
|
131
|
+
"monitor": 30,
|
|
132
|
+
"close": 15
|
|
133
|
+
},
|
|
134
|
+
"framework_lag_declaration": "A clean \"we screen against OFAC / capture consent / complete DSRs / maintain a ROPA\" audit is NON-EVIDENCE for operational integrity; it confirms the processes exist, not that screening normalizes confusables, consent is integrity-bound and re-validated, erasure is evidence-backed and propagated, and the ROPA matches reality.",
|
|
135
|
+
"skill_chain": [
|
|
136
|
+
{
|
|
137
|
+
"skill": "privacy-consent-ops",
|
|
138
|
+
"purpose": "enumerate the sanctions-normalization / consent-binding / erasure-evidence / ROPA-reconciliation checks"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"skill": "global-grc",
|
|
142
|
+
"purpose": "frame the multi-jurisdiction privacy + sanctions obligations the controls must meet"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"skill": "sector-financial",
|
|
146
|
+
"purpose": "cross-reference the sanctions-screening obligation for financial entities"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"skill": "framework-gap-analysis",
|
|
150
|
+
"purpose": "map findings to the SI-10 / A.5.34 gaps the controls do not cover"
|
|
151
|
+
}
|
|
152
|
+
],
|
|
153
|
+
"token_budget": {
|
|
154
|
+
"estimated_total": 12000,
|
|
155
|
+
"breakdown": {
|
|
156
|
+
"govern": 1200,
|
|
157
|
+
"direct": 800,
|
|
158
|
+
"look": 4000,
|
|
159
|
+
"detect": 3800,
|
|
160
|
+
"analyze": 1500,
|
|
161
|
+
"validate": 500,
|
|
162
|
+
"close": 200
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
"look": {
|
|
167
|
+
"artifacts": [
|
|
168
|
+
{
|
|
169
|
+
"id": "sanctions-screening-config",
|
|
170
|
+
"type": "config_file",
|
|
171
|
+
"source": "grep for compliance-sanctions-fuzzy / compliance-sanctions-aliases / compliance-sanctions / normalize / confusable / NFKC / codepoint-class across the screening path.",
|
|
172
|
+
"description": "Whether sanctions screening normalizes confusables/homoglyphs and applies alias + transliteration + fuzzy matching before deciding.",
|
|
173
|
+
"required": true,
|
|
174
|
+
"air_gap_alternative": "Inspect the screening source for Unicode normalization + alias/fuzzy layers."
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"id": "consent-config",
|
|
178
|
+
"type": "config_file",
|
|
179
|
+
"source": "grep for consent.js / iab-tcf / iab-mspa / consent string / consent_log / signature / lawful basis across the consent path.",
|
|
180
|
+
"description": "Whether the consent signal is integrity-bound to a server-side consent_log and re-validated at processing time.",
|
|
181
|
+
"required": true,
|
|
182
|
+
"air_gap_alternative": "Inspect the consent source for the binding to the consent_log and the processing-time re-check."
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"id": "dsr-erasure-config",
|
|
186
|
+
"type": "config_file",
|
|
187
|
+
"source": "grep for dsr.js / erasure / right to be forgotten / completion / propagate / processor / backup across the DSR workflow.",
|
|
188
|
+
"description": "Whether erasure records per-store completion evidence and propagates to all downstream copies and processors.",
|
|
189
|
+
"required": true,
|
|
190
|
+
"air_gap_alternative": "Inspect the DSR workflow for completion-evidence gating and downstream propagation tracking."
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"id": "ropa-and-dark-patterns",
|
|
194
|
+
"type": "config_file",
|
|
195
|
+
"source": "grep for gdpr-ropa / data-act / record of processing / dark-patterns across the privacy-governance surface.",
|
|
196
|
+
"description": "Whether the ROPA is reconciled against actual processing (drift) and how the consent UI is constructed.",
|
|
197
|
+
"required": false,
|
|
198
|
+
"air_gap_alternative": "Inspect the ROPA source/reconciliation cadence and the consent-capture flow."
|
|
199
|
+
}
|
|
200
|
+
],
|
|
201
|
+
"collection_scope": {
|
|
202
|
+
"time_window": "current sanctions / consent / DSR / ROPA configuration + source state (point-in-time posture audit)",
|
|
203
|
+
"asset_scope": "the sanctions-screening path, the consent capture + enforcement path, the DSR/erasure workflow, and the ROPA"
|
|
204
|
+
},
|
|
205
|
+
"environment_assumptions": [
|
|
206
|
+
{
|
|
207
|
+
"assumption": "The operator performs sanctions screening and/or processes personal data under a consent / lawful-basis regime.",
|
|
208
|
+
"if_false": "If no sanctions screening applies, skip those indicators; if no personal data is processed, the consent/DSR/ROPA indicators are out of scope."
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"assumption": "Privacy/sanctions source or config is readable.",
|
|
212
|
+
"if_false": "Mark visibility_gap=no_privacy_inventory and report only what the screening/consent/DSR source reveals."
|
|
213
|
+
}
|
|
214
|
+
],
|
|
215
|
+
"fallback_if_unavailable": [
|
|
216
|
+
{
|
|
217
|
+
"artifact_id": "sanctions-screening-config",
|
|
218
|
+
"fallback_action": "If the operator does no sanctions screening, skip the homoglyph and alias indicators.",
|
|
219
|
+
"confidence_impact": "none"
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"artifact_id": "ropa-and-dark-patterns",
|
|
223
|
+
"fallback_action": "If no ROPA obligation applies, skip the ROPA-drift indicator.",
|
|
224
|
+
"confidence_impact": "low"
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
"detect": {
|
|
229
|
+
"indicators": [
|
|
230
|
+
{
|
|
231
|
+
"id": "sanctions-screening-homoglyph-evasion",
|
|
232
|
+
"type": "config_value",
|
|
233
|
+
"value": "Sanctions / watchlist screening matches names without first normalizing confusable / homoglyph Unicode (e.g. Cyrillic/Latin lookalikes, combining marks, zero-width characters), so a name spelled with lookalikes evades the match.",
|
|
234
|
+
"description": "An adversary spells a sanctioned (OFAC/EU/UN) name with visually identical but distinct code points; the screen returns no hit and the prohibited party is onboarded or paid — a sanctions-control bypass with severe legal exposure.",
|
|
235
|
+
"confidence": "high",
|
|
236
|
+
"deterministic": false,
|
|
237
|
+
"attack_ref": "T1036",
|
|
238
|
+
"false_positive_checks_required": [
|
|
239
|
+
"Confirm the screen normalizes to a canonical skeleton (NFKC + confusable folding, e.g. via the vendored codepoint-class) BEFORE matching — screening that compares raw bytes / unnormalized strings is the finding.",
|
|
240
|
+
"A screen that already runs Unicode confusable folding + transliteration before fuzzy match is safe; test it with a known homoglyph variant of a listed name."
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"id": "sanctions-screening-alias-transliteration-gap",
|
|
245
|
+
"type": "config_value",
|
|
246
|
+
"value": "Sanctions screening is exact-match (or narrow fuzzy) only, with no alias list, transliteration variants, or edit-distance tolerance for the listed name.",
|
|
247
|
+
"description": "Listed parties appear under aliases, transliterations (Arabic/Cyrillic→Latin), and minor spelling variants; an exact-match screen misses all of them, passing a sanctioned entity that any alias-aware screen would catch.",
|
|
248
|
+
"confidence": "medium",
|
|
249
|
+
"deterministic": false,
|
|
250
|
+
"attack_ref": "T1036",
|
|
251
|
+
"false_positive_checks_required": [
|
|
252
|
+
"Confirm screening applies the sanction list's alias entries + transliteration + bounded edit-distance fuzzy match — exact-string-only screening is the finding.",
|
|
253
|
+
"A screen tuned with documented alias/fuzzy coverage and a false-positive review process is safe; the finding is exact-match with no alias/fuzzy layer."
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"id": "consent-record-no-integrity-binding",
|
|
258
|
+
"type": "config_value",
|
|
259
|
+
"value": "An IAB TCF / MSPA (or first-party) consent string is accepted and acted on without an integrity binding to the consent_log of record (no signature/HMAC, no server-side log the signal is checked against).",
|
|
260
|
+
"description": "A consent signal with no integrity binding can be forged or tampered (a client asserts consent it never gave, or replays another user's), and there is no authoritative record to reconcile against — defeating the lawful-basis evidence.",
|
|
261
|
+
"confidence": "high",
|
|
262
|
+
"deterministic": false,
|
|
263
|
+
"attack_ref": "T1565.001",
|
|
264
|
+
"false_positive_checks_required": [
|
|
265
|
+
"Confirm the consent signal is bound to a server-side consent_log (signed/HMAC'd or reconciled against the authoritative record) before it authorizes processing — acting on a client-presented consent string with no server reconciliation is the finding.",
|
|
266
|
+
"A consent string cryptographically bound to a server-issued, logged token is safe; the finding is trusting a mutable client-presented signal."
|
|
267
|
+
]
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"id": "consent-not-revalidated-at-processing",
|
|
271
|
+
"type": "config_value",
|
|
272
|
+
"value": "Consent is captured once and cached, with no re-check at processing time, so a withdrawn or expired consent continues to authorize processing.",
|
|
273
|
+
"description": "Once consent is withdrawn (or its purpose/duration expires), continuing to process on the stale cached signal is unlawful processing — operating on a permission that no longer holds.",
|
|
274
|
+
"confidence": "medium",
|
|
275
|
+
"deterministic": false,
|
|
276
|
+
"attack_ref": "T1565.001",
|
|
277
|
+
"false_positive_checks_required": [
|
|
278
|
+
"Confirm processing re-checks the current consent state (and its purpose/expiry) at use time, not just at capture — processing on a cached consent with no withdrawal/expiry re-check is the finding.",
|
|
279
|
+
"A system that propagates withdrawal to all processing paths in real time (event-driven invalidation) is safe."
|
|
280
|
+
]
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"id": "dsr-erasure-no-completion-proof",
|
|
284
|
+
"type": "config_value",
|
|
285
|
+
"value": "A data-subject erasure / DSR request is marked \"completed\" without proof that every store actually erased the records (the status is a manual flag, not evidence-backed).",
|
|
286
|
+
"description": "A \"completed\" erasure that did not actually erase leaves the data subject's records live while the org asserts compliance — a false compliance claim and a GDPR Art.17 / CCPA violation that surfaces on audit or re-request.",
|
|
287
|
+
"confidence": "high",
|
|
288
|
+
"deterministic": false,
|
|
289
|
+
"attack_ref": "T1565.001",
|
|
290
|
+
"false_positive_checks_required": [
|
|
291
|
+
"Confirm the erasure workflow records per-store completion evidence (a verifiable deletion receipt / re-query returning empty) before marking the ticket complete — a manually-flagged \"completed\" with no per-store proof is the finding.",
|
|
292
|
+
"A workflow that gates \"completed\" on confirmed per-store erasure evidence is safe; the finding is an unverified status flag."
|
|
293
|
+
]
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"id": "dsr-erasure-not-propagated-downstream",
|
|
297
|
+
"type": "config_value",
|
|
298
|
+
"value": "Erasure is applied to the primary store but not propagated to all downstream copies — backups, replicas, search indexes, caches, data-warehouse exports, and third-party processors.",
|
|
299
|
+
"description": "Records erased from the primary but surviving in a search index, warehouse, or processor are still live personal data; the erasure is incomplete and the org's \"erased\" claim is false for every un-propagated copy.",
|
|
300
|
+
"confidence": "medium",
|
|
301
|
+
"deterministic": false,
|
|
302
|
+
"attack_ref": "T1070",
|
|
303
|
+
"false_positive_checks_required": [
|
|
304
|
+
"Confirm the erasure propagates to (or is tracked against) every downstream copy + processor on a maintained data-map — erasure of only the primary store with no downstream propagation/tracking is the finding.",
|
|
305
|
+
"A documented data-map with confirmed propagation (or a defensible backup-expiry exception) is safe; the finding is untracked downstream copies."
|
|
306
|
+
]
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"id": "ropa-drifts-from-actual-processing",
|
|
310
|
+
"type": "config_value",
|
|
311
|
+
"value": "The GDPR Record of Processing Activities (ROPA) / data-act inventory drifts from the actual processing — new data flows, purposes, or third-party processors are not reflected.",
|
|
312
|
+
"description": "Processing not in the ROPA is undocumented processing: it escapes the lawful-basis, retention, and DSR-scope analysis the ROPA drives, so consent/erasure controls silently fail to cover it.",
|
|
313
|
+
"confidence": "low",
|
|
314
|
+
"deterministic": false,
|
|
315
|
+
"attack_ref": "T1565.001",
|
|
316
|
+
"false_positive_checks_required": [
|
|
317
|
+
"Confirm the ROPA is reconciled against the actual data flows / processor list on a cadence (drift surfaces new processing) — a ROPA that has not been reconciled against the live system is the finding.",
|
|
318
|
+
"A ROPA generated from or reconciled against the live processing inventory is safe; the finding is a hand-maintained ROPA that drifted."
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
],
|
|
322
|
+
"false_positive_profile": [
|
|
323
|
+
{
|
|
324
|
+
"indicator_id": "sanctions-screening-homoglyph-evasion",
|
|
325
|
+
"benign_pattern": "A control enforced by a dedicated layer (a confusable-folding screen, a server-bound consent token, an evidence-gated erasure workflow, a generated ROPA) or a genuinely out-of-scope surface.",
|
|
326
|
+
"distinguishing_test": "Confirm the screen normalizes to a canonical skeleton (NFKC + confusable folding, e.g. via the vendored codepoint-class) BEFORE matching — screening that compares raw bytes / unnormalized strings is the finding."
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
"indicator_id": "sanctions-screening-alias-transliteration-gap",
|
|
330
|
+
"benign_pattern": "A control enforced by a dedicated layer (a confusable-folding screen, a server-bound consent token, an evidence-gated erasure workflow, a generated ROPA) or a genuinely out-of-scope surface.",
|
|
331
|
+
"distinguishing_test": "Confirm screening applies the sanction list's alias entries + transliteration + bounded edit-distance fuzzy match — exact-string-only screening is the finding."
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"indicator_id": "consent-record-no-integrity-binding",
|
|
335
|
+
"benign_pattern": "A control enforced by a dedicated layer (a confusable-folding screen, a server-bound consent token, an evidence-gated erasure workflow, a generated ROPA) or a genuinely out-of-scope surface.",
|
|
336
|
+
"distinguishing_test": "Confirm the consent signal is bound to a server-side consent_log (signed/HMAC'd or reconciled against the authoritative record) before it authorizes processing — acting on a client-presented consent string with no server reconciliation is the finding."
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"indicator_id": "consent-not-revalidated-at-processing",
|
|
340
|
+
"benign_pattern": "A control enforced by a dedicated layer (a confusable-folding screen, a server-bound consent token, an evidence-gated erasure workflow, a generated ROPA) or a genuinely out-of-scope surface.",
|
|
341
|
+
"distinguishing_test": "Confirm processing re-checks the current consent state (and its purpose/expiry) at use time, not just at capture — processing on a cached consent with no withdrawal/expiry re-check is the finding."
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"indicator_id": "dsr-erasure-no-completion-proof",
|
|
345
|
+
"benign_pattern": "A control enforced by a dedicated layer (a confusable-folding screen, a server-bound consent token, an evidence-gated erasure workflow, a generated ROPA) or a genuinely out-of-scope surface.",
|
|
346
|
+
"distinguishing_test": "Confirm the erasure workflow records per-store completion evidence (a verifiable deletion receipt / re-query returning empty) before marking the ticket complete — a manually-flagged \"completed\" with no per-store proof is the finding."
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"indicator_id": "dsr-erasure-not-propagated-downstream",
|
|
350
|
+
"benign_pattern": "A control enforced by a dedicated layer (a confusable-folding screen, a server-bound consent token, an evidence-gated erasure workflow, a generated ROPA) or a genuinely out-of-scope surface.",
|
|
351
|
+
"distinguishing_test": "Confirm the erasure propagates to (or is tracked against) every downstream copy + processor on a maintained data-map — erasure of only the primary store with no downstream propagation/tracking is the finding."
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
"indicator_id": "ropa-drifts-from-actual-processing",
|
|
355
|
+
"benign_pattern": "A control enforced by a dedicated layer (a confusable-folding screen, a server-bound consent token, an evidence-gated erasure workflow, a generated ROPA) or a genuinely out-of-scope surface.",
|
|
356
|
+
"distinguishing_test": "Confirm the ROPA is reconciled against the actual data flows / processor list on a cadence (drift surfaces new processing) — a ROPA that has not been reconciled against the live system is the finding."
|
|
357
|
+
}
|
|
358
|
+
],
|
|
359
|
+
"minimum_signal": {
|
|
360
|
+
"detected": "At least one control is operationally bypassable — sanctions screening without confusable normalization or alias/fuzzy matching, a consent signal not integrity-bound or not re-validated, an erasure marked complete without evidence or downstream propagation, or a drifted ROPA.",
|
|
361
|
+
"inconclusive": "A control is enforced by a layer the audit could not read (a dedicated screening service, a consent platform) — record as visibility_gap, not a clean result.",
|
|
362
|
+
"not_detected": "Sanctions screening normalizes confusables and applies alias/fuzzy matching, consent is integrity-bound + re-validated at processing, erasure is evidence-backed + propagated downstream, and the ROPA is reconciled against actual processing."
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
"analyze": {
|
|
366
|
+
"rwep_inputs": [
|
|
367
|
+
{
|
|
368
|
+
"signal_id": "sanctions-screening-homoglyph-evasion",
|
|
369
|
+
"rwep_factor": "public_poc",
|
|
370
|
+
"weight": 20
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"signal_id": "dsr-erasure-no-completion-proof",
|
|
374
|
+
"rwep_factor": "blast_radius",
|
|
375
|
+
"weight": 15
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"signal_id": "consent-record-no-integrity-binding",
|
|
379
|
+
"rwep_factor": "active_exploitation",
|
|
380
|
+
"weight": 10
|
|
381
|
+
}
|
|
382
|
+
],
|
|
383
|
+
"blast_radius_model": {
|
|
384
|
+
"scope_question": "Does the gap let a prohibited party through the sanctions screen, or leave personal data unlawfully processed / un-erased across the data estate?",
|
|
385
|
+
"scoring_rubric": [
|
|
386
|
+
{
|
|
387
|
+
"condition": "Sanctions screening evadable by a trivial homoglyph on a payment/onboarding path (prohibited-party admission with legal exposure)",
|
|
388
|
+
"blast_radius_score": 5,
|
|
389
|
+
"description": "Sanctions-control bypass with regulatory + legal consequence"
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"condition": "Erasure incomplete / consent forgeable across all data subjects",
|
|
393
|
+
"blast_radius_score": 4,
|
|
394
|
+
"description": "Systemic unlawful processing / false compliance across the data estate"
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"condition": "ROPA drift or single-purpose consent staleness",
|
|
398
|
+
"blast_radius_score": 2,
|
|
399
|
+
"description": "Localised compliance gap"
|
|
400
|
+
}
|
|
401
|
+
]
|
|
402
|
+
},
|
|
403
|
+
"compliance_theater_check": {
|
|
404
|
+
"claim": "We screen against OFAC, capture consent, complete DSRs, and maintain a ROPA — privacy and sanctions are handled.",
|
|
405
|
+
"audit_evidence": "A screening vendor, a consent banner, a DSR ticket queue, a ROPA document.",
|
|
406
|
+
"reality_test": "Test the screen with a homoglyph name; check whether consent is server-bound and re-validated; ask for per-store erasure evidence + the propagation map; reconcile the ROPA against live data flows. If any control reports success while the obligation is unmet, the processes are paper.",
|
|
407
|
+
"theater_verdict_if_gap": "theater"
|
|
408
|
+
},
|
|
409
|
+
"framework_gap_mapping": [
|
|
410
|
+
{
|
|
411
|
+
"finding_id": "sanctions-screening-homoglyph-evasion",
|
|
412
|
+
"framework": "nist-800-53",
|
|
413
|
+
"claimed_control": "SI-10 (input validation)",
|
|
414
|
+
"actual_gap": "SI-10 validates format; it does not require Unicode confusable normalization before the screening decision."
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
"finding_id": "dsr-erasure-no-completion-proof",
|
|
418
|
+
"framework": "iso-27001-2022",
|
|
419
|
+
"claimed_control": "A.5.34 (privacy / PII)",
|
|
420
|
+
"actual_gap": "A.5.34 is attested by having a DSR process; it does not require per-store erasure evidence before \"completed\"."
|
|
421
|
+
}
|
|
422
|
+
],
|
|
423
|
+
"escalation_criteria": [
|
|
424
|
+
{
|
|
425
|
+
"condition": "Sanctions screening is evadable by a homoglyph on a live onboarding/payment path",
|
|
426
|
+
"action": "raise_severity"
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
"condition": "Erasure is marked complete with no per-store evidence across the data subject base",
|
|
430
|
+
"action": "trigger_playbook"
|
|
431
|
+
}
|
|
432
|
+
]
|
|
433
|
+
},
|
|
434
|
+
"validate": {
|
|
435
|
+
"remediation_paths": [
|
|
436
|
+
{
|
|
437
|
+
"id": "normalize-and-fuzzy-screen",
|
|
438
|
+
"description": "Normalize names to a canonical confusable-folded skeleton (NFKC + Unicode confusable folding via the vendored codepoint-class) and apply the list's aliases + transliteration + bounded edit-distance fuzzy match before deciding.",
|
|
439
|
+
"preconditions": [
|
|
440
|
+
"operator performs sanctions screening"
|
|
441
|
+
],
|
|
442
|
+
"priority": 1,
|
|
443
|
+
"for_signals": [
|
|
444
|
+
"sanctions-screening-homoglyph-evasion",
|
|
445
|
+
"sanctions-screening-alias-transliteration-gap"
|
|
446
|
+
]
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
"id": "bind-and-revalidate-consent",
|
|
450
|
+
"description": "Bind the consent signal to a server-side consent_log (signed/HMAC or reconciled), and re-check current consent (purpose + expiry + withdrawal) at processing time, not just at capture.",
|
|
451
|
+
"preconditions": [],
|
|
452
|
+
"priority": 1,
|
|
453
|
+
"for_signals": [
|
|
454
|
+
"consent-record-no-integrity-binding",
|
|
455
|
+
"consent-not-revalidated-at-processing"
|
|
456
|
+
]
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"id": "evidence-gate-and-propagate-erasure",
|
|
460
|
+
"description": "Gate erasure \"completed\" on per-store deletion evidence (a re-query returning empty / a deletion receipt) and propagate erasure to every downstream copy + processor on a maintained data-map.",
|
|
461
|
+
"preconditions": [],
|
|
462
|
+
"priority": 1,
|
|
463
|
+
"for_signals": [
|
|
464
|
+
"dsr-erasure-no-completion-proof",
|
|
465
|
+
"dsr-erasure-not-propagated-downstream"
|
|
466
|
+
]
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
"id": "reconcile-ropa",
|
|
470
|
+
"description": "Reconcile the ROPA against the actual data flows / processor inventory on a cadence so new processing surfaces and is brought under the consent/retention/DSR analysis.",
|
|
471
|
+
"preconditions": [],
|
|
472
|
+
"priority": 2,
|
|
473
|
+
"for_signals": [
|
|
474
|
+
"ropa-drifts-from-actual-processing"
|
|
475
|
+
]
|
|
476
|
+
}
|
|
477
|
+
],
|
|
478
|
+
"validation_tests": [
|
|
479
|
+
{
|
|
480
|
+
"id": "homoglyph-name-screened",
|
|
481
|
+
"test": "Submit a sanctioned name spelled with confusable Unicode (e.g. Cyrillic lookalikes) to the screen.",
|
|
482
|
+
"expected_result": "The screen normalizes and flags it as a match — the homoglyph variant does not evade.",
|
|
483
|
+
"test_type": "negative"
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
"id": "forged-consent-rejected",
|
|
487
|
+
"test": "Present a consent string asserting consent with no matching server-side consent_log entry.",
|
|
488
|
+
"expected_result": "Processing is refused — the signal must reconcile to the authoritative record.",
|
|
489
|
+
"test_type": "negative"
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
"id": "erasure-completion-gated",
|
|
493
|
+
"test": "Mark a DSR erasure complete while a downstream store still holds the records.",
|
|
494
|
+
"expected_result": "The workflow refuses \"completed\" until per-store evidence (including downstream) confirms deletion.",
|
|
495
|
+
"test_type": "negative"
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
"id": "legitimate-flows-work",
|
|
499
|
+
"test": "Screen a clean party, capture + use a validly-bound consent, and complete an erasure with full evidence.",
|
|
500
|
+
"expected_result": "All proceed normally — no regression on the legitimate path.",
|
|
501
|
+
"test_type": "functional"
|
|
502
|
+
}
|
|
503
|
+
],
|
|
504
|
+
"residual_risk_statement": {
|
|
505
|
+
"risk": "A determined adversary using a novel transliteration the alias list does not cover can still evade screening; and a processor that silently retains data outside the data-map remains a blind spot.",
|
|
506
|
+
"why_remains": "Normalization + fuzzy matching raise the bar but cannot enumerate every name variant; downstream propagation depends on the completeness of the data-map.",
|
|
507
|
+
"acceptance_level": "ciso"
|
|
508
|
+
},
|
|
509
|
+
"evidence_requirements": [
|
|
510
|
+
{
|
|
511
|
+
"evidence_type": "config_diff",
|
|
512
|
+
"description": "The screening normalization/alias/fuzzy config, consent-binding + re-validation logic, erasure evidence-gating + propagation map, and ROPA reconciliation cadence as audited.",
|
|
513
|
+
"retention_period": "1 year"
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
"evidence_type": "exploit_replay_negative",
|
|
517
|
+
"description": "Outcomes of the homoglyph-screen / forged-consent / erasure-completion negative tests plus the legitimate-flow functional test.",
|
|
518
|
+
"retention_period": "1 year"
|
|
519
|
+
}
|
|
520
|
+
],
|
|
521
|
+
"regression_trigger": [
|
|
522
|
+
{
|
|
523
|
+
"condition": "A new data flow, processor, consent purpose, or sanctions-list update",
|
|
524
|
+
"interval": "on change"
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
"condition": "Periodic re-attestation of privacy/consent/sanctions operational integrity",
|
|
528
|
+
"interval": "quarterly"
|
|
529
|
+
}
|
|
530
|
+
]
|
|
531
|
+
},
|
|
532
|
+
"close": {
|
|
533
|
+
"evidence_package": {
|
|
534
|
+
"bundle_format": "csaf-2.0",
|
|
535
|
+
"contents": [
|
|
536
|
+
"privacy/sanctions config snapshot",
|
|
537
|
+
"per-indicator findings + false-positive disposition",
|
|
538
|
+
"negative + functional test results",
|
|
539
|
+
"framework gap mapping"
|
|
540
|
+
],
|
|
541
|
+
"destination": ".exceptd/attestations/<session_id>/attestation.json"
|
|
542
|
+
},
|
|
543
|
+
"learning_loop": {
|
|
544
|
+
"enabled": true,
|
|
545
|
+
"lesson_template": {
|
|
546
|
+
"attack_vector": "A prohibited party evading a sanctions screen via homoglyph spelling, a forged/stale consent authorizing unlawful processing, or a falsely \"completed\" erasure leaving live personal data — the control reported success while the obligation was unmet.",
|
|
547
|
+
"control_gap": "Sanctions screening lacks confusable normalization / alias-fuzzy matching; consent is not integrity-bound or re-validated; erasure is not evidence-gated or propagated; ROPA drifts.",
|
|
548
|
+
"framework_gap": "NIST SI-10 + ISO A.5.34 attest the process exists but not its operational integrity.",
|
|
549
|
+
"new_control_requirement": "Sanctions screening MUST normalize confusables before matching; consent MUST be server-bound + re-validated; erasure MUST be evidence-gated + propagated downstream."
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
"notification_actions": [
|
|
553
|
+
{
|
|
554
|
+
"obligation_ref": "EU/GDPR Art.17 / Art.33 72h",
|
|
555
|
+
"deadline": "72h from detect_confirmed",
|
|
556
|
+
"recipient": "data protection authority",
|
|
557
|
+
"evidence_attached": [
|
|
558
|
+
"attestation"
|
|
559
|
+
]
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
"obligation_ref": "US/OFAC sanctions reporting 240h",
|
|
563
|
+
"deadline": "per OFAC reporting timeline from detect_confirmed",
|
|
564
|
+
"recipient": "OFAC / compliance counsel",
|
|
565
|
+
"evidence_attached": [
|
|
566
|
+
"attestation"
|
|
567
|
+
]
|
|
568
|
+
}
|
|
569
|
+
],
|
|
570
|
+
"exception_generation": {
|
|
571
|
+
"trigger_condition": "A legacy screen or store cannot adopt normalization / evidence-gating immediately.",
|
|
572
|
+
"exception_template": {
|
|
573
|
+
"scope": "the specific screen / store",
|
|
574
|
+
"duration": "90 days",
|
|
575
|
+
"compensating_controls": [
|
|
576
|
+
"manual confusable review of near-miss screening results",
|
|
577
|
+
"reconcile consent against the server log out of band",
|
|
578
|
+
"manual downstream-erasure attestation"
|
|
579
|
+
],
|
|
580
|
+
"risk_acceptance_owner": "ciso"
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
"regression_schedule": {
|
|
584
|
+
"next_run": "quarterly or on any new data flow / processor / sanctions-list update",
|
|
585
|
+
"trigger": "change to the screening / consent / DSR / ROPA surfaces, or quarterly re-attestation"
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
"directives": [
|
|
590
|
+
{
|
|
591
|
+
"id": "all-privacy-sanctions-controls",
|
|
592
|
+
"title": "Inventory + integrity-test the sanctions-screening, consent, DSR, and ROPA controls",
|
|
593
|
+
"applies_to": {
|
|
594
|
+
"always": true
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
"id": "sanctions-homoglyph-sweep",
|
|
599
|
+
"title": "Targeted homoglyph / alias sanctions-screening-evasion sweep",
|
|
600
|
+
"applies_to": {
|
|
601
|
+
"attack_technique": "T1036"
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
]
|
|
605
|
+
}
|