Skip to content

Commit e4140ac

Browse files
committed
Add OWASP Top 10 and API importer support
1 parent 6dcc3d2 commit e4140ac

7 files changed

Lines changed: 371 additions & 0 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import unittest
2+
3+
from application import create_app, sqla # type: ignore
4+
from application.database import db
5+
from application.defs import cre_defs as defs
6+
from application.prompt_client import prompt_client
7+
from application.utils.external_project_parsers.parsers import owasp_api_top10_2023
8+
9+
10+
class TestOwaspApiTop10_2023Parser(unittest.TestCase):
11+
def tearDown(self) -> None:
12+
sqla.session.remove()
13+
sqla.drop_all()
14+
self.app_context.pop()
15+
16+
def setUp(self) -> None:
17+
self.app = create_app(mode="test")
18+
self.app_context = self.app.app_context()
19+
self.app_context.push()
20+
sqla.create_all()
21+
self.collection = db.Node_collection()
22+
23+
def test_parse(self) -> None:
24+
for cre_id, name in [
25+
("304-667", "Protect API against unauthorized access/modification (IDOR)"),
26+
("724-770", "Technical application access control"),
27+
("715-223", "Ensure trusted origin of third party resources"),
28+
]:
29+
self.collection.add_cre(defs.CRE(id=cre_id, name=name, description=""))
30+
31+
result = owasp_api_top10_2023.OwaspApiTop10_2023().parse(
32+
self.collection, prompt_client.PromptHandler(database=self.collection)
33+
)
34+
35+
entries = result.results["OWASP API Security Top 10 2023"]
36+
self.assertEqual(10, len(entries))
37+
self.assertEqual("API1", entries[0].sectionID)
38+
self.assertEqual("Broken Object Level Authorization", entries[0].section)
39+
self.assertEqual(
40+
["304-667", "724-770"], [l.document.id for l in entries[0].links]
41+
)
42+
self.assertEqual("API10", entries[-1].sectionID)
43+
self.assertEqual(["715-223"], [l.document.id for l in entries[-1].links])
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import unittest
2+
3+
from application import create_app, sqla # type: ignore
4+
from application.database import db
5+
from application.defs import cre_defs as defs
6+
from application.prompt_client import prompt_client
7+
from application.utils.external_project_parsers.parsers import owasp_top10_2025
8+
9+
10+
class TestOwaspTop10_2025Parser(unittest.TestCase):
11+
def tearDown(self) -> None:
12+
sqla.session.remove()
13+
sqla.drop_all()
14+
self.app_context.pop()
15+
16+
def setUp(self) -> None:
17+
self.app = create_app(mode="test")
18+
self.app_context = self.app.app_context()
19+
self.app_context.push()
20+
sqla.create_all()
21+
self.collection = db.Node_collection()
22+
23+
def test_parse(self) -> None:
24+
self.collection.add_cre(
25+
defs.CRE(id="177-260", name="Session management", description="")
26+
)
27+
self.collection.add_cre(
28+
defs.CRE(
29+
id="117-371",
30+
name="Use a centralized access control mechanism",
31+
description="",
32+
)
33+
)
34+
self.collection.add_cre(
35+
defs.CRE(
36+
id="724-770",
37+
name="Technical application access control",
38+
description="",
39+
)
40+
)
41+
self.collection.add_cre(
42+
defs.CRE(
43+
id="031-447", name="Whitelist all external (HTTP) input", description=""
44+
)
45+
)
46+
self.collection.add_cre(
47+
defs.CRE(
48+
id="064-808", name="Encode output context-specifically", description=""
49+
)
50+
)
51+
self.collection.add_cre(
52+
defs.CRE(id="760-764", name="Injection protection", description="")
53+
)
54+
self.collection.add_cre(
55+
defs.CRE(id="513-183", name="Error handling", description="")
56+
)
57+
58+
result = owasp_top10_2025.OwaspTop10_2025().parse(
59+
self.collection,
60+
prompt_client.PromptHandler(database=self.collection),
61+
)
62+
63+
entries = result.results["OWASP Top 10 2025"]
64+
self.assertEqual(10, len(entries))
65+
self.assertEqual("A01", entries[0].sectionID)
66+
self.assertEqual("Broken Access Control", entries[0].section)
67+
self.assertEqual(
68+
"https://owasp.org/Top10/2025/A01_2025-Broken_Access_Control/",
69+
entries[0].hyperlink,
70+
)
71+
self.assertEqual(
72+
["117-371", "177-260", "724-770"],
73+
[link.document.id for link in entries[0].links],
74+
)
75+
self.assertEqual(
76+
["031-447", "064-808", "760-764"],
77+
[link.document.id for link in entries[4].links],
78+
)
79+
self.assertEqual("A10", entries[-1].sectionID)
80+
self.assertEqual(["513-183"], [link.document.id for link in entries[-1].links])
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
[
2+
{
3+
"section_id": "API1",
4+
"section": "Broken Object Level Authorization",
5+
"hyperlink": "https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/",
6+
"cre_ids": ["304-667", "724-770"]
7+
},
8+
{
9+
"section_id": "API2",
10+
"section": "Broken Authentication",
11+
"hyperlink": "https://owasp.org/API-Security/editions/2023/en/0xa2-broken-authentication/",
12+
"cre_ids": ["177-260", "586-842", "633-428"]
13+
},
14+
{
15+
"section_id": "API3",
16+
"section": "Broken Object Property Level Authorization",
17+
"hyperlink": "https://owasp.org/API-Security/editions/2023/en/0xa3-broken-object-property-level-authorization/",
18+
"cre_ids": ["538-770", "724-770", "128-128"]
19+
},
20+
{
21+
"section_id": "API4",
22+
"section": "Unrestricted Resource Consumption",
23+
"hyperlink": "https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/",
24+
"cre_ids": ["623-550"]
25+
},
26+
{
27+
"section_id": "API5",
28+
"section": "Broken Function Level Authorization",
29+
"hyperlink": "https://owasp.org/API-Security/editions/2023/en/0xa5-broken-function-level-authorization/",
30+
"cre_ids": ["650-560", "724-770"]
31+
},
32+
{
33+
"section_id": "API6",
34+
"section": "Unrestricted Access to Sensitive Business Flows",
35+
"hyperlink": "https://owasp.org/API-Security/editions/2023/en/0xa6-unrestricted-access-to-sensitive-business-flows/",
36+
"cre_ids": ["534-605", "630-573"]
37+
},
38+
{
39+
"section_id": "API7",
40+
"section": "Server Side Request Forgery",
41+
"hyperlink": "https://owasp.org/API-Security/editions/2023/en/0xa7-server-side-request-forgery/",
42+
"cre_ids": ["028-728", "657-084"]
43+
},
44+
{
45+
"section_id": "API8",
46+
"section": "Security Misconfiguration",
47+
"hyperlink": "https://owasp.org/API-Security/editions/2023/en/0xa8-security-misconfiguration/",
48+
"cre_ids": ["486-813"]
49+
},
50+
{
51+
"section_id": "API9",
52+
"section": "Improper Inventory Management",
53+
"hyperlink": "https://owasp.org/API-Security/editions/2023/en/0xa9-improper-inventory-management/",
54+
"cre_ids": ["162-655", "863-521"]
55+
},
56+
{
57+
"section_id": "API10",
58+
"section": "Unsafe Consumption of APIs",
59+
"hyperlink": "https://owasp.org/API-Security/editions/2023/en/0xaa-unsafe-consumption-of-apis/",
60+
"cre_ids": ["715-223"]
61+
}
62+
]
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
[
2+
{
3+
"section_id": "A01",
4+
"section": "Broken Access Control",
5+
"hyperlink": "https://owasp.org/Top10/2025/A01_2025-Broken_Access_Control/",
6+
"cre_ids": ["117-371", "177-260", "724-770"]
7+
},
8+
{
9+
"section_id": "A02",
10+
"section": "Security Misconfiguration",
11+
"hyperlink": "https://owasp.org/Top10/2025/A02_2025-Security_Misconfiguration/",
12+
"cre_ids": ["486-813"]
13+
},
14+
{
15+
"section_id": "A03",
16+
"section": "Software Supply Chain Failures",
17+
"hyperlink": "https://owasp.org/Top10/2025/A03_2025-Software_Supply_Chain_Failures/",
18+
"cre_ids": ["613-286", "613-287", "715-223", "863-521"]
19+
},
20+
{
21+
"section_id": "A04",
22+
"section": "Cryptographic Failures",
23+
"hyperlink": "https://owasp.org/Top10/2025/A04_2025-Cryptographic_Failures/",
24+
"cre_ids": ["170-772", "227-045"]
25+
},
26+
{
27+
"section_id": "A05",
28+
"section": "Injection",
29+
"hyperlink": "https://owasp.org/Top10/2025/A05_2025-Injection/",
30+
"cre_ids": ["031-447", "064-808", "760-764"]
31+
},
32+
{
33+
"section_id": "A06",
34+
"section": "Insecure Design",
35+
"hyperlink": "https://owasp.org/Top10/2025/A06_2025-Insecure_Design/",
36+
"cre_ids": ["126-668", "155-155"]
37+
},
38+
{
39+
"section_id": "A07",
40+
"section": "Authentication Failures",
41+
"hyperlink": "https://owasp.org/Top10/2025/A07_2025-Authentication_Failures/",
42+
"cre_ids": ["002-630", "177-260", "586-842", "633-428"]
43+
},
44+
{
45+
"section_id": "A08",
46+
"section": "Software or Data Integrity Failures",
47+
"hyperlink": "https://owasp.org/Top10/2025/A08_2025-Software_or_Data_Integrity_Failures/",
48+
"cre_ids": ["613-287", "836-068"]
49+
},
50+
{
51+
"section_id": "A09",
52+
"section": "Security Logging and Alerting Failures",
53+
"hyperlink": "https://owasp.org/Top10/2025/A09_2025-Security_Logging_and_Alerting_Failures/",
54+
"cre_ids": ["067-050", "148-420", "402-706", "843-841"]
55+
},
56+
{
57+
"section_id": "A10",
58+
"section": "Mishandling of Exceptional Conditions",
59+
"hyperlink": "https://owasp.org/Top10/2025/A10_2025-Mishandling_of_Exceptional_Conditions/",
60+
"cre_ids": ["513-183"]
61+
}
62+
]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import json
2+
from pathlib import Path
3+
4+
from application.database import db
5+
from application.defs import cre_defs as defs
6+
from application.prompt_client import prompt_client
7+
from application.utils.external_project_parsers.base_parser_defs import (
8+
ParseResult,
9+
ParserInterface,
10+
)
11+
12+
13+
class OwaspApiTop10_2023(ParserInterface):
14+
name = "OWASP API Security Top 10 2023"
15+
data_file = (
16+
Path(__file__).resolve().parent.parent / "data" / "owasp_api_top10_2023.json"
17+
)
18+
19+
def parse(self, cache: db.Node_collection, ph: prompt_client.PromptHandler):
20+
with self.data_file.open("r", encoding="utf-8") as handle:
21+
raw_entries = json.load(handle)
22+
23+
entries = []
24+
for entry in raw_entries:
25+
standard = defs.Standard(
26+
name=self.name,
27+
sectionID=entry["section_id"],
28+
section=entry["section"],
29+
hyperlink=entry["hyperlink"],
30+
)
31+
for cre_id in entry.get("cre_ids", []):
32+
cres = cache.get_CREs(external_id=cre_id)
33+
if not cres:
34+
continue
35+
standard.add_link(
36+
defs.Link(
37+
ltype=defs.LinkTypes.LinkedTo,
38+
document=cres[0].shallow_copy(),
39+
)
40+
)
41+
entries.append(standard)
42+
43+
return ParseResult(
44+
results={self.name: entries},
45+
calculate_gap_analysis=False,
46+
calculate_embeddings=False,
47+
)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import json
2+
from pathlib import Path
3+
4+
from application.database import db
5+
from application.defs import cre_defs as defs
6+
from application.prompt_client import prompt_client
7+
from application.utils.external_project_parsers.base_parser_defs import (
8+
ParseResult,
9+
ParserInterface,
10+
)
11+
12+
13+
class OwaspTop10_2025(ParserInterface):
14+
name = "OWASP Top 10 2025"
15+
data_file = (
16+
Path(__file__).resolve().parent.parent / "data" / "owasp_top10_2025.json"
17+
)
18+
19+
def parse(self, cache: db.Node_collection, ph: prompt_client.PromptHandler):
20+
with self.data_file.open("r", encoding="utf-8") as handle:
21+
raw_entries = json.load(handle)
22+
23+
entries = []
24+
for entry in raw_entries:
25+
standard = defs.Standard(
26+
name=self.name,
27+
sectionID=entry["section_id"],
28+
section=entry["section"],
29+
hyperlink=entry["hyperlink"],
30+
)
31+
for cre_id in entry.get("cre_ids", []):
32+
cres = cache.get_CREs(external_id=cre_id)
33+
if not cres:
34+
continue
35+
standard.add_link(
36+
defs.Link(
37+
ltype=defs.LinkTypes.LinkedTo,
38+
document=cres[0].shallow_copy(),
39+
)
40+
)
41+
entries.append(standard)
42+
43+
return ParseResult(
44+
results={self.name: entries},
45+
calculate_gap_analysis=False,
46+
calculate_embeddings=False,
47+
)

cre.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,36 @@ def main() -> None:
167167
action="store_true",
168168
help="import owasp secure headers",
169169
)
170+
parser.add_argument(
171+
"--owasp_top10_2025_in",
172+
action="store_true",
173+
help="import OWASP Top 10 2025",
174+
)
175+
parser.add_argument(
176+
"--owasp_api_top10_2023_in",
177+
action="store_true",
178+
help="import OWASP API Security Top 10 2023",
179+
)
180+
parser.add_argument(
181+
"--owasp_kubernetes_top10_2022_in",
182+
action="store_true",
183+
help="import OWASP Kubernetes Top Ten 2022",
184+
)
185+
parser.add_argument(
186+
"--owasp_kubernetes_top10_2025_in",
187+
action="store_true",
188+
help="import OWASP Kubernetes Top Ten 2025 draft",
189+
)
190+
parser.add_argument(
191+
"--owasp_llm_top10_2025_in",
192+
action="store_true",
193+
help="import OWASP Top 10 for LLM and Gen AI Apps 2025",
194+
)
195+
parser.add_argument(
196+
"--owasp_aisvs_in",
197+
action="store_true",
198+
help="import OWASP AI Security Verification Standard (AISVS)",
199+
)
170200
parser.add_argument(
171201
"--pci_dss_3_2_in",
172202
action="store_true",

0 commit comments

Comments
 (0)