kekkai-cli 1.0.5__py3-none-any.whl → 1.1.1__py3-none-any.whl
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.
- kekkai/cli.py +789 -19
- kekkai/compliance/__init__.py +68 -0
- kekkai/compliance/hipaa.py +235 -0
- kekkai/compliance/mappings.py +136 -0
- kekkai/compliance/owasp.py +517 -0
- kekkai/compliance/owasp_agentic.py +267 -0
- kekkai/compliance/pci_dss.py +205 -0
- kekkai/compliance/soc2.py +209 -0
- kekkai/dojo.py +91 -14
- kekkai/dojo_import.py +9 -1
- kekkai/fix/__init__.py +47 -0
- kekkai/fix/audit.py +278 -0
- kekkai/fix/differ.py +427 -0
- kekkai/fix/engine.py +500 -0
- kekkai/fix/prompts.py +251 -0
- kekkai/output.py +10 -12
- kekkai/report/__init__.py +41 -0
- kekkai/report/compliance_matrix.py +98 -0
- kekkai/report/generator.py +365 -0
- kekkai/report/html.py +69 -0
- kekkai/report/pdf.py +63 -0
- kekkai/report/unified.py +226 -0
- kekkai/scanners/container.py +33 -3
- kekkai/scanners/gitleaks.py +3 -1
- kekkai/scanners/semgrep.py +1 -1
- kekkai/scanners/trivy.py +1 -1
- kekkai/threatflow/model_adapter.py +143 -1
- kekkai/triage/__init__.py +54 -1
- kekkai/triage/loader.py +196 -0
- kekkai_cli-1.1.1.dist-info/METADATA +379 -0
- {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/RECORD +34 -33
- {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/entry_points.txt +0 -1
- {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/top_level.txt +0 -1
- kekkai_cli-1.0.5.dist-info/METADATA +0 -135
- portal/__init__.py +0 -19
- portal/api.py +0 -155
- portal/auth.py +0 -103
- portal/enterprise/__init__.py +0 -32
- portal/enterprise/audit.py +0 -435
- portal/enterprise/licensing.py +0 -342
- portal/enterprise/rbac.py +0 -276
- portal/enterprise/saml.py +0 -595
- portal/ops/__init__.py +0 -53
- portal/ops/backup.py +0 -553
- portal/ops/log_shipper.py +0 -469
- portal/ops/monitoring.py +0 -517
- portal/ops/restore.py +0 -469
- portal/ops/secrets.py +0 -408
- portal/ops/upgrade.py +0 -591
- portal/tenants.py +0 -340
- portal/uploads.py +0 -259
- portal/web.py +0 -384
- {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"""OWASP Top 10 for Agentic AI mapping for security findings.
|
|
2
|
+
|
|
3
|
+
Maps findings to OWASP Agentic AI Top 10 categories based on rule patterns.
|
|
4
|
+
Reference: https://genai.owasp.org/initiatives/agentic-security-initiative/
|
|
5
|
+
|
|
6
|
+
Released: December 2025 at Black Hat Europe
|
|
7
|
+
|
|
8
|
+
This framework addresses security risks specific to autonomous AI agents
|
|
9
|
+
that make decisions and take actions in real-world environments.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
from .mappings import FrameworkControl
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from kekkai.scanners.base import Finding
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True)
|
|
24
|
+
class OWASPAgenticCategory:
|
|
25
|
+
"""OWASP Agentic AI Top 10 category definition."""
|
|
26
|
+
|
|
27
|
+
id: str
|
|
28
|
+
name: str
|
|
29
|
+
description: str
|
|
30
|
+
rule_patterns: tuple[str, ...]
|
|
31
|
+
scanner_types: tuple[str, ...] # Only apply to these scanner types
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# OWASP Top 10 for Agentic AI (December 2025)
|
|
35
|
+
OWASP_AGENTIC_TOP_10: dict[str, OWASPAgenticCategory] = {
|
|
36
|
+
"AA01": OWASPAgenticCategory(
|
|
37
|
+
id="AA01:2025",
|
|
38
|
+
name="Agent Goal Hijack",
|
|
39
|
+
description=(
|
|
40
|
+
"Attackers alter an agent's objectives through malicious content, "
|
|
41
|
+
"prompt injection, or manipulated inputs causing the agent to "
|
|
42
|
+
"act against the user's intent."
|
|
43
|
+
),
|
|
44
|
+
rule_patterns=(
|
|
45
|
+
"goal-hijack",
|
|
46
|
+
"prompt-injection",
|
|
47
|
+
"jailbreak",
|
|
48
|
+
"objective-manipulation",
|
|
49
|
+
"instruction-override",
|
|
50
|
+
"system-prompt",
|
|
51
|
+
),
|
|
52
|
+
scanner_types=("llm", "ai", "genai", "agent", "semgrep"),
|
|
53
|
+
),
|
|
54
|
+
"AA02": OWASPAgenticCategory(
|
|
55
|
+
id="AA02:2025",
|
|
56
|
+
name="Tool Misuse and Exploitation",
|
|
57
|
+
description=(
|
|
58
|
+
"Agents use legitimate tools in unsafe or unintended ways, "
|
|
59
|
+
"potentially causing harmful actions through manipulation "
|
|
60
|
+
"of tool parameters or abuse of tool capabilities."
|
|
61
|
+
),
|
|
62
|
+
rule_patterns=(
|
|
63
|
+
"tool-misuse",
|
|
64
|
+
"tool-abuse",
|
|
65
|
+
"function-call",
|
|
66
|
+
"api-abuse",
|
|
67
|
+
"unsafe-tool",
|
|
68
|
+
"tool-injection",
|
|
69
|
+
),
|
|
70
|
+
scanner_types=("llm", "ai", "genai", "agent", "semgrep"),
|
|
71
|
+
),
|
|
72
|
+
"AA03": OWASPAgenticCategory(
|
|
73
|
+
id="AA03:2025",
|
|
74
|
+
name="Identity and Privilege Abuse",
|
|
75
|
+
description=(
|
|
76
|
+
"Agents inherit or escalate high-privilege credentials, "
|
|
77
|
+
"risking unauthorized access to sensitive systems, data, "
|
|
78
|
+
"or operations beyond their intended scope."
|
|
79
|
+
),
|
|
80
|
+
rule_patterns=(
|
|
81
|
+
"privilege-escalation",
|
|
82
|
+
"identity-abuse",
|
|
83
|
+
"credential-inheritance",
|
|
84
|
+
"over-privileged",
|
|
85
|
+
"least-privilege",
|
|
86
|
+
"agent-permission",
|
|
87
|
+
),
|
|
88
|
+
scanner_types=("llm", "ai", "genai", "agent", "semgrep"),
|
|
89
|
+
),
|
|
90
|
+
"AA04": OWASPAgenticCategory(
|
|
91
|
+
id="AA04:2025",
|
|
92
|
+
name="Agentic Supply Chain Vulnerabilities",
|
|
93
|
+
description=(
|
|
94
|
+
"Compromised external components, plugins, or third-party "
|
|
95
|
+
"agents can affect the security and behavior of the entire "
|
|
96
|
+
"agentic system."
|
|
97
|
+
),
|
|
98
|
+
rule_patterns=(
|
|
99
|
+
"agent-supply-chain",
|
|
100
|
+
"plugin-vulnerability",
|
|
101
|
+
"external-agent",
|
|
102
|
+
"third-party-agent",
|
|
103
|
+
"model-supply-chain",
|
|
104
|
+
"compromised-plugin",
|
|
105
|
+
),
|
|
106
|
+
scanner_types=("llm", "ai", "genai", "agent", "semgrep", "trivy"),
|
|
107
|
+
),
|
|
108
|
+
"AA05": OWASPAgenticCategory(
|
|
109
|
+
id="AA05:2025",
|
|
110
|
+
name="Unexpected Code Execution",
|
|
111
|
+
description=(
|
|
112
|
+
"Agents generate or execute code unsafely, potentially "
|
|
113
|
+
"running malicious code, accessing unauthorized resources, "
|
|
114
|
+
"or causing system compromise."
|
|
115
|
+
),
|
|
116
|
+
rule_patterns=(
|
|
117
|
+
"code-execution",
|
|
118
|
+
"code-generation",
|
|
119
|
+
"unsafe-eval",
|
|
120
|
+
"dynamic-execution",
|
|
121
|
+
"sandbox-escape",
|
|
122
|
+
"code-injection",
|
|
123
|
+
),
|
|
124
|
+
scanner_types=("llm", "ai", "genai", "agent", "semgrep"),
|
|
125
|
+
),
|
|
126
|
+
"AA06": OWASPAgenticCategory(
|
|
127
|
+
id="AA06:2025",
|
|
128
|
+
name="Memory and Context Poisoning",
|
|
129
|
+
description=(
|
|
130
|
+
"Attackers corrupt an agent's memory systems or context "
|
|
131
|
+
"window to influence future behavior, decisions, or outputs "
|
|
132
|
+
"across sessions."
|
|
133
|
+
),
|
|
134
|
+
rule_patterns=(
|
|
135
|
+
"memory-poisoning",
|
|
136
|
+
"context-poisoning",
|
|
137
|
+
"context-manipulation",
|
|
138
|
+
"memory-injection",
|
|
139
|
+
"persistent-attack",
|
|
140
|
+
"rag-poisoning",
|
|
141
|
+
),
|
|
142
|
+
scanner_types=("llm", "ai", "genai", "agent"),
|
|
143
|
+
),
|
|
144
|
+
"AA07": OWASPAgenticCategory(
|
|
145
|
+
id="AA07:2025",
|
|
146
|
+
name="Insecure Inter-Agent Communication",
|
|
147
|
+
description=(
|
|
148
|
+
"Risks of spoofing, tampering, and man-in-the-middle attacks "
|
|
149
|
+
"in multi-agent systems due to weak authentication or "
|
|
150
|
+
"encryption between agents."
|
|
151
|
+
),
|
|
152
|
+
rule_patterns=(
|
|
153
|
+
"inter-agent",
|
|
154
|
+
"multi-agent",
|
|
155
|
+
"agent-communication",
|
|
156
|
+
"agent-spoofing",
|
|
157
|
+
"agent-tampering",
|
|
158
|
+
"agent-auth",
|
|
159
|
+
),
|
|
160
|
+
scanner_types=("llm", "ai", "genai", "agent"),
|
|
161
|
+
),
|
|
162
|
+
"AA08": OWASPAgenticCategory(
|
|
163
|
+
id="AA08:2025",
|
|
164
|
+
name="Cascading Failures",
|
|
165
|
+
description=(
|
|
166
|
+
"Small errors or failures in one part of an agentic system "
|
|
167
|
+
"can propagate and cause larger, widespread failures across "
|
|
168
|
+
"the entire system."
|
|
169
|
+
),
|
|
170
|
+
rule_patterns=(
|
|
171
|
+
"cascading-failure",
|
|
172
|
+
"error-propagation",
|
|
173
|
+
"fault-tolerance",
|
|
174
|
+
"failure-isolation",
|
|
175
|
+
"circuit-breaker",
|
|
176
|
+
"retry-storm",
|
|
177
|
+
),
|
|
178
|
+
scanner_types=("llm", "ai", "genai", "agent", "semgrep"),
|
|
179
|
+
),
|
|
180
|
+
"AA09": OWASPAgenticCategory(
|
|
181
|
+
id="AA09:2025",
|
|
182
|
+
name="Human-Agent Trust Exploitation",
|
|
183
|
+
description=(
|
|
184
|
+
"Users place excessive trust in agent recommendations, "
|
|
185
|
+
"leading to social engineering attacks, manipulation, "
|
|
186
|
+
"or harmful decisions based on agent outputs."
|
|
187
|
+
),
|
|
188
|
+
rule_patterns=(
|
|
189
|
+
"trust-exploitation",
|
|
190
|
+
"over-trust",
|
|
191
|
+
"social-engineering",
|
|
192
|
+
"manipulation",
|
|
193
|
+
"deception",
|
|
194
|
+
"human-override",
|
|
195
|
+
),
|
|
196
|
+
scanner_types=("llm", "ai", "genai", "agent"),
|
|
197
|
+
),
|
|
198
|
+
"AA10": OWASPAgenticCategory(
|
|
199
|
+
id="AA10:2025",
|
|
200
|
+
name="Rogue Agents",
|
|
201
|
+
description=(
|
|
202
|
+
"Compromised agents act maliciously while appearing legitimate, "
|
|
203
|
+
"potentially exfiltrating data, causing damage, or subverting "
|
|
204
|
+
"system controls."
|
|
205
|
+
),
|
|
206
|
+
rule_patterns=(
|
|
207
|
+
"rogue-agent",
|
|
208
|
+
"compromised-agent",
|
|
209
|
+
"malicious-agent",
|
|
210
|
+
"agent-takeover",
|
|
211
|
+
"agent-backdoor",
|
|
212
|
+
"agent-exfiltration",
|
|
213
|
+
),
|
|
214
|
+
scanner_types=("llm", "ai", "genai", "agent"),
|
|
215
|
+
),
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def map_to_owasp_agentic(finding: Finding) -> list[FrameworkControl]:
|
|
220
|
+
"""Map a finding to OWASP Agentic AI Top 10 categories.
|
|
221
|
+
|
|
222
|
+
Agentic AI mappings are primarily pattern-based since there are
|
|
223
|
+
few established CWEs for these emerging risks. Mappings are also
|
|
224
|
+
filtered by scanner type to avoid false positives.
|
|
225
|
+
"""
|
|
226
|
+
controls: list[FrameworkControl] = []
|
|
227
|
+
|
|
228
|
+
# Check rule_id patterns
|
|
229
|
+
rule_id_lower = (finding.rule_id or "").lower()
|
|
230
|
+
title_lower = finding.title.lower()
|
|
231
|
+
description_lower = finding.description.lower()
|
|
232
|
+
scanner_lower = finding.scanner.lower()
|
|
233
|
+
|
|
234
|
+
for category in OWASP_AGENTIC_TOP_10.values():
|
|
235
|
+
matched = False
|
|
236
|
+
|
|
237
|
+
# Check if scanner type is relevant for this category
|
|
238
|
+
scanner_relevant = any(st in scanner_lower for st in category.scanner_types)
|
|
239
|
+
|
|
240
|
+
# For generic scanners like semgrep, also check if the finding
|
|
241
|
+
# is related to AI/LLM based on content
|
|
242
|
+
if not scanner_relevant:
|
|
243
|
+
ai_keywords = ("llm", "agent", "ai", "model", "prompt", "genai")
|
|
244
|
+
if any(kw in title_lower or kw in description_lower for kw in ai_keywords):
|
|
245
|
+
scanner_relevant = True
|
|
246
|
+
|
|
247
|
+
if not scanner_relevant:
|
|
248
|
+
continue
|
|
249
|
+
|
|
250
|
+
# Match by rule pattern
|
|
251
|
+
for pattern in category.rule_patterns:
|
|
252
|
+
if pattern in rule_id_lower or pattern in title_lower or pattern in description_lower:
|
|
253
|
+
matched = True
|
|
254
|
+
break
|
|
255
|
+
|
|
256
|
+
if matched:
|
|
257
|
+
controls.append(
|
|
258
|
+
FrameworkControl(
|
|
259
|
+
framework="OWASP-Agentic",
|
|
260
|
+
control_id=category.id,
|
|
261
|
+
title=category.name,
|
|
262
|
+
description=category.description,
|
|
263
|
+
requirement_level="required",
|
|
264
|
+
)
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
return controls
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""PCI-DSS v4.0 control mapping for security findings.
|
|
2
|
+
|
|
3
|
+
Maps findings to PCI-DSS requirements based on CWE IDs and rule patterns.
|
|
4
|
+
Reference: https://docs-prv.pcisecuritystandards.org/PCI%20DSS/Standard/PCI-DSS-v4_0.pdf
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from .mappings import FrameworkControl
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from kekkai.scanners.base import Finding
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class PCIDSSControl:
|
|
20
|
+
"""PCI-DSS v4.0 control definition."""
|
|
21
|
+
|
|
22
|
+
id: str
|
|
23
|
+
title: str
|
|
24
|
+
description: str
|
|
25
|
+
cwes: frozenset[int]
|
|
26
|
+
rule_patterns: tuple[str, ...]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# PCI-DSS v4.0 Requirements relevant to application security
|
|
30
|
+
PCI_DSS_CONTROLS: dict[str, PCIDSSControl] = {
|
|
31
|
+
"1.4": PCIDSSControl(
|
|
32
|
+
id="1.4",
|
|
33
|
+
title="Network connections between trusted and untrusted networks are controlled",
|
|
34
|
+
description=(
|
|
35
|
+
"System components that store, process, or transmit CHD are not "
|
|
36
|
+
"directly accessible from untrusted networks"
|
|
37
|
+
),
|
|
38
|
+
cwes=frozenset({918, 441}), # SSRF, open redirect
|
|
39
|
+
rule_patterns=("ssrf", "network", "firewall"),
|
|
40
|
+
),
|
|
41
|
+
"2.2.6": PCIDSSControl(
|
|
42
|
+
id="2.2.6",
|
|
43
|
+
title="System security parameters prevent misuse",
|
|
44
|
+
description="Common security parameter settings are correctly configured",
|
|
45
|
+
cwes=frozenset({16, 260, 315, 520, 756}),
|
|
46
|
+
rule_patterns=("misconfiguration", "config", "security-parameter", "hardcoded"),
|
|
47
|
+
),
|
|
48
|
+
"3.5": PCIDSSControl(
|
|
49
|
+
id="3.5",
|
|
50
|
+
title="Primary account number (PAN) is secured wherever stored",
|
|
51
|
+
description="PAN is rendered unreadable using strong cryptography",
|
|
52
|
+
cwes=frozenset({311, 312, 319, 327, 328}),
|
|
53
|
+
rule_patterns=("encryption", "crypto", "storage", "pan", "card"),
|
|
54
|
+
),
|
|
55
|
+
"4.2": PCIDSSControl(
|
|
56
|
+
id="4.2",
|
|
57
|
+
title="PAN is protected during transmission",
|
|
58
|
+
description=(
|
|
59
|
+
"Strong cryptography protects PAN during transmission over open, public networks"
|
|
60
|
+
),
|
|
61
|
+
cwes=frozenset({319, 523, 757}),
|
|
62
|
+
rule_patterns=("tls", "ssl", "transmission", "transport"),
|
|
63
|
+
),
|
|
64
|
+
"5.2": PCIDSSControl(
|
|
65
|
+
id="5.2",
|
|
66
|
+
title="Malicious software is prevented or detected and addressed",
|
|
67
|
+
description="Anti-malware solutions detect and address malicious software",
|
|
68
|
+
cwes=frozenset({94, 502, 829}), # code injection, deserialization, untrusted code
|
|
69
|
+
rule_patterns=("malware", "code-injection", "deserialization"),
|
|
70
|
+
),
|
|
71
|
+
"6.2.4": PCIDSSControl(
|
|
72
|
+
id="6.2.4",
|
|
73
|
+
title="Software engineering techniques prevent or mitigate common attacks",
|
|
74
|
+
description=(
|
|
75
|
+
"Injection attacks, buffer overflows, insecure cryptographic "
|
|
76
|
+
"storage, etc. are prevented"
|
|
77
|
+
),
|
|
78
|
+
cwes=frozenset({20, 74, 77, 78, 79, 89, 90, 91, 94, 120, 134, 190}),
|
|
79
|
+
rule_patterns=("injection", "sqli", "xss", "buffer", "overflow"),
|
|
80
|
+
),
|
|
81
|
+
"6.3.1": PCIDSSControl(
|
|
82
|
+
id="6.3.1",
|
|
83
|
+
title="Security vulnerabilities are identified and managed",
|
|
84
|
+
description=(
|
|
85
|
+
"A process is defined for identifying security vulnerabilities "
|
|
86
|
+
"using reputable external sources"
|
|
87
|
+
),
|
|
88
|
+
cwes=frozenset({937, 1035, 1104}),
|
|
89
|
+
rule_patterns=("cve-", "vulnerability", "outdated", "component"),
|
|
90
|
+
),
|
|
91
|
+
"6.3.2": PCIDSSControl(
|
|
92
|
+
id="6.3.2",
|
|
93
|
+
title="An inventory of custom and third-party software is maintained",
|
|
94
|
+
description="Software inventory including components and dependencies",
|
|
95
|
+
cwes=frozenset({1104}),
|
|
96
|
+
rule_patterns=("dependency", "component", "sbom"),
|
|
97
|
+
),
|
|
98
|
+
"6.5.1": PCIDSSControl(
|
|
99
|
+
id="6.5.1",
|
|
100
|
+
title="Changes to production systems follow change control procedures",
|
|
101
|
+
description="Development and test environments are separate from production",
|
|
102
|
+
cwes=frozenset({489, 540}), # debug code, sensitive info exposure
|
|
103
|
+
rule_patterns=("debug", "development", "test-code"),
|
|
104
|
+
),
|
|
105
|
+
"6.5.2": PCIDSSControl(
|
|
106
|
+
id="6.5.2",
|
|
107
|
+
title="Live PANs are not used in pre-production environments",
|
|
108
|
+
description="Test data does not contain live PAN or sensitive auth data",
|
|
109
|
+
cwes=frozenset({200, 312}),
|
|
110
|
+
rule_patterns=("test-data", "sensitive-data", "pii"),
|
|
111
|
+
),
|
|
112
|
+
"6.5.4": PCIDSSControl(
|
|
113
|
+
id="6.5.4",
|
|
114
|
+
title="Roles and functions are separated between production and pre-production",
|
|
115
|
+
description="Separation of duties between environments",
|
|
116
|
+
cwes=frozenset({269, 284}),
|
|
117
|
+
rule_patterns=("privilege", "separation", "access-control"),
|
|
118
|
+
),
|
|
119
|
+
"7.2": PCIDSSControl(
|
|
120
|
+
id="7.2",
|
|
121
|
+
title="Access to system components and data is appropriately defined",
|
|
122
|
+
description="Role-based access control limits access based on need-to-know",
|
|
123
|
+
cwes=frozenset({264, 284, 285, 639, 862, 863}),
|
|
124
|
+
rule_patterns=("access-control", "authorization", "rbac", "idor"),
|
|
125
|
+
),
|
|
126
|
+
"8.3": PCIDSSControl(
|
|
127
|
+
id="8.3",
|
|
128
|
+
title="Strong authentication for users and administrators",
|
|
129
|
+
description="MFA and strong password requirements",
|
|
130
|
+
cwes=frozenset({255, 259, 287, 307, 521, 640, 798}),
|
|
131
|
+
rule_patterns=("authentication", "password", "credential", "mfa", "hardcoded-password"),
|
|
132
|
+
),
|
|
133
|
+
"8.6": PCIDSSControl(
|
|
134
|
+
id="8.6",
|
|
135
|
+
title="Use of application and system accounts is strictly managed",
|
|
136
|
+
description="Shared and service accounts are managed securely",
|
|
137
|
+
cwes=frozenset({250, 269, 522}),
|
|
138
|
+
rule_patterns=("service-account", "shared-credential", "privilege"),
|
|
139
|
+
),
|
|
140
|
+
"10.3": PCIDSSControl(
|
|
141
|
+
id="10.3",
|
|
142
|
+
title="Audit logs are protected from destruction and unauthorized modifications",
|
|
143
|
+
description="Audit trail records cannot be altered",
|
|
144
|
+
cwes=frozenset({117, 532, 778}),
|
|
145
|
+
rule_patterns=("logging", "audit", "log-injection", "log-tampering"),
|
|
146
|
+
),
|
|
147
|
+
"11.3.1": PCIDSSControl(
|
|
148
|
+
id="11.3.1",
|
|
149
|
+
title="External and internal vulnerabilities are managed",
|
|
150
|
+
description="Vulnerability scans performed at least quarterly",
|
|
151
|
+
cwes=frozenset({937}),
|
|
152
|
+
rule_patterns=("vulnerability", "scan"),
|
|
153
|
+
),
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _extract_cwe_id(cwe_str: str | None) -> int | None:
|
|
158
|
+
"""Extract numeric CWE ID from string."""
|
|
159
|
+
if not cwe_str:
|
|
160
|
+
return None
|
|
161
|
+
cwe_str = cwe_str.upper().replace("CWE-", "").replace("CWE", "")
|
|
162
|
+
try:
|
|
163
|
+
return int(cwe_str.strip())
|
|
164
|
+
except ValueError:
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def map_to_pci_dss(finding: Finding) -> list[FrameworkControl]:
|
|
169
|
+
"""Map a finding to PCI-DSS v4.0 controls."""
|
|
170
|
+
controls: list[FrameworkControl] = []
|
|
171
|
+
|
|
172
|
+
cwe_id = _extract_cwe_id(finding.cwe)
|
|
173
|
+
rule_id_lower = (finding.rule_id or "").lower()
|
|
174
|
+
title_lower = finding.title.lower()
|
|
175
|
+
|
|
176
|
+
for control in PCI_DSS_CONTROLS.values():
|
|
177
|
+
matched = False
|
|
178
|
+
|
|
179
|
+
# Match by CWE
|
|
180
|
+
if cwe_id and cwe_id in control.cwes:
|
|
181
|
+
matched = True
|
|
182
|
+
|
|
183
|
+
# Match by rule pattern
|
|
184
|
+
if not matched:
|
|
185
|
+
for pattern in control.rule_patterns:
|
|
186
|
+
if pattern in rule_id_lower or pattern in title_lower:
|
|
187
|
+
matched = True
|
|
188
|
+
break
|
|
189
|
+
|
|
190
|
+
# Special case: CVEs map to 6.3.1 (vulnerability management)
|
|
191
|
+
if not matched and control.id == "6.3.1" and finding.cve:
|
|
192
|
+
matched = True
|
|
193
|
+
|
|
194
|
+
if matched:
|
|
195
|
+
controls.append(
|
|
196
|
+
FrameworkControl(
|
|
197
|
+
framework="PCI-DSS",
|
|
198
|
+
control_id=control.id,
|
|
199
|
+
title=control.title,
|
|
200
|
+
description=control.description,
|
|
201
|
+
requirement_level="required",
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
return controls
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""SOC 2 Type II criteria mapping for security findings.
|
|
2
|
+
|
|
3
|
+
Maps findings to SOC 2 Trust Services Criteria based on CWE IDs and rule patterns.
|
|
4
|
+
Reference: https://www.aicpa.org/resources/landing/trust-services-criteria
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from .mappings import FrameworkControl
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from kekkai.scanners.base import Finding
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class SOC2Criterion:
|
|
20
|
+
"""SOC 2 Trust Services Criterion definition."""
|
|
21
|
+
|
|
22
|
+
id: str
|
|
23
|
+
title: str
|
|
24
|
+
description: str
|
|
25
|
+
category: str # Security, Availability, Processing Integrity, Confidentiality, Privacy
|
|
26
|
+
cwes: frozenset[int]
|
|
27
|
+
rule_patterns: tuple[str, ...]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# SOC 2 Trust Services Criteria relevant to application security
|
|
31
|
+
SOC2_CRITERIA: dict[str, SOC2Criterion] = {
|
|
32
|
+
# Security (Common Criteria)
|
|
33
|
+
"CC6.1": SOC2Criterion(
|
|
34
|
+
id="CC6.1",
|
|
35
|
+
title="Logical and Physical Access Controls",
|
|
36
|
+
description=(
|
|
37
|
+
"The entity implements logical access security software, "
|
|
38
|
+
"infrastructure, and architectures to protect against threats"
|
|
39
|
+
),
|
|
40
|
+
category="Security",
|
|
41
|
+
cwes=frozenset({264, 284, 285, 287, 306, 639, 862, 863}),
|
|
42
|
+
rule_patterns=("access-control", "authorization", "authentication", "idor"),
|
|
43
|
+
),
|
|
44
|
+
"CC6.2": SOC2Criterion(
|
|
45
|
+
id="CC6.2",
|
|
46
|
+
title="User Registration and Authorization",
|
|
47
|
+
description="Prior to issuing system credentials, users are registered and authorized",
|
|
48
|
+
category="Security",
|
|
49
|
+
cwes=frozenset({287, 288, 302, 307, 521}),
|
|
50
|
+
rule_patterns=("registration", "user-management", "credential"),
|
|
51
|
+
),
|
|
52
|
+
"CC6.3": SOC2Criterion(
|
|
53
|
+
id="CC6.3",
|
|
54
|
+
title="Credential Lifecycle Management",
|
|
55
|
+
description="The entity authorizes, modifies, or removes access based on roles",
|
|
56
|
+
category="Security",
|
|
57
|
+
cwes=frozenset({255, 259, 269, 522, 613, 640, 798}),
|
|
58
|
+
rule_patterns=("credential", "password", "session", "privilege"),
|
|
59
|
+
),
|
|
60
|
+
"CC6.6": SOC2Criterion(
|
|
61
|
+
id="CC6.6",
|
|
62
|
+
title="Security Events Detection",
|
|
63
|
+
description="The entity implements controls to prevent, detect, and act on security events",
|
|
64
|
+
category="Security",
|
|
65
|
+
cwes=frozenset({117, 223, 532, 778}),
|
|
66
|
+
rule_patterns=("logging", "monitoring", "detection", "audit"),
|
|
67
|
+
),
|
|
68
|
+
"CC6.7": SOC2Criterion(
|
|
69
|
+
id="CC6.7",
|
|
70
|
+
title="Transmission Protection",
|
|
71
|
+
description=(
|
|
72
|
+
"The entity restricts transmission of confidential information "
|
|
73
|
+
"over communication channels"
|
|
74
|
+
),
|
|
75
|
+
category="Security",
|
|
76
|
+
cwes=frozenset({319, 523, 757}),
|
|
77
|
+
rule_patterns=("tls", "ssl", "encryption", "transmission"),
|
|
78
|
+
),
|
|
79
|
+
"CC6.8": SOC2Criterion(
|
|
80
|
+
id="CC6.8",
|
|
81
|
+
title="Malicious Software Prevention",
|
|
82
|
+
description="The entity implements controls to prevent or detect malicious software",
|
|
83
|
+
category="Security",
|
|
84
|
+
cwes=frozenset({94, 502, 829}),
|
|
85
|
+
rule_patterns=("malware", "injection", "deserialization"),
|
|
86
|
+
),
|
|
87
|
+
"CC7.1": SOC2Criterion(
|
|
88
|
+
id="CC7.1",
|
|
89
|
+
title="Vulnerability Management",
|
|
90
|
+
description=(
|
|
91
|
+
"The entity uses detection and monitoring procedures to identify vulnerabilities"
|
|
92
|
+
),
|
|
93
|
+
category="Security",
|
|
94
|
+
cwes=frozenset({937, 1035, 1104}),
|
|
95
|
+
rule_patterns=("vulnerability", "cve-", "outdated", "component"),
|
|
96
|
+
),
|
|
97
|
+
"CC7.2": SOC2Criterion(
|
|
98
|
+
id="CC7.2",
|
|
99
|
+
title="Security Incident Response",
|
|
100
|
+
description=(
|
|
101
|
+
"The entity monitors system components for anomalies indicative of malicious acts"
|
|
102
|
+
),
|
|
103
|
+
category="Security",
|
|
104
|
+
cwes=frozenset({778, 779}),
|
|
105
|
+
rule_patterns=("incident", "response", "anomaly"),
|
|
106
|
+
),
|
|
107
|
+
"CC8.1": SOC2Criterion(
|
|
108
|
+
id="CC8.1",
|
|
109
|
+
title="Change Management",
|
|
110
|
+
description="The entity authorizes, designs, develops, configures, and implements changes",
|
|
111
|
+
category="Security",
|
|
112
|
+
cwes=frozenset({489, 540}),
|
|
113
|
+
rule_patterns=("change-management", "deployment", "debug"),
|
|
114
|
+
),
|
|
115
|
+
# Confidentiality
|
|
116
|
+
"C1.1": SOC2Criterion(
|
|
117
|
+
id="C1.1",
|
|
118
|
+
title="Confidential Information Identification",
|
|
119
|
+
description="The entity identifies and maintains confidential information",
|
|
120
|
+
category="Confidentiality",
|
|
121
|
+
cwes=frozenset({200, 201, 312, 319, 359}),
|
|
122
|
+
rule_patterns=("sensitive-data", "pii", "secret", "confidential"),
|
|
123
|
+
),
|
|
124
|
+
"C1.2": SOC2Criterion(
|
|
125
|
+
id="C1.2",
|
|
126
|
+
title="Confidential Information Disposal",
|
|
127
|
+
description="The entity disposes of confidential information to meet objectives",
|
|
128
|
+
category="Confidentiality",
|
|
129
|
+
cwes=frozenset({226, 312, 459}),
|
|
130
|
+
rule_patterns=("disposal", "cleanup", "retention"),
|
|
131
|
+
),
|
|
132
|
+
# Processing Integrity
|
|
133
|
+
"PI1.2": SOC2Criterion(
|
|
134
|
+
id="PI1.2",
|
|
135
|
+
title="Input Validation",
|
|
136
|
+
description="The entity implements policies to verify input is complete and accurate",
|
|
137
|
+
category="Processing Integrity",
|
|
138
|
+
cwes=frozenset({20, 74, 77, 78, 79, 89, 91, 94}),
|
|
139
|
+
rule_patterns=("validation", "input", "injection", "xss", "sqli"),
|
|
140
|
+
),
|
|
141
|
+
"PI1.4": SOC2Criterion(
|
|
142
|
+
id="PI1.4",
|
|
143
|
+
title="Output Validation",
|
|
144
|
+
description="The entity implements policies to verify output is complete and accurate",
|
|
145
|
+
category="Processing Integrity",
|
|
146
|
+
cwes=frozenset({79, 116}),
|
|
147
|
+
rule_patterns=("output", "encoding", "xss"),
|
|
148
|
+
),
|
|
149
|
+
# Availability
|
|
150
|
+
"A1.2": SOC2Criterion(
|
|
151
|
+
id="A1.2",
|
|
152
|
+
title="System Recovery",
|
|
153
|
+
description="The entity implements policies to support system recovery",
|
|
154
|
+
category="Availability",
|
|
155
|
+
cwes=frozenset({400, 770}), # resource exhaustion
|
|
156
|
+
rule_patterns=("dos", "resource", "availability", "recovery"),
|
|
157
|
+
),
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _extract_cwe_id(cwe_str: str | None) -> int | None:
|
|
162
|
+
"""Extract numeric CWE ID from string."""
|
|
163
|
+
if not cwe_str:
|
|
164
|
+
return None
|
|
165
|
+
cwe_str = cwe_str.upper().replace("CWE-", "").replace("CWE", "")
|
|
166
|
+
try:
|
|
167
|
+
return int(cwe_str.strip())
|
|
168
|
+
except ValueError:
|
|
169
|
+
return None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def map_to_soc2(finding: Finding) -> list[FrameworkControl]:
|
|
173
|
+
"""Map a finding to SOC 2 criteria."""
|
|
174
|
+
controls: list[FrameworkControl] = []
|
|
175
|
+
|
|
176
|
+
cwe_id = _extract_cwe_id(finding.cwe)
|
|
177
|
+
rule_id_lower = (finding.rule_id or "").lower()
|
|
178
|
+
title_lower = finding.title.lower()
|
|
179
|
+
|
|
180
|
+
for criterion in SOC2_CRITERIA.values():
|
|
181
|
+
matched = False
|
|
182
|
+
|
|
183
|
+
# Match by CWE
|
|
184
|
+
if cwe_id and cwe_id in criterion.cwes:
|
|
185
|
+
matched = True
|
|
186
|
+
|
|
187
|
+
# Match by rule pattern
|
|
188
|
+
if not matched:
|
|
189
|
+
for pattern in criterion.rule_patterns:
|
|
190
|
+
if pattern in rule_id_lower or pattern in title_lower:
|
|
191
|
+
matched = True
|
|
192
|
+
break
|
|
193
|
+
|
|
194
|
+
# CVEs map to CC7.1 (vulnerability management)
|
|
195
|
+
if not matched and criterion.id == "CC7.1" and finding.cve:
|
|
196
|
+
matched = True
|
|
197
|
+
|
|
198
|
+
if matched:
|
|
199
|
+
controls.append(
|
|
200
|
+
FrameworkControl(
|
|
201
|
+
framework="SOC2",
|
|
202
|
+
control_id=criterion.id,
|
|
203
|
+
title=criterion.title,
|
|
204
|
+
description=criterion.description,
|
|
205
|
+
requirement_level="required",
|
|
206
|
+
)
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
return controls
|