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,517 @@
|
|
|
1
|
+
"""OWASP Top 10 2025 mapping for security findings.
|
|
2
|
+
|
|
3
|
+
Maps findings to OWASP Top 10 2025 categories based on CWE IDs and rule patterns.
|
|
4
|
+
Reference: https://owasp.org/Top10/2025/
|
|
5
|
+
|
|
6
|
+
Changes from 2021:
|
|
7
|
+
- A01:2025 Broken Access Control (now includes SSRF)
|
|
8
|
+
- A02:2025 Security Misconfiguration (moved up from #5)
|
|
9
|
+
- A03:2025 Software Supply Chain Failures (NEW - replaces Vulnerable Components)
|
|
10
|
+
- A04:2025 Cryptographic Failures (moved down from #2)
|
|
11
|
+
- A05:2025 Injection (moved down from #3)
|
|
12
|
+
- A06:2025 Insecure Design (moved down from #4)
|
|
13
|
+
- A07:2025 Authentication Failures (renamed)
|
|
14
|
+
- A08:2025 Software or Data Integrity Failures (stable)
|
|
15
|
+
- A09:2025 Security Logging and Alerting Failures (minor rename)
|
|
16
|
+
- A10:2025 Mishandling of Exceptional Conditions (NEW)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from typing import TYPE_CHECKING
|
|
23
|
+
|
|
24
|
+
from .mappings import FrameworkControl
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from kekkai.scanners.base import Finding
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass(frozen=True)
|
|
31
|
+
class OWASPCategory:
|
|
32
|
+
"""OWASP Top 10 category definition."""
|
|
33
|
+
|
|
34
|
+
id: str
|
|
35
|
+
name: str
|
|
36
|
+
description: str
|
|
37
|
+
cwes: frozenset[int]
|
|
38
|
+
rule_patterns: tuple[str, ...]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# OWASP Top 10 2025 Categories with CWE mappings
|
|
42
|
+
OWASP_TOP_10: dict[str, OWASPCategory] = {
|
|
43
|
+
"A01": OWASPCategory(
|
|
44
|
+
id="A01:2025",
|
|
45
|
+
name="Broken Access Control",
|
|
46
|
+
description=(
|
|
47
|
+
"Restrictions on authenticated users are not properly enforced. "
|
|
48
|
+
"Now includes SSRF vulnerabilities."
|
|
49
|
+
),
|
|
50
|
+
cwes=frozenset(
|
|
51
|
+
{
|
|
52
|
+
22,
|
|
53
|
+
23,
|
|
54
|
+
35,
|
|
55
|
+
59, # Path traversal
|
|
56
|
+
200,
|
|
57
|
+
201,
|
|
58
|
+
219, # Information exposure
|
|
59
|
+
264,
|
|
60
|
+
275,
|
|
61
|
+
276,
|
|
62
|
+
284,
|
|
63
|
+
285, # Permissions
|
|
64
|
+
352, # CSRF
|
|
65
|
+
359,
|
|
66
|
+
377,
|
|
67
|
+
402,
|
|
68
|
+
425,
|
|
69
|
+
441,
|
|
70
|
+
497,
|
|
71
|
+
538,
|
|
72
|
+
540,
|
|
73
|
+
548,
|
|
74
|
+
552,
|
|
75
|
+
566,
|
|
76
|
+
601, # Open redirect
|
|
77
|
+
639,
|
|
78
|
+
651,
|
|
79
|
+
668,
|
|
80
|
+
706,
|
|
81
|
+
862,
|
|
82
|
+
863, # Missing authorization
|
|
83
|
+
913,
|
|
84
|
+
918, # SSRF (moved from A10:2021)
|
|
85
|
+
922,
|
|
86
|
+
1275,
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
rule_patterns=(
|
|
90
|
+
"access-control",
|
|
91
|
+
"authorization",
|
|
92
|
+
"idor",
|
|
93
|
+
"path-traversal",
|
|
94
|
+
"directory-traversal",
|
|
95
|
+
"ssrf",
|
|
96
|
+
"server-side-request",
|
|
97
|
+
"open-redirect",
|
|
98
|
+
),
|
|
99
|
+
),
|
|
100
|
+
"A02": OWASPCategory(
|
|
101
|
+
id="A02:2025",
|
|
102
|
+
name="Security Misconfiguration",
|
|
103
|
+
description=(
|
|
104
|
+
"Missing security hardening or improperly configured permissions. "
|
|
105
|
+
"Moved up from #5 in 2021."
|
|
106
|
+
),
|
|
107
|
+
cwes=frozenset(
|
|
108
|
+
{
|
|
109
|
+
2,
|
|
110
|
+
11,
|
|
111
|
+
13,
|
|
112
|
+
15,
|
|
113
|
+
16,
|
|
114
|
+
260,
|
|
115
|
+
315,
|
|
116
|
+
520,
|
|
117
|
+
526,
|
|
118
|
+
537,
|
|
119
|
+
541,
|
|
120
|
+
547,
|
|
121
|
+
611, # XXE
|
|
122
|
+
614,
|
|
123
|
+
756,
|
|
124
|
+
776,
|
|
125
|
+
942,
|
|
126
|
+
1004,
|
|
127
|
+
1032,
|
|
128
|
+
1174,
|
|
129
|
+
}
|
|
130
|
+
),
|
|
131
|
+
rule_patterns=(
|
|
132
|
+
"misconfiguration",
|
|
133
|
+
"config",
|
|
134
|
+
"default",
|
|
135
|
+
"debug",
|
|
136
|
+
"verbose",
|
|
137
|
+
"hardcoded",
|
|
138
|
+
"xxe",
|
|
139
|
+
),
|
|
140
|
+
),
|
|
141
|
+
"A03": OWASPCategory(
|
|
142
|
+
id="A03:2025",
|
|
143
|
+
name="Software Supply Chain Failures",
|
|
144
|
+
description=(
|
|
145
|
+
"Vulnerabilities in software dependencies, build systems, and "
|
|
146
|
+
"distribution infrastructure. Replaces Vulnerable Components from 2021."
|
|
147
|
+
),
|
|
148
|
+
cwes=frozenset(
|
|
149
|
+
{
|
|
150
|
+
426, # Untrusted search path
|
|
151
|
+
494, # Download without integrity check
|
|
152
|
+
506, # Embedded malicious code
|
|
153
|
+
829, # Inclusion of untrusted functionality
|
|
154
|
+
937, # Using components with known vulnerabilities
|
|
155
|
+
1035, # Reliance on reverse DNS
|
|
156
|
+
1104, # Use of unmaintained third-party components
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
rule_patterns=(
|
|
160
|
+
"supply-chain",
|
|
161
|
+
"dependency",
|
|
162
|
+
"component",
|
|
163
|
+
"outdated",
|
|
164
|
+
"cve-",
|
|
165
|
+
"vulnerability",
|
|
166
|
+
"sbom",
|
|
167
|
+
"third-party",
|
|
168
|
+
),
|
|
169
|
+
),
|
|
170
|
+
"A04": OWASPCategory(
|
|
171
|
+
id="A04:2025",
|
|
172
|
+
name="Cryptographic Failures",
|
|
173
|
+
description=(
|
|
174
|
+
"Failures related to cryptography leading to sensitive data exposure. "
|
|
175
|
+
"Moved down from #2 in 2021."
|
|
176
|
+
),
|
|
177
|
+
cwes=frozenset(
|
|
178
|
+
{
|
|
179
|
+
261,
|
|
180
|
+
296,
|
|
181
|
+
310,
|
|
182
|
+
319, # Cleartext transmission
|
|
183
|
+
320,
|
|
184
|
+
321,
|
|
185
|
+
322,
|
|
186
|
+
323,
|
|
187
|
+
324,
|
|
188
|
+
325,
|
|
189
|
+
326,
|
|
190
|
+
327,
|
|
191
|
+
328,
|
|
192
|
+
329, # Weak crypto
|
|
193
|
+
330,
|
|
194
|
+
331,
|
|
195
|
+
335,
|
|
196
|
+
336,
|
|
197
|
+
337,
|
|
198
|
+
338,
|
|
199
|
+
339,
|
|
200
|
+
340,
|
|
201
|
+
347,
|
|
202
|
+
523,
|
|
203
|
+
720,
|
|
204
|
+
757,
|
|
205
|
+
759,
|
|
206
|
+
760,
|
|
207
|
+
780,
|
|
208
|
+
818,
|
|
209
|
+
916,
|
|
210
|
+
}
|
|
211
|
+
),
|
|
212
|
+
rule_patterns=(
|
|
213
|
+
"crypto",
|
|
214
|
+
"encryption",
|
|
215
|
+
"hash",
|
|
216
|
+
"ssl",
|
|
217
|
+
"tls",
|
|
218
|
+
"certificate",
|
|
219
|
+
"weak-crypto",
|
|
220
|
+
"cleartext",
|
|
221
|
+
),
|
|
222
|
+
),
|
|
223
|
+
"A05": OWASPCategory(
|
|
224
|
+
id="A05:2025",
|
|
225
|
+
name="Injection",
|
|
226
|
+
description=(
|
|
227
|
+
"User-supplied data is not validated, filtered, or sanitized. "
|
|
228
|
+
"Moved down from #3 in 2021."
|
|
229
|
+
),
|
|
230
|
+
cwes=frozenset(
|
|
231
|
+
{
|
|
232
|
+
20, # Improper input validation
|
|
233
|
+
74,
|
|
234
|
+
75,
|
|
235
|
+
77,
|
|
236
|
+
78,
|
|
237
|
+
79,
|
|
238
|
+
80,
|
|
239
|
+
83,
|
|
240
|
+
87,
|
|
241
|
+
88,
|
|
242
|
+
89, # SQL injection
|
|
243
|
+
90,
|
|
244
|
+
91,
|
|
245
|
+
93,
|
|
246
|
+
94,
|
|
247
|
+
95,
|
|
248
|
+
96,
|
|
249
|
+
97,
|
|
250
|
+
98,
|
|
251
|
+
99,
|
|
252
|
+
100,
|
|
253
|
+
113,
|
|
254
|
+
116,
|
|
255
|
+
138,
|
|
256
|
+
184,
|
|
257
|
+
470,
|
|
258
|
+
471,
|
|
259
|
+
564,
|
|
260
|
+
610,
|
|
261
|
+
643,
|
|
262
|
+
644,
|
|
263
|
+
652,
|
|
264
|
+
917,
|
|
265
|
+
}
|
|
266
|
+
),
|
|
267
|
+
rule_patterns=(
|
|
268
|
+
"injection",
|
|
269
|
+
"sqli",
|
|
270
|
+
"xss",
|
|
271
|
+
"command-injection",
|
|
272
|
+
"os-command",
|
|
273
|
+
"ldap",
|
|
274
|
+
"xpath",
|
|
275
|
+
"nosql",
|
|
276
|
+
"template-injection",
|
|
277
|
+
),
|
|
278
|
+
),
|
|
279
|
+
"A06": OWASPCategory(
|
|
280
|
+
id="A06:2025",
|
|
281
|
+
name="Insecure Design",
|
|
282
|
+
description=("Missing or ineffective control design. Moved down from #4 in 2021."),
|
|
283
|
+
cwes=frozenset(
|
|
284
|
+
{
|
|
285
|
+
73,
|
|
286
|
+
183,
|
|
287
|
+
209,
|
|
288
|
+
213,
|
|
289
|
+
235,
|
|
290
|
+
256,
|
|
291
|
+
257,
|
|
292
|
+
266,
|
|
293
|
+
269,
|
|
294
|
+
280,
|
|
295
|
+
311,
|
|
296
|
+
312,
|
|
297
|
+
313,
|
|
298
|
+
316,
|
|
299
|
+
419,
|
|
300
|
+
430,
|
|
301
|
+
434,
|
|
302
|
+
444,
|
|
303
|
+
451,
|
|
304
|
+
472,
|
|
305
|
+
501,
|
|
306
|
+
522,
|
|
307
|
+
525,
|
|
308
|
+
539,
|
|
309
|
+
579,
|
|
310
|
+
598,
|
|
311
|
+
602,
|
|
312
|
+
642,
|
|
313
|
+
646,
|
|
314
|
+
650,
|
|
315
|
+
653,
|
|
316
|
+
656,
|
|
317
|
+
657,
|
|
318
|
+
799,
|
|
319
|
+
807,
|
|
320
|
+
840,
|
|
321
|
+
841,
|
|
322
|
+
927,
|
|
323
|
+
1021,
|
|
324
|
+
1173,
|
|
325
|
+
}
|
|
326
|
+
),
|
|
327
|
+
rule_patterns=(
|
|
328
|
+
"insecure-design",
|
|
329
|
+
"business-logic",
|
|
330
|
+
"threat-model",
|
|
331
|
+
"race-condition",
|
|
332
|
+
),
|
|
333
|
+
),
|
|
334
|
+
"A07": OWASPCategory(
|
|
335
|
+
id="A07:2025",
|
|
336
|
+
name="Authentication Failures",
|
|
337
|
+
description=(
|
|
338
|
+
"Functions related to authentication and session management "
|
|
339
|
+
"are incorrectly implemented. Renamed from 'Identification and "
|
|
340
|
+
"Authentication Failures'."
|
|
341
|
+
),
|
|
342
|
+
cwes=frozenset(
|
|
343
|
+
{
|
|
344
|
+
255,
|
|
345
|
+
259,
|
|
346
|
+
287,
|
|
347
|
+
288,
|
|
348
|
+
290,
|
|
349
|
+
294,
|
|
350
|
+
295,
|
|
351
|
+
297,
|
|
352
|
+
300,
|
|
353
|
+
302,
|
|
354
|
+
304,
|
|
355
|
+
306,
|
|
356
|
+
307,
|
|
357
|
+
346,
|
|
358
|
+
384,
|
|
359
|
+
521, # Weak password
|
|
360
|
+
613, # Session expiration
|
|
361
|
+
620,
|
|
362
|
+
640,
|
|
363
|
+
798, # Hardcoded credentials
|
|
364
|
+
940,
|
|
365
|
+
1216,
|
|
366
|
+
}
|
|
367
|
+
),
|
|
368
|
+
rule_patterns=(
|
|
369
|
+
"authentication",
|
|
370
|
+
"auth",
|
|
371
|
+
"session",
|
|
372
|
+
"password",
|
|
373
|
+
"credential",
|
|
374
|
+
"login",
|
|
375
|
+
"jwt",
|
|
376
|
+
"mfa",
|
|
377
|
+
"2fa",
|
|
378
|
+
),
|
|
379
|
+
),
|
|
380
|
+
"A08": OWASPCategory(
|
|
381
|
+
id="A08:2025",
|
|
382
|
+
name="Software or Data Integrity Failures",
|
|
383
|
+
description=("Code and infrastructure that does not protect against integrity violations."),
|
|
384
|
+
cwes=frozenset(
|
|
385
|
+
{
|
|
386
|
+
345, # Insufficient verification
|
|
387
|
+
353,
|
|
388
|
+
426,
|
|
389
|
+
494,
|
|
390
|
+
502, # Deserialization
|
|
391
|
+
565,
|
|
392
|
+
784,
|
|
393
|
+
829,
|
|
394
|
+
830,
|
|
395
|
+
913,
|
|
396
|
+
915,
|
|
397
|
+
}
|
|
398
|
+
),
|
|
399
|
+
rule_patterns=(
|
|
400
|
+
"deserialization",
|
|
401
|
+
"integrity",
|
|
402
|
+
"signature",
|
|
403
|
+
"ci-cd",
|
|
404
|
+
"update",
|
|
405
|
+
"tampering",
|
|
406
|
+
),
|
|
407
|
+
),
|
|
408
|
+
"A09": OWASPCategory(
|
|
409
|
+
id="A09:2025",
|
|
410
|
+
name="Security Logging and Alerting Failures",
|
|
411
|
+
description=(
|
|
412
|
+
"Insufficient logging, detection, monitoring, and active response. "
|
|
413
|
+
"Minor rename to include 'Alerting'."
|
|
414
|
+
),
|
|
415
|
+
cwes=frozenset(
|
|
416
|
+
{
|
|
417
|
+
117, # Log injection
|
|
418
|
+
223, # Omission of security info
|
|
419
|
+
532, # Info exposure through logs
|
|
420
|
+
778,
|
|
421
|
+
779, # Insufficient logging
|
|
422
|
+
}
|
|
423
|
+
),
|
|
424
|
+
rule_patterns=(
|
|
425
|
+
"logging",
|
|
426
|
+
"monitoring",
|
|
427
|
+
"audit",
|
|
428
|
+
"log-injection",
|
|
429
|
+
"alerting",
|
|
430
|
+
),
|
|
431
|
+
),
|
|
432
|
+
"A10": OWASPCategory(
|
|
433
|
+
id="A10:2025",
|
|
434
|
+
name="Mishandling of Exceptional Conditions",
|
|
435
|
+
description=(
|
|
436
|
+
"Improper handling of errors, exceptions, and unexpected inputs. NEW category in 2025."
|
|
437
|
+
),
|
|
438
|
+
cwes=frozenset(
|
|
439
|
+
{
|
|
440
|
+
248, # Uncaught exception
|
|
441
|
+
252,
|
|
442
|
+
253, # Unchecked return value
|
|
443
|
+
390,
|
|
444
|
+
391, # Detection of error condition
|
|
445
|
+
392, # Missing report of error
|
|
446
|
+
397, # Throwing generic exception
|
|
447
|
+
754, # Improper check for unusual conditions
|
|
448
|
+
755, # Improper handling of exceptional conditions
|
|
449
|
+
756, # Missing custom error page
|
|
450
|
+
757, # Selection of insecure algorithm during negotiation
|
|
451
|
+
}
|
|
452
|
+
),
|
|
453
|
+
rule_patterns=(
|
|
454
|
+
"exception",
|
|
455
|
+
"error-handling",
|
|
456
|
+
"uncaught",
|
|
457
|
+
"unhandled",
|
|
458
|
+
"edge-case",
|
|
459
|
+
"boundary",
|
|
460
|
+
"overflow",
|
|
461
|
+
),
|
|
462
|
+
),
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def _extract_cwe_id(cwe_str: str | None) -> int | None:
|
|
467
|
+
"""Extract numeric CWE ID from string like 'CWE-79'."""
|
|
468
|
+
if not cwe_str:
|
|
469
|
+
return None
|
|
470
|
+
cwe_str = cwe_str.upper().replace("CWE-", "").replace("CWE", "")
|
|
471
|
+
try:
|
|
472
|
+
return int(cwe_str.strip())
|
|
473
|
+
except ValueError:
|
|
474
|
+
return None
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def map_to_owasp(finding: Finding) -> list[FrameworkControl]:
|
|
478
|
+
"""Map a finding to OWASP Top 10 2025 categories."""
|
|
479
|
+
controls: list[FrameworkControl] = []
|
|
480
|
+
|
|
481
|
+
# Extract CWE ID
|
|
482
|
+
cwe_id = _extract_cwe_id(finding.cwe)
|
|
483
|
+
|
|
484
|
+
# Check rule_id patterns
|
|
485
|
+
rule_id_lower = (finding.rule_id or "").lower()
|
|
486
|
+
title_lower = finding.title.lower()
|
|
487
|
+
|
|
488
|
+
for category in OWASP_TOP_10.values():
|
|
489
|
+
matched = False
|
|
490
|
+
|
|
491
|
+
# Match by CWE
|
|
492
|
+
if cwe_id and cwe_id in category.cwes:
|
|
493
|
+
matched = True
|
|
494
|
+
|
|
495
|
+
# Match by rule pattern
|
|
496
|
+
if not matched:
|
|
497
|
+
for pattern in category.rule_patterns:
|
|
498
|
+
if pattern in rule_id_lower or pattern in title_lower:
|
|
499
|
+
matched = True
|
|
500
|
+
break
|
|
501
|
+
|
|
502
|
+
# Match CVEs to A03 (Software Supply Chain Failures)
|
|
503
|
+
if not matched and category.id == "A03:2025" and finding.cve:
|
|
504
|
+
matched = True
|
|
505
|
+
|
|
506
|
+
if matched:
|
|
507
|
+
controls.append(
|
|
508
|
+
FrameworkControl(
|
|
509
|
+
framework="OWASP",
|
|
510
|
+
control_id=category.id,
|
|
511
|
+
title=category.name,
|
|
512
|
+
description=category.description,
|
|
513
|
+
requirement_level="required",
|
|
514
|
+
)
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
return controls
|