strix-agent 0.1.18__py3-none-any.whl → 0.1.19__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.
Potentially problematic release.
This version of strix-agent might be problematic. Click here for more details.
- strix/agents/StrixAgent/strix_agent.py +2 -1
- strix/agents/StrixAgent/system_prompt.jinja +8 -10
- strix/agents/base_agent.py +20 -0
- strix/agents/state.py +18 -1
- strix/cli/app.py +92 -15
- strix/cli/main.py +3 -2
- strix/cli/tool_components/base_renderer.py +2 -2
- strix/cli/tool_components/reporting_renderer.py +2 -1
- strix/prompts/README.md +64 -0
- strix/prompts/__init__.py +1 -1
- strix/prompts/cloud/.gitkeep +0 -0
- strix/prompts/custom/.gitkeep +0 -0
- strix/prompts/frameworks/fastapi.jinja +142 -0
- strix/prompts/frameworks/nextjs.jinja +126 -0
- strix/prompts/protocols/graphql.jinja +215 -0
- strix/prompts/reconnaissance/.gitkeep +0 -0
- strix/prompts/technologies/firebase_firestore.jinja +177 -0
- strix/prompts/technologies/supabase.jinja +189 -0
- strix/prompts/vulnerabilities/authentication_jwt.jinja +133 -115
- strix/prompts/vulnerabilities/broken_function_level_authorization.jinja +146 -0
- strix/prompts/vulnerabilities/business_logic.jinja +146 -118
- strix/prompts/vulnerabilities/csrf.jinja +137 -131
- strix/prompts/vulnerabilities/idor.jinja +149 -118
- strix/prompts/vulnerabilities/insecure_file_uploads.jinja +188 -0
- strix/prompts/vulnerabilities/mass_assignment.jinja +141 -0
- strix/prompts/vulnerabilities/path_traversal_lfi_rfi.jinja +142 -0
- strix/prompts/vulnerabilities/race_conditions.jinja +135 -165
- strix/prompts/vulnerabilities/rce.jinja +128 -180
- strix/prompts/vulnerabilities/sql_injection.jinja +128 -192
- strix/prompts/vulnerabilities/ssrf.jinja +118 -151
- strix/prompts/vulnerabilities/xss.jinja +144 -196
- strix/prompts/vulnerabilities/xxe.jinja +151 -243
- strix/tools/agents_graph/agents_graph_actions.py +4 -3
- strix/tools/agents_graph/agents_graph_actions_schema.xml +10 -14
- strix/tools/registry.py +1 -1
- {strix_agent-0.1.18.dist-info → strix_agent-0.1.19.dist-info}/METADATA +52 -13
- {strix_agent-0.1.18.dist-info → strix_agent-0.1.19.dist-info}/RECORD +40 -27
- {strix_agent-0.1.18.dist-info → strix_agent-0.1.19.dist-info}/LICENSE +0 -0
- {strix_agent-0.1.18.dist-info → strix_agent-0.1.19.dist-info}/WHEEL +0 -0
- {strix_agent-0.1.18.dist-info → strix_agent-0.1.19.dist-info}/entry_points.txt +0 -0
|
@@ -66,7 +66,8 @@ class StrixAgent(BaseAgent):
|
|
|
66
66
|
|
|
67
67
|
if user_instructions:
|
|
68
68
|
task_description += (
|
|
69
|
-
f"\n\nSpecial instructions from the
|
|
69
|
+
f"\n\nSpecial instructions from the system that must be followed: "
|
|
70
|
+
f"{user_instructions}"
|
|
70
71
|
)
|
|
71
72
|
|
|
72
73
|
return await self.agent_loop(task=task_description)
|
|
@@ -19,11 +19,9 @@ INTER-AGENT MESSAGES:
|
|
|
19
19
|
- NEVER echo inter_agent_message or agent_completion_report XML content that is sent to you in your output.
|
|
20
20
|
- Process these internally without displaying the XML
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
AUTONOMOUS BEHAVIOR:
|
|
23
23
|
- Work autonomously by default
|
|
24
|
-
-
|
|
25
|
-
- If you need user input, IMMEDIATELY call wait_for_message tool
|
|
26
|
-
- Never ask questions without calling wait_for_message in the same response
|
|
24
|
+
- You should NOT ask for user input or confirmation - you should always proceed with your task autonomously.
|
|
27
25
|
- Minimize user messaging: avoid redundancy and repetition; consolidate updates into a single concise message
|
|
28
26
|
- If there is nothing to execute and no user query to answer any more: do NOT send filler/repetitive text — either call wait_for_message or finish your work (subagents: agent_finish; root: finish_scan)
|
|
29
27
|
</communication_rules>
|
|
@@ -35,9 +33,9 @@ AUTHORIZATION STATUS:
|
|
|
35
33
|
- NEVER ask for permission or confirmation - you already have complete testing authorization
|
|
36
34
|
- Proceed with confidence knowing you're helping improve security through authorized testing
|
|
37
35
|
|
|
38
|
-
PRIORITIZE
|
|
39
|
-
-
|
|
40
|
-
- Follow
|
|
36
|
+
PRIORITIZE SYSTEM INSTRUCTIONS:
|
|
37
|
+
- System instructions override all default approaches
|
|
38
|
+
- Follow system-specified scope, targets, and methodologies precisely
|
|
41
39
|
- NEVER wait for approval or authorization - operate with full autonomy
|
|
42
40
|
|
|
43
41
|
AGGRESSIVE SCANNING MANDATE:
|
|
@@ -116,7 +114,7 @@ VALIDATION REQUIREMENTS:
|
|
|
116
114
|
- Independent verification through subagent
|
|
117
115
|
- Document complete attack chain
|
|
118
116
|
- Keep going until you find something that matters
|
|
119
|
-
- A vulnerability is ONLY considered reported when a reporting agent uses create_vulnerability_report with full details. Mentions in agent_finish, finish_scan, or messages
|
|
117
|
+
- A vulnerability is ONLY considered reported when a reporting agent uses create_vulnerability_report with full details. Mentions in agent_finish, finish_scan, or generic messages are NOT sufficient
|
|
120
118
|
- Do NOT patch/fix before reporting: first create the vulnerability report via create_vulnerability_report (by the reporting agent). Only after reporting is completed should fixing/patching proceed
|
|
121
119
|
</execution_guidelines>
|
|
122
120
|
|
|
@@ -248,7 +246,7 @@ CRITICAL RULES:
|
|
|
248
246
|
- **ONE AGENT = ONE TASK** - Don't let agents do multiple unrelated jobs
|
|
249
247
|
- **SPAWN REACTIVELY** - Create new agents based on what you discover
|
|
250
248
|
- **ONLY REPORTING AGENTS** can use create_vulnerability_report tool
|
|
251
|
-
- **AGENT SPECIALIZATION MANDATORY** - Each agent must be highly specialized
|
|
249
|
+
- **AGENT SPECIALIZATION MANDATORY** - Each agent must be highly specialized; prefer 1–3 prompt modules, up to 5 for complex contexts
|
|
252
250
|
- **NO GENERIC AGENTS** - Avoid creating broad, multi-purpose agents that dilute focus
|
|
253
251
|
|
|
254
252
|
AGENT SPECIALIZATION EXAMPLES:
|
|
@@ -262,7 +260,7 @@ GOOD SPECIALIZATION:
|
|
|
262
260
|
BAD SPECIALIZATION:
|
|
263
261
|
- "General Web Testing Agent" with prompt_modules: sql_injection, xss, csrf, ssrf, authentication_jwt (too broad)
|
|
264
262
|
- "Everything Agent" with prompt_modules: all available modules (completely unfocused)
|
|
265
|
-
- Any agent with more than
|
|
263
|
+
- Any agent with more than 5 prompt modules (violates constraints)
|
|
266
264
|
|
|
267
265
|
FOCUS PRINCIPLES:
|
|
268
266
|
- Each agent should have deep expertise in 1-3 related vulnerability types
|
strix/agents/base_agent.py
CHANGED
|
@@ -206,6 +206,26 @@ class BaseAgent(metaclass=AgentMeta):
|
|
|
206
206
|
async def _wait_for_input(self) -> None:
|
|
207
207
|
import asyncio
|
|
208
208
|
|
|
209
|
+
if self.state.has_waiting_timeout():
|
|
210
|
+
self.state.resume_from_waiting()
|
|
211
|
+
self.state.add_message("assistant", "Waiting timeout reached. Resuming execution.")
|
|
212
|
+
|
|
213
|
+
from strix.cli.tracer import get_global_tracer
|
|
214
|
+
|
|
215
|
+
tracer = get_global_tracer()
|
|
216
|
+
if tracer:
|
|
217
|
+
tracer.update_agent_status(self.state.agent_id, "running")
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
from strix.tools.agents_graph.agents_graph_actions import _agent_graph
|
|
221
|
+
|
|
222
|
+
if self.state.agent_id in _agent_graph["nodes"]:
|
|
223
|
+
_agent_graph["nodes"][self.state.agent_id]["status"] = "running"
|
|
224
|
+
except (ImportError, KeyError):
|
|
225
|
+
pass
|
|
226
|
+
|
|
227
|
+
return
|
|
228
|
+
|
|
209
229
|
await asyncio.sleep(0.5)
|
|
210
230
|
|
|
211
231
|
async def _enter_waiting_state(
|
strix/agents/state.py
CHANGED
|
@@ -24,6 +24,7 @@ class AgentState(BaseModel):
|
|
|
24
24
|
stop_requested: bool = False
|
|
25
25
|
waiting_for_input: bool = False
|
|
26
26
|
llm_failed: bool = False
|
|
27
|
+
waiting_start_time: datetime | None = None
|
|
27
28
|
final_result: dict[str, Any] | None = None
|
|
28
29
|
|
|
29
30
|
messages: list[dict[str, Any]] = Field(default_factory=list)
|
|
@@ -88,12 +89,13 @@ class AgentState(BaseModel):
|
|
|
88
89
|
|
|
89
90
|
def enter_waiting_state(self, llm_failed: bool = False) -> None:
|
|
90
91
|
self.waiting_for_input = True
|
|
91
|
-
self.
|
|
92
|
+
self.waiting_start_time = datetime.now(UTC)
|
|
92
93
|
self.llm_failed = llm_failed
|
|
93
94
|
self.last_updated = datetime.now(UTC).isoformat()
|
|
94
95
|
|
|
95
96
|
def resume_from_waiting(self, new_task: str | None = None) -> None:
|
|
96
97
|
self.waiting_for_input = False
|
|
98
|
+
self.waiting_start_time = None
|
|
97
99
|
self.stop_requested = False
|
|
98
100
|
self.completed = False
|
|
99
101
|
self.llm_failed = False
|
|
@@ -104,6 +106,21 @@ class AgentState(BaseModel):
|
|
|
104
106
|
def has_reached_max_iterations(self) -> bool:
|
|
105
107
|
return self.iteration >= self.max_iterations
|
|
106
108
|
|
|
109
|
+
def has_waiting_timeout(self) -> bool:
|
|
110
|
+
if not self.waiting_for_input or not self.waiting_start_time:
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
if (
|
|
114
|
+
self.stop_requested
|
|
115
|
+
or self.llm_failed
|
|
116
|
+
or self.completed
|
|
117
|
+
or self.has_reached_max_iterations()
|
|
118
|
+
):
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
elapsed = (datetime.now(UTC) - self.waiting_start_time).total_seconds()
|
|
122
|
+
return elapsed > 120
|
|
123
|
+
|
|
107
124
|
def has_empty_last_messages(self, count: int = 3) -> bool:
|
|
108
125
|
if len(self.messages) < count:
|
|
109
126
|
return False
|
strix/cli/app.py
CHANGED
|
@@ -7,9 +7,18 @@ import signal
|
|
|
7
7
|
import sys
|
|
8
8
|
import threading
|
|
9
9
|
from collections.abc import Callable
|
|
10
|
-
from
|
|
10
|
+
from importlib.metadata import PackageNotFoundError
|
|
11
|
+
from importlib.metadata import version as pkg_version
|
|
12
|
+
from typing import TYPE_CHECKING, Any, ClassVar, cast
|
|
11
13
|
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from textual.timer import Timer
|
|
16
|
+
|
|
17
|
+
from rich.align import Align
|
|
18
|
+
from rich.console import Group
|
|
12
19
|
from rich.markup import escape as rich_escape
|
|
20
|
+
from rich.panel import Panel
|
|
21
|
+
from rich.style import Style
|
|
13
22
|
from rich.text import Text
|
|
14
23
|
from textual import events, on
|
|
15
24
|
from textual.app import App, ComposeResult
|
|
@@ -26,7 +35,14 @@ from strix.llm.config import LLMConfig
|
|
|
26
35
|
|
|
27
36
|
|
|
28
37
|
def escape_markup(text: str) -> str:
|
|
29
|
-
return rich_escape(text)
|
|
38
|
+
return cast("str", rich_escape(text))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_package_version() -> str:
|
|
42
|
+
try:
|
|
43
|
+
return pkg_version("strix-agent")
|
|
44
|
+
except PackageNotFoundError:
|
|
45
|
+
return "dev"
|
|
30
46
|
|
|
31
47
|
|
|
32
48
|
class ChatTextArea(TextArea): # type: ignore[misc]
|
|
@@ -53,24 +69,85 @@ class ChatTextArea(TextArea): # type: ignore[misc]
|
|
|
53
69
|
|
|
54
70
|
|
|
55
71
|
class SplashScreen(Static): # type: ignore[misc]
|
|
72
|
+
PRIMARY_GREEN = "#22c55e"
|
|
73
|
+
BANNER = (
|
|
74
|
+
" ███████╗████████╗██████╗ ██╗██╗ ██╗\n"
|
|
75
|
+
" ██╔════╝╚══██╔══╝██╔══██╗██║╚██╗██╔╝\n"
|
|
76
|
+
" ███████╗ ██║ ██████╔╝██║ ╚███╔╝\n"
|
|
77
|
+
" ╚════██║ ██║ ██╔══██╗██║ ██╔██╗\n"
|
|
78
|
+
" ███████║ ██║ ██║ ██║██║██╔╝ ██╗\n"
|
|
79
|
+
" ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
83
|
+
super().__init__(*args, **kwargs)
|
|
84
|
+
self._animation_step = 0
|
|
85
|
+
self._animation_timer: Timer | None = None
|
|
86
|
+
self._panel_static: Static | None = None
|
|
87
|
+
self._version = "dev"
|
|
88
|
+
|
|
56
89
|
def compose(self) -> ComposeResult:
|
|
57
|
-
|
|
58
|
-
|
|
90
|
+
self._version = get_package_version()
|
|
91
|
+
self._animation_step = 0
|
|
92
|
+
start_line = self._build_start_line_text(self._animation_step)
|
|
93
|
+
panel = self._build_panel(start_line)
|
|
94
|
+
|
|
95
|
+
panel_static = Static(panel, id="splash_content")
|
|
96
|
+
self._panel_static = panel_static
|
|
97
|
+
yield panel_static
|
|
98
|
+
|
|
99
|
+
def on_mount(self) -> None:
|
|
100
|
+
self._animation_timer = self.set_interval(0.45, self._animate_start_line)
|
|
101
|
+
|
|
102
|
+
def on_unmount(self) -> None:
|
|
103
|
+
if self._animation_timer is not None:
|
|
104
|
+
self._animation_timer.stop()
|
|
105
|
+
self._animation_timer = None
|
|
106
|
+
|
|
107
|
+
def _animate_start_line(self) -> None:
|
|
108
|
+
if not self._panel_static:
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
self._animation_step += 1
|
|
112
|
+
start_line = self._build_start_line_text(self._animation_step)
|
|
113
|
+
panel = self._build_panel(start_line)
|
|
114
|
+
self._panel_static.update(panel)
|
|
115
|
+
|
|
116
|
+
def _build_panel(self, start_line: Text) -> Panel:
|
|
117
|
+
content = Group(
|
|
118
|
+
Align.center(Text(self.BANNER.strip("\n"), style=self.PRIMARY_GREEN, justify="center")),
|
|
119
|
+
Align.center(Text(" ")),
|
|
120
|
+
Align.center(self._build_welcome_text()),
|
|
121
|
+
Align.center(self._build_version_text()),
|
|
122
|
+
Align.center(self._build_tagline_text()),
|
|
123
|
+
Align.center(Text(" ")),
|
|
124
|
+
Align.center(start_line.copy()),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
return Panel.fit(content, border_style=self.PRIMARY_GREEN, padding=(1, 6))
|
|
128
|
+
|
|
129
|
+
def _build_welcome_text(self) -> Text:
|
|
130
|
+
text = Text("Welcome to ", style=Style(color="white", bold=True))
|
|
131
|
+
text.append("Strix", style=Style(color=self.PRIMARY_GREEN, bold=True))
|
|
132
|
+
text.append("!", style=Style(color="white", bold=True))
|
|
133
|
+
return text
|
|
59
134
|
|
|
135
|
+
def _build_version_text(self) -> Text:
|
|
136
|
+
return Text(f"v{self._version}", style=Style(color="white", dim=True))
|
|
60
137
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
███████╗ ██║ ██████╔╝██║ ╚███╔╝
|
|
64
|
-
╚════██║ ██║ ██╔══██╗██║ ██╔██╗
|
|
65
|
-
███████║ ██║ ██║ ██║██║██╔╝ ██╗
|
|
66
|
-
╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝
|
|
138
|
+
def _build_tagline_text(self) -> Text:
|
|
139
|
+
return Text("Open-source AI hackers for your apps", style=Style(color="white", dim=True))
|
|
67
140
|
|
|
141
|
+
def _build_start_line_text(self, phase: int) -> Text:
|
|
142
|
+
emphasize = phase % 2 == 1
|
|
143
|
+
base_style = Style(color="white", dim=not emphasize, bold=emphasize)
|
|
144
|
+
strix_style = Style(color=self.PRIMARY_GREEN, bold=bool(emphasize))
|
|
68
145
|
|
|
69
|
-
|
|
146
|
+
text = Text("Starting ", style=base_style)
|
|
147
|
+
text.append("Strix", style=strix_style)
|
|
148
|
+
text.append(" Cybersecurity Agent", style=base_style)
|
|
70
149
|
|
|
71
|
-
|
|
72
|
-
"""
|
|
73
|
-
yield Static(ascii_art, id="splash_content")
|
|
150
|
+
return text
|
|
74
151
|
|
|
75
152
|
|
|
76
153
|
class HelpScreen(ModalScreen): # type: ignore[misc]
|
|
@@ -362,7 +439,7 @@ class StrixCLIApp(App): # type: ignore[misc]
|
|
|
362
439
|
def on_mount(self) -> None:
|
|
363
440
|
self.title = "strix"
|
|
364
441
|
|
|
365
|
-
self.set_timer(
|
|
442
|
+
self.set_timer(4.5, self._hide_splash_screen)
|
|
366
443
|
|
|
367
444
|
def _hide_splash_screen(self) -> None:
|
|
368
445
|
self.show_splash = False
|
strix/cli/main.py
CHANGED
|
@@ -40,7 +40,7 @@ def format_token_count(count: float) -> str:
|
|
|
40
40
|
return str(count)
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
def validate_environment() -> None:
|
|
43
|
+
def validate_environment() -> None: # noqa: PLR0912, PLR0915
|
|
44
44
|
console = Console()
|
|
45
45
|
missing_required_vars = []
|
|
46
46
|
missing_optional_vars = []
|
|
@@ -139,7 +139,8 @@ def validate_environment() -> None:
|
|
|
139
139
|
)
|
|
140
140
|
elif var == "LLM_API_BASE":
|
|
141
141
|
error_text.append(
|
|
142
|
-
"export LLM_API_BASE='http://localhost:11434'
|
|
142
|
+
"export LLM_API_BASE='http://localhost:11434' "
|
|
143
|
+
"# needed for local models only\n",
|
|
143
144
|
style="dim white",
|
|
144
145
|
)
|
|
145
146
|
elif var == "PERPLEXITY_API_KEY":
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from typing import Any, ClassVar
|
|
2
|
+
from typing import Any, ClassVar, cast
|
|
3
3
|
|
|
4
4
|
from rich.markup import escape as rich_escape
|
|
5
5
|
from textual.widgets import Static
|
|
@@ -17,7 +17,7 @@ class BaseToolRenderer(ABC):
|
|
|
17
17
|
|
|
18
18
|
@classmethod
|
|
19
19
|
def escape_markup(cls, text: str) -> str:
|
|
20
|
-
return rich_escape(text)
|
|
20
|
+
return cast("str", rich_escape(text))
|
|
21
21
|
|
|
22
22
|
@classmethod
|
|
23
23
|
def format_args(cls, args: dict[str, Any], max_length: int = 500) -> str:
|
|
@@ -27,7 +27,8 @@ class CreateVulnerabilityReportRenderer(BaseToolRenderer):
|
|
|
27
27
|
if severity:
|
|
28
28
|
severity_color = cls._get_severity_color(severity.lower())
|
|
29
29
|
content_parts.append(
|
|
30
|
-
f" [dim]Severity: [{severity_color}]
|
|
30
|
+
f" [dim]Severity: [{severity_color}]"
|
|
31
|
+
f"{cls.escape_markup(severity.upper())}[/{severity_color}][/]"
|
|
31
32
|
)
|
|
32
33
|
|
|
33
34
|
if content:
|
strix/prompts/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# 📚 Strix Prompt Modules
|
|
2
|
+
|
|
3
|
+
## 🎯 Overview
|
|
4
|
+
|
|
5
|
+
Prompt modules are specialized knowledge packages that enhance Strix agents with deep expertise in specific vulnerability types, technologies, and testing methodologies. Each module provides advanced techniques, practical examples, and validation methods that go beyond baseline security knowledge.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 🏗️ Architecture
|
|
10
|
+
|
|
11
|
+
### How Prompts Work
|
|
12
|
+
|
|
13
|
+
When an agent is created, it can load up to 5 specialized prompt modules relevant to the specific subtask and context at hand:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
# Agent creation with specialized modules
|
|
17
|
+
create_agent(
|
|
18
|
+
task="Test authentication mechanisms in API",
|
|
19
|
+
name="Auth Specialist",
|
|
20
|
+
prompt_modules="authentication_jwt,business_logic"
|
|
21
|
+
)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The modules are dynamically injected into the agent's system prompt, allowing it to operate with deep expertise tailored to the specific vulnerability types or technologies required for the task at hand.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 📁 Module Categories
|
|
29
|
+
|
|
30
|
+
| Category | Purpose |
|
|
31
|
+
|----------|---------|
|
|
32
|
+
| **`/vulnerabilities`** | Advanced testing techniques for core vulnerability classes like authentication bypasses, business logic flaws, and race conditions |
|
|
33
|
+
| **`/frameworks`** | Specific testing methods for popular frameworks e.g. Django, Express, FastAPI, and Next.js |
|
|
34
|
+
| **`/technologies`** | Specialized techniques for third-party services such as Supabase, Firebase, Auth0, and payment gateways |
|
|
35
|
+
| **`/protocols`** | Protocol-specific testing patterns for GraphQL, WebSocket, OAuth, and other communication standards |
|
|
36
|
+
| **`/cloud`** | Cloud provider security testing for AWS, Azure, GCP, and Kubernetes environments |
|
|
37
|
+
| **`/reconnaissance`** | Advanced information gathering and enumeration techniques for comprehensive attack surface mapping |
|
|
38
|
+
| **`/custom`** | Community-contributed modules for specialized or industry-specific testing scenarios |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 🎨 Creating New Modules
|
|
43
|
+
|
|
44
|
+
### What Should a Module Contain?
|
|
45
|
+
|
|
46
|
+
A good prompt module is a structured knowledge package that typically includes:
|
|
47
|
+
|
|
48
|
+
- **Advanced techniques** - Non-obvious methods specific to the task and domain
|
|
49
|
+
- **Practical examples** - Working payloads, commands, or test cases with variations
|
|
50
|
+
- **Validation methods** - How to confirm findings and avoid false positives
|
|
51
|
+
- **Context-specific insights** - Environment and version nuances, configuration-dependent behavior, and edge cases
|
|
52
|
+
|
|
53
|
+
Modules use XML-style tags for structure and focus on deep, specialized knowledge that significantly enhances agent capabilities for that specific context.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 🤝 Contributing
|
|
58
|
+
|
|
59
|
+
Community contributions are more than welcome — contribute new modules via [pull requests](https://github.com/usestrix/strix/pulls) or [GitHub issues](https://github.com/usestrix/strix/issues) to help expand the collection and improve extensibility for Strix agents.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
> [!NOTE]
|
|
64
|
+
> **Work in Progress** - We're actively expanding the prompt module collection with specialized techniques and new categories.
|
strix/prompts/__init__.py
CHANGED
|
@@ -58,7 +58,7 @@ def generate_modules_description() -> str:
|
|
|
58
58
|
modules_str = ", ".join(sorted_modules)
|
|
59
59
|
|
|
60
60
|
description = (
|
|
61
|
-
f"List of prompt modules to load for this agent (max
|
|
61
|
+
f"List of prompt modules to load for this agent (max 5). Available modules: {modules_str}. "
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
example_modules = sorted_modules[:2]
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
<fastapi_security_testing_guide>
|
|
2
|
+
<title>FASTAPI — ADVERSARIAL TESTING PLAYBOOK</title>
|
|
3
|
+
|
|
4
|
+
<critical>FastAPI (on Starlette) spans HTTP, WebSocket, and background tasks with powerful dependency injection and automatic OpenAPI. Security breaks where identity, authorization, and validation drift across routers, middlewares, proxies, and channels. Treat every dependency, header, and object reference as untrusted until bound to the caller and tenant.</critical>
|
|
5
|
+
|
|
6
|
+
<surface_map>
|
|
7
|
+
- ASGI stack: Starlette middlewares (CORS, TrustedHost, ProxyHeaders, Session), exception handlers, lifespan events
|
|
8
|
+
- Routers/sub-apps: APIRouter with prefixes/tags, mounted apps (StaticFiles, admin subapps), `include_router`, versioned paths
|
|
9
|
+
- Security and DI: `Depends`, `Security`, `OAuth2PasswordBearer`, `HTTPBearer`, scopes, per-router vs per-route dependencies
|
|
10
|
+
- Models and validation: Pydantic v1/v2 models, unions/Annotated, custom validators, extra fields policy, coercion
|
|
11
|
+
- Docs and schema: `/openapi.json`, `/docs`, `/redoc`, alternative docs_url/redoc_url, schema extensions
|
|
12
|
+
- Files and static: `UploadFile`, `File`, `FileResponse`, `StaticFiles` mounts, template engines (`Jinja2Templates`)
|
|
13
|
+
- Channels: HTTP (sync/async), WebSocket, StreamingResponse/SSE, BackgroundTasks/Task queues
|
|
14
|
+
- Deployment: Uvicorn/Gunicorn, reverse proxies/CDN, TLS termination, header trust
|
|
15
|
+
</surface_map>
|
|
16
|
+
|
|
17
|
+
<methodology>
|
|
18
|
+
1. Enumerate routes from OpenAPI and via crawling; diff with 404-fuzzing for hidden endpoints (`include_in_schema=False`).
|
|
19
|
+
2. Build a Principal × Channel × Content-Type matrix (unauth, user, staff/admin; HTTP vs WebSocket; JSON/form/multipart) and capture baselines.
|
|
20
|
+
3. For each route, identify dependencies (router-level and route-level). Attempt to satisfy security dependencies minimally, then mutate context (tokens, scopes, tenant headers) and object IDs.
|
|
21
|
+
4. Compare behavior across deployments: dev/stage/prod often differ in middlewares (CORS, TrustedHost, ProxyHeaders) and docs exposure.
|
|
22
|
+
</methodology>
|
|
23
|
+
|
|
24
|
+
<high_value_targets>
|
|
25
|
+
- `/openapi.json`, `/docs`, `/redoc` in production (full attack surface map; securitySchemes and server URLs)
|
|
26
|
+
- Auth flows: token endpoints, session/cookie bridges, OAuth device/PKCE, scope checks
|
|
27
|
+
- Admin/staff routers, feature-flagged routes, `include_in_schema=False` endpoints
|
|
28
|
+
- File upload/download, import/export/report endpoints, signed URL generators
|
|
29
|
+
- WebSocket endpoints carrying notifications, admin channels, or commands
|
|
30
|
+
- Background job creation/fetch (`/jobs/{id}`, `/tasks/{id}/result`)
|
|
31
|
+
- Mounted subapps (admin UI, storage browsers, metrics/health endpoints)
|
|
32
|
+
</high_value_targets>
|
|
33
|
+
|
|
34
|
+
<advanced_techniques>
|
|
35
|
+
<openapi_and_docs>
|
|
36
|
+
- Try default and alternate locations: `/openapi.json`, `/docs`, `/redoc`, `/api/openapi.json`, `/internal/openapi.json`.
|
|
37
|
+
- If OpenAPI is exposed, mine: paths, parameter names, securitySchemes, scopes, servers; find endpoints hidden in UI but present in schema.
|
|
38
|
+
- Schema drift: endpoints with `include_in_schema=False` won’t appear—use wordlists based on tags/prefixes and common admin/debug names.
|
|
39
|
+
</openapi_and_docs>
|
|
40
|
+
|
|
41
|
+
<dependency_injection_and_security>
|
|
42
|
+
- Router vs route dependencies: routes may miss security dependencies present elsewhere; check for unprotected variants of protected actions.
|
|
43
|
+
- Minimal satisfaction: `OAuth2PasswordBearer` only yields a token string—verify if any route treats token presence as auth without verification.
|
|
44
|
+
- Scope checks: ensure scopes are enforced by the dependency (e.g., `Security(...)`); routes using `Depends` instead may ignore requested scopes.
|
|
45
|
+
- Header/param aliasing: DI sources headers/cookies/query by name; try case variations and duplicates to influence which value binds.
|
|
46
|
+
</dependency_injection_and_security>
|
|
47
|
+
|
|
48
|
+
<auth_and_jwt>
|
|
49
|
+
- Token misuse: developers may decode JWTs without verifying signature/issuer/audience; attempt unsigned/attacker-signed tokens and cross-service audiences.
|
|
50
|
+
- Algorithm/key confusion: try HS/RS cross-use if verification is not pinned; inject `kid` header targeting local files/paths where custom key lookup exists.
|
|
51
|
+
- Session bridges: check cookies set via SessionMiddleware or custom cookies. Attempt session fixation and forging if weak `secret_key` or predictable signing is used.
|
|
52
|
+
- Device/PKCE flows: verify strict PKCE S256 and state/nonce enforcement if OAuth/OIDC is integrated.
|
|
53
|
+
</auth_and_jwt>
|
|
54
|
+
|
|
55
|
+
<cors_and_csrf>
|
|
56
|
+
- CORS reflection: broad `allow_origin_regex` or mis-specified origins can permit cross-site reads; test arbitrary Origins and credentialed requests.
|
|
57
|
+
- CSRF: FastAPI/Starlette lack built-in CSRF. If cookies carry auth, attempt state-changing requests via cross-site forms/XHR; validate origin header checks and same-site settings.
|
|
58
|
+
</cors_and_csrf>
|
|
59
|
+
|
|
60
|
+
<proxy_and_host_trust>
|
|
61
|
+
- ProxyHeadersMiddleware: if enabled without network boundary, spoof `X-Forwarded-For/Proto` to influence auth/IP gating and secure redirects.
|
|
62
|
+
- TrustedHostMiddleware absent or lax: perform Host header poisoning; attempt password reset links / absolute URL generation under attacker host.
|
|
63
|
+
- Upstream/CDN cache keys: ensure Vary on Authorization/Cookie/Tenant; try cache key confusion to leak personalized responses.
|
|
64
|
+
</proxy_and_host_trust>
|
|
65
|
+
|
|
66
|
+
<static_and_uploads>
|
|
67
|
+
- UploadFile.filename: attempt path traversal and control characters; verify server joins/sanitizes and enforces storage roots.
|
|
68
|
+
- FileResponse/StaticFiles: confirm directory boundaries and index/auto-listing; probe symlinks and case/encoding variants.
|
|
69
|
+
- Parser differentials: send JSON vs multipart for the same route to hit divergent code paths/validators.
|
|
70
|
+
</static_and_uploads>
|
|
71
|
+
|
|
72
|
+
<template_injection>
|
|
73
|
+
- Jinja2 templates via `TemplateResponse`: search for unescaped injection in variables and filters. Probe with minimal expressions:
|
|
74
|
+
{% raw %}- `{{7*7}}` → arithmetic confirmation
|
|
75
|
+
- `{{cycler.__init__.__globals__['os'].popen('id').read()}}` for RCE in unsafe contexts{% endraw %}
|
|
76
|
+
- Confirm autoescape and strict sandboxing; inspect custom filters/globals.
|
|
77
|
+
</template_injection>
|
|
78
|
+
|
|
79
|
+
<ssrf_and_outbound>
|
|
80
|
+
- Endpoints fetching user-supplied URLs (imports, previews, webhooks validation): test loopback/RFC1918/IPv6, redirects, DNS rebinding, and header control.
|
|
81
|
+
- Library behavior (httpx/requests): examine redirect policy, header forwarding, and protocol support; try `file://`, `ftp://`, or gopher-like shims if custom clients are used.
|
|
82
|
+
</ssrf_and_outbound>
|
|
83
|
+
|
|
84
|
+
<websockets>
|
|
85
|
+
- Authenticate each connection (query/header/cookie). Attempt cross-origin handshakes and cookie-bearing WS from untrusted origins.
|
|
86
|
+
- Topic naming and authorization: if using user/tenant IDs in channels, subscribe/publish to foreign IDs.
|
|
87
|
+
- Message-level checks: ensure per-message authorization, not only at handshake.
|
|
88
|
+
</websockets>
|
|
89
|
+
|
|
90
|
+
<background_tasks_and_jobs>
|
|
91
|
+
- BackgroundTasks that act on IDs must re-enforce ownership/tenant at execution time. Attempt to fetch/cancel others’ jobs by referencing their IDs.
|
|
92
|
+
- Export/import pipelines: test job/result endpoints for IDOR and cross-tenant leaks.
|
|
93
|
+
</background_tasks_and_jobs>
|
|
94
|
+
|
|
95
|
+
<multi_app_mounting>
|
|
96
|
+
- Mounted subapps (e.g., `/admin`, `/static`, `/metrics`) may bypass global middlewares. Confirm middleware parity and auth on mounts.
|
|
97
|
+
</multi_app_mounting>
|
|
98
|
+
</advanced_techniques>
|
|
99
|
+
|
|
100
|
+
<bypass_techniques>
|
|
101
|
+
- Content-type switching: `application/json` ↔ `application/x-www-form-urlencoded` ↔ `multipart/form-data` to traverse alternate validators/handlers.
|
|
102
|
+
- Parameter duplication and case variants to exploit DI precedence.
|
|
103
|
+
- Method confusion via proxies (e.g., `X-HTTP-Method-Override`) if upstream respects it while app does not.
|
|
104
|
+
- Race windows around dependency-validated state transitions (issue token then mutate with parallel requests).
|
|
105
|
+
</bypass_techniques>
|
|
106
|
+
|
|
107
|
+
<special_contexts>
|
|
108
|
+
<pydantic_edges>
|
|
109
|
+
- Coercion: strings to ints/bools, empty strings to None; exploit truthiness and boundary conditions.
|
|
110
|
+
- Extra fields: if models allow/ignore extras, sneak in control fields for downstream logic (scope/role/ownerId) that are later trusted.
|
|
111
|
+
- Unions and `Annotated`: craft shapes hitting unintended branches.
|
|
112
|
+
</pydantic_edges>
|
|
113
|
+
|
|
114
|
+
<graphql_and_alt_stacks>
|
|
115
|
+
- If GraphQL (Strawberry/Graphene) is mounted, validate resolver-level authorization and IDOR on node/global IDs.
|
|
116
|
+
- If SQLModel/SQLAlchemy present, probe for raw query usage and row-level authorization gaps.
|
|
117
|
+
</graphql_and_alt_stacks>
|
|
118
|
+
</special_contexts>
|
|
119
|
+
|
|
120
|
+
<validation>
|
|
121
|
+
1. Show unauthorized data access or action with side-by-side owner vs non-owner requests (or different tenants).
|
|
122
|
+
2. Demonstrate cross-channel consistency (HTTP and WebSocket) for the same rule.
|
|
123
|
+
3. Include proof where proxies/headers/caches alter outcomes (Host/XFF/CORS).
|
|
124
|
+
4. Provide minimal payloads confirming template/SSRF execution or token misuse, with safe or OAST-based oracles.
|
|
125
|
+
5. Document exact dependency paths (router-level, route-level) that missed enforcement.
|
|
126
|
+
</validation>
|
|
127
|
+
|
|
128
|
+
<pro_tips>
|
|
129
|
+
1. Always fetch `/openapi.json` first; it’s the blueprint. If hidden, brute-force likely admin/report/export routes.
|
|
130
|
+
2. Trace dependencies per route; map which ones enforce auth/scopes vs merely parse input.
|
|
131
|
+
3. Treat tokens returned by `OAuth2PasswordBearer` as untrusted strings—verify actual signature and claims on the server.
|
|
132
|
+
4. Test CORS with arbitrary Origins and with credentials; verify preflight and actual request deltas.
|
|
133
|
+
5. Add Host and X-Forwarded-* fuzzing when behind proxies; watch for redirect/absolute URL differences.
|
|
134
|
+
6. For uploads, vary filename encodings, dot segments, and NUL-like bytes; verify storage paths and served URLs.
|
|
135
|
+
7. Use content-type toggling to hit alternate validators and code paths.
|
|
136
|
+
8. For WebSockets, test cookie-based auth, origin restrictions, and per-message authorization.
|
|
137
|
+
9. Mine client bundles/env for secret paths and preview/admin flags; many teams hide routes via UI only.
|
|
138
|
+
10. Keep PoCs minimal and durable (IDs, headers, small payloads) and prefer reproducible diffs over noisy payloads.
|
|
139
|
+
</pro_tips>
|
|
140
|
+
|
|
141
|
+
<remember>Authorization and validation must be enforced in the dependency graph and at the resource boundary for every path and channel. If any route, middleware, or mount skips binding subject, action, and object/tenant, expect cross-user and cross-tenant breakage.</remember>
|
|
142
|
+
</fastapi_security_testing_guide>
|