Skip to content

Commit b5dcd68

Browse files
committed
fix(security): sanitize report output, prevent prompt injection, remove dead code
- Sanitize markdown report content to prevent stored XSS - Sanitize AI prompt inputs to prevent prompt injection - Remove unused ScanOrchestrator instantiation in commands.py - Remove unused _agent_instances dict in scheduler.py - Fix asyncio.run() to handle already-running event loop
1 parent 10fbf0d commit b5dcd68

4 files changed

Lines changed: 29 additions & 16 deletions

File tree

bugfinder/ai/prompts.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
from __future__ import annotations
22

3+
import re
4+
35
"""
46
Prompt templates for AI interactions.
57
68
Each prompt is a function that takes context and returns a (system, user) tuple.
79
"""
810

911

12+
def _sanitize_prompt(text: str, max_length: int = 1000) -> str:
13+
cleaned = re.sub(r"[<>{}\\;]", "", text)
14+
return cleaned[:max_length]
15+
16+
1017
SYSTEM_PLANNER = """You are BugFinder's AI security assessment planner.
1118
Your role is to analyze the target, review current findings, and decide the next best step.
1219
Only recommend steps that are legal and within scope.
@@ -30,19 +37,19 @@
3037

3138
def planner_prompt(target_type: str, target: str, graph_summary: str) -> tuple[str, str]:
3239
system = SYSTEM_PLANNER
33-
user = f"""Target Type: {target_type}
34-
Target: {target}
35-
Current Knowledge Graph: {graph_summary}
40+
user = f"""Target Type: {_sanitize_prompt(target_type)}
41+
Target: {_sanitize_prompt(target)}
42+
Current Knowledge Graph: {_sanitize_prompt(graph_summary)}
3643
3744
What should I test next? Respond in JSON format."""
3845
return system, user
3946

4047

4148
def explainer_prompt(finding_title: str, description: str, evidence: str) -> tuple[str, str]:
4249
system = SYSTEM_EXPLAINER
43-
user = f"""Finding: {finding_title}
44-
Description: {description}
45-
Evidence: {evidence}
50+
user = f"""Finding: {_sanitize_prompt(finding_title)}
51+
Description: {_sanitize_prompt(description)}
52+
Evidence: {_sanitize_prompt(evidence)}
4653
4754
Explain this finding in simple terms. Include:
4855
1. What is this vulnerability?
@@ -55,9 +62,9 @@ def explainer_prompt(finding_title: str, description: str, evidence: str) -> tup
5562

5663
def report_prompt(target: str, findings_summary: str, graph_summary: str) -> tuple[str, str]:
5764
system = SYSTEM_REPORT
58-
user = f"""Target: {target}
59-
Findings: {findings_summary}
60-
Asset Graph: {graph_summary}
65+
user = f"""Target: {_sanitize_prompt(target)}
66+
Findings: {_sanitize_prompt(findings_summary)}
67+
Asset Graph: {_sanitize_prompt(graph_summary)}
6168
6269
Generate a professional security assessment report."""
6370
return system, user

bugfinder/cli/commands.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@ def _run_scan(
152152
output: str | None = None,
153153
report_format: str = "markdown",
154154
) -> None:
155-
asyncio.run(_async_scan(target, profile, expert, output, report_format))
155+
try:
156+
loop = asyncio.get_running_loop()
157+
loop.create_task(_async_scan(target, profile, expert, output, report_format))
158+
except RuntimeError:
159+
asyncio.run(_async_scan(target, profile, expert, output, report_format))
156160

157161

158162
async def _async_scan(
@@ -164,7 +168,6 @@ async def _async_scan(
164168
) -> None:
165169
from bugfinder.database.repository import Repository
166170
from bugfinder.database.session import async_session_factory
167-
from bugfinder.engine.scheduler import ScanOrchestrator
168171
from bugfinder.knowledge_graph.graph import KnowledgeGraph
169172
from bugfinder.reporting.markdown import generate_markdown_report
170173

@@ -193,8 +196,6 @@ async def _async_scan(
193196
except Exception:
194197
pass
195198

196-
ScanOrchestrator(kg, ai_client, repo)
197-
198199
ttype = target.type.value
199200

200201
rprint(f"\n[bold]Scan Plan[/bold] ({target.type.value})")

bugfinder/engine/scheduler.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ def __init__(
5353
self.repo = repository
5454
self.progress = ScanProgress(target="", target_type="")
5555
self._start_time: float = 0.0
56-
self._agent_instances: dict[str, Any] = {}
5756

5857
def log(self, message: str) -> None:
5958
self.progress.log.append(message)

bugfinder/reporting/markdown.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import re
34
from datetime import UTC, datetime
45
from typing import Any
56

@@ -15,6 +16,11 @@
1516
}
1617

1718

19+
def _sanitize_md(text: str) -> str:
20+
text = re.sub(r"[`*_{}[\]()#+\-.!|~]", "", text)
21+
return text[:500]
22+
23+
1824
def generate_markdown_report(
1925
target: str,
2026
target_type: str,
@@ -89,7 +95,7 @@ def generate_markdown_report(
8995
for i, f in enumerate(sorted_findings, 1):
9096
sev = f.get("severity", "info")
9197
icon = SEVERITY_ICONS.get(sev, "")
92-
title = f.get("title", "Untitled Finding")
98+
title = _sanitize_md(f.get("title", "Untitled Finding"))
9399
lines.append(f"### {i}. {icon} {title}")
94100
lines.append("")
95101
lines.append(f"- **Severity**: {sev.upper()}")
@@ -105,7 +111,7 @@ def generate_markdown_report(
105111

106112
lines.append("")
107113

108-
desc = f.get("description", "")
114+
desc = _sanitize_md(f.get("description", ""))
109115
if desc:
110116
lines.append(f"**Description**: {desc}")
111117
lines.append("")

0 commit comments

Comments
 (0)