Skip to content

Commit f496836

Browse files
committed
Enhance AI validation logic and add new test case for API10
- Updated the validation logic in `validate.py` to include regex checks for specific API keywords, improving detection accuracy. - Added a new test case in `test_ai_modules.py` to ensure that the API10 scenario does not trigger false positives for API1, validating the robustness of the classification process.
1 parent ab7aacb commit f496836

2 files changed

Lines changed: 49 additions & 7 deletions

File tree

src/secnodeapi/ai/validate.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import asyncio
66
import json
7+
import re
78
from typing import List, Optional, Tuple
89

910
import structlog
@@ -43,15 +44,18 @@ def _deterministic_validate_result(result: TestResult) -> Optional[Finding]:
4344
req_snippet = f"{result.test_case.method} {result.request_url}"
4445
resp_snippet = result.response_body[:500]
4546

46-
bola_like = any(
47-
keyword in category_text
48-
for keyword in ("bola", "idor", "api1", "bfla", "api5", "broken object", "broken function")
47+
bola_like = (
48+
any(keyword in category_text for keyword in ("bola", "idor", "bfla", "broken object", "broken function"))
49+
or re.search(r"\bapi1\b", category_text) is not None
50+
or re.search(r"\bapi5\b", category_text) is not None
4951
)
50-
mass_assignment_like = any(
51-
keyword in category_text for keyword in ("mass assignment", "bopla", "api3")
52+
mass_assignment_like = (
53+
any(keyword in category_text for keyword in ("mass assignment", "bopla"))
54+
or re.search(r"\bapi3\b", category_text) is not None
5255
)
53-
rate_limit_like = any(
54-
keyword in category_text for keyword in ("rate limit", "ratelimit", "api4")
56+
rate_limit_like = (
57+
any(keyword in category_text for keyword in ("rate limit", "ratelimit"))
58+
or re.search(r"\bapi4\b", category_text) is not None
5559
)
5660

5761
if bola_like and is_2xx:

tests/test_ai_modules.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,41 @@ async def fake_call_llm(*args, **kwargs):
152152
assert confirmed == []
153153
assert len(suspected) == 1
154154
assert suspected[0].validation_source == "ai-suspected"
155+
156+
157+
@pytest.mark.asyncio
158+
async def test_classify_findings_api10_does_not_trigger_api1_deterministic(monkeypatch) -> None:
159+
test_case = TestCase(
160+
id="T-API10-1",
161+
name="Unsafe consumption scenario",
162+
description="Downstream third-party API behavior",
163+
owasp_category="API10: Unsafe Consumption of APIs",
164+
endpoint="/integrations/provider",
165+
method="GET",
166+
)
167+
result = TestResult(
168+
test_case=test_case,
169+
status_code=200,
170+
response_body='{"status":"ok"}',
171+
response_headers={},
172+
request_url="https://api.example.com/integrations/provider",
173+
request_headers={},
174+
request_body=None,
175+
response_time_ms=15.0,
176+
)
177+
called = False
178+
179+
async def fake_call_llm(*args, **kwargs):
180+
nonlocal called
181+
called = True
182+
return (
183+
'{"analysis":"not vulnerable","is_vulnerable":false,"cvss_score":0.0,'
184+
'"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N",'
185+
'"description":"no issue","remediation":"none","confidence":0.9}'
186+
)
187+
188+
monkeypatch.setattr("secnodeapi.ai.validate.call_llm", fake_call_llm)
189+
confirmed, suspected = await classify_findings([result])
190+
assert called is True
191+
assert confirmed == []
192+
assert suspected == []

0 commit comments

Comments
 (0)