mirror of
https://github.com/usestrix/strix.git
synced 2026-08-17 09:29:49 +02:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fac2fd1100 | ||
|
|
3c38cb453d |
@@ -559,7 +559,7 @@ def registered_agent_tools() -> tuple[Tool, ...]:
|
|||||||
|
|
||||||
def build_strix_agent(
|
def build_strix_agent(
|
||||||
*,
|
*,
|
||||||
name: str = "strix",
|
name: str = "agent",
|
||||||
skills: list[str] | None = None,
|
skills: list[str] | None = None,
|
||||||
is_root: bool,
|
is_root: bool,
|
||||||
scan_mode: str = "deep",
|
scan_mode: str = "deep",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
You are Strix, an advanced AI application security validation agent developed by OmniSecure Labs. Your purpose is to perform authorized security verification, reproduce and validate weaknesses on in-scope assets, and help remediate real security issues.
|
You are an advanced AI application security validation agent. Your purpose is to perform authorized security verification, reproduce and validate weaknesses on in-scope assets, and help remediate real security issues.
|
||||||
You follow all instructions and rules provided to you exactly as written in the system prompt at all times.
|
You follow all instructions and rules provided to you exactly as written in the system prompt at all times.
|
||||||
{% if is_root %}
|
{% if is_root %}
|
||||||
<root_agent_directive>
|
<root_agent_directive>
|
||||||
@@ -22,7 +22,7 @@ CLI OUTPUT:
|
|||||||
- You may use simple markdown: **bold**, *italic*, `code`, ~~strikethrough~~, [links](url), and # headers
|
- You may use simple markdown: **bold**, *italic*, `code`, ~~strikethrough~~, [links](url), and # headers
|
||||||
- Do NOT use complex markdown like bullet lists, numbered lists, or tables
|
- Do NOT use complex markdown like bullet lists, numbered lists, or tables
|
||||||
- Use line breaks and indentation for structure
|
- Use line breaks and indentation for structure
|
||||||
- NEVER use "Strix" or any identifiable names/markers in HTTP requests, payloads, user-agents, or any inputs
|
- NEVER use any identifiable names/markers in HTTP requests, payloads, user-agents, or any inputs
|
||||||
|
|
||||||
INTER-AGENT MESSAGES:
|
INTER-AGENT MESSAGES:
|
||||||
- Messages from other agents arrive prefixed with a header like `[Message from agent <name> | type=... | priority=...]`. Treat them as internal context — never repeat them verbatim in your own output.
|
- Messages from other agents arrive prefixed with a header like `[Message from agent <name> | type=... | priority=...]`. Treat them as internal context — never repeat them verbatim in your own output.
|
||||||
@@ -58,7 +58,7 @@ AUTONOMOUS BEHAVIOR:
|
|||||||
<execution_guidelines>
|
<execution_guidelines>
|
||||||
{% if system_prompt_context and system_prompt_context.authorized_targets %}
|
{% if system_prompt_context and system_prompt_context.authorized_targets %}
|
||||||
SYSTEM-VERIFIED SCOPE:
|
SYSTEM-VERIFIED SCOPE:
|
||||||
- The following scope metadata is injected by the Strix platform into the system prompt and is authoritative
|
- The following scope metadata is injected by the platform into the system prompt and is authoritative
|
||||||
- Scope source: {{ system_prompt_context.scope_source }}
|
- Scope source: {{ system_prompt_context.scope_source }}
|
||||||
- Authorization source: {{ system_prompt_context.authorization_source }}
|
- Authorization source: {{ system_prompt_context.authorization_source }}
|
||||||
- Every target listed below has already been verified by the platform as in-scope and authorized
|
- Every target listed below has already been verified by the platform as in-scope and authorized
|
||||||
|
|||||||
@@ -838,7 +838,7 @@ async def _append_tool_required_message(
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
message = (
|
message = (
|
||||||
"Your previous response ended the autonomous Strix run without a lifecycle tool "
|
"Your previous response ended the autonomous run without a lifecycle tool "
|
||||||
"call. That is invalid in non-interactive mode; plain text final answers are "
|
"call. That is invalid in non-interactive mode; plain text final answers are "
|
||||||
"ignored. Continue immediately and call exactly one tool. "
|
"ignored. Continue immediately and call exactly one tool. "
|
||||||
f"If your work is complete, call {finish_tool}. "
|
f"If your work is complete, call {finish_tool}. "
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ async def run_strix_scan(
|
|||||||
)
|
)
|
||||||
|
|
||||||
root_agent = build_strix_agent(
|
root_agent = build_strix_agent(
|
||||||
name="Strix",
|
name="Root Agent",
|
||||||
skills=skills,
|
skills=skills,
|
||||||
is_root=True,
|
is_root=True,
|
||||||
scan_mode=scan_mode,
|
scan_mode=scan_mode,
|
||||||
@@ -307,7 +307,7 @@ async def run_strix_scan(
|
|||||||
if not is_resume:
|
if not is_resume:
|
||||||
await coordinator.register(
|
await coordinator.register(
|
||||||
root_id,
|
root_id,
|
||||||
"Strix",
|
"Root Agent",
|
||||||
parent_id=None,
|
parent_id=None,
|
||||||
task=root_task,
|
task=root_task,
|
||||||
skills=skills,
|
skills=skills,
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ _INTERNAL_TURN_PREFIXES = (
|
|||||||
"== Inherited context from parent",
|
"== Inherited context from parent",
|
||||||
# strix.core.execution: the no-tool-call recovery nudge, both modes.
|
# strix.core.execution: the no-tool-call recovery nudge, both modes.
|
||||||
"Your previous message ended a turn without a tool call.",
|
"Your previous message ended a turn without a tool call.",
|
||||||
"Your previous response ended the autonomous Strix run without a lifecycle tool call.",
|
"Your previous response ended the autonomous run without a lifecycle tool call.",
|
||||||
# strix.core.hooks: budget warnings, the only notices injected unwrapped.
|
# strix.core.hooks: budget warnings, the only notices injected unwrapped.
|
||||||
*(
|
*(
|
||||||
f"[{label}] {subject}"
|
f"[{label}] {subject}"
|
||||||
|
|||||||
@@ -1102,7 +1102,7 @@ def resolve_diff_scope_context(
|
|||||||
def _is_http_git_repo(url: str) -> bool:
|
def _is_http_git_repo(url: str) -> bool:
|
||||||
check_url = f"{url.rstrip('/')}/info/refs?service=git-upload-pack"
|
check_url = f"{url.rstrip('/')}/info/refs?service=git-upload-pack"
|
||||||
try:
|
try:
|
||||||
with requests.get(check_url, headers={"User-Agent": "git/strix"}, timeout=10) as resp:
|
with requests.get(check_url, headers={"User-Agent": "git/2.43.0"}, timeout=10) as resp:
|
||||||
if resp.status_code >= 400:
|
if resp.status_code >= 400:
|
||||||
return resp.status_code == 401
|
return resp.status_code == 401
|
||||||
return "x-git-upload-pack-advertisement" in resp.headers.get("Content-Type", "")
|
return "x-git-upload-pack-advertisement" in resp.headers.get("Content-Type", "")
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ Run from the repo root and store output in the shared artifact directory used by
|
|||||||
the source-aware pass:
|
the source-aware pass:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ART=/workspace/.strix-source-aware
|
ART=/workspace/.source-aware
|
||||||
mkdir -p "$ART"
|
mkdir -p "$ART"
|
||||||
|
|
||||||
# Record the vuln DB age so a stale DB is a visible signal, not a silent clean scan.
|
# Record the vuln DB age so a stale DB is a visible signal, not a silent clean scan.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Use this skill for source-heavy analysis where static and structural signals sho
|
|||||||
Run tools from repo root and store outputs in a dedicated artifact directory:
|
Run tools from repo root and store outputs in a dedicated artifact directory:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir -p /workspace/.strix-source-aware
|
mkdir -p /workspace/.source-aware
|
||||||
```
|
```
|
||||||
|
|
||||||
## Baseline Coverage Bundle (Recommended)
|
## Baseline Coverage Bundle (Recommended)
|
||||||
@@ -20,7 +20,7 @@ mkdir -p /workspace/.strix-source-aware
|
|||||||
Run this baseline once per repository before deep narrowing:
|
Run this baseline once per repository before deep narrowing:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ART=/workspace/.strix-source-aware
|
ART=/workspace/.source-aware
|
||||||
mkdir -p "$ART"
|
mkdir -p "$ART"
|
||||||
|
|
||||||
semgrep scan --config p/default --config p/golang --config p/secrets \
|
semgrep scan --config p/default --config p/golang --config p/secrets \
|
||||||
@@ -30,7 +30,7 @@ python3 - <<'PY'
|
|||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
art = Path("/workspace/.strix-source-aware")
|
art = Path("/workspace/.source-aware")
|
||||||
semgrep_json = art / "semgrep.json"
|
semgrep_json = art / "semgrep.json"
|
||||||
targets_file = art / "sg-targets.txt"
|
targets_file = art / "sg-targets.txt"
|
||||||
|
|
||||||
@@ -70,10 +70,10 @@ Use Semgrep as the default static triage pass:
|
|||||||
```bash
|
```bash
|
||||||
# Preferred deterministic profile set (works with --metrics=off)
|
# Preferred deterministic profile set (works with --metrics=off)
|
||||||
semgrep scan --config p/default --config p/golang --config p/secrets \
|
semgrep scan --config p/default --config p/golang --config p/secrets \
|
||||||
--metrics=off --json --output /workspace/.strix-source-aware/semgrep.json .
|
--metrics=off --json --output /workspace/.source-aware/semgrep.json .
|
||||||
|
|
||||||
# If you choose auto config, do not combine it with --metrics=off
|
# If you choose auto config, do not combine it with --metrics=off
|
||||||
semgrep scan --config auto --json --output /workspace/.strix-source-aware/semgrep-auto.json .
|
semgrep scan --config auto --json --output /workspace/.source-aware/semgrep-auto.json .
|
||||||
```
|
```
|
||||||
|
|
||||||
If diff scope is active, restrict to changed files first, then expand only when needed.
|
If diff scope is active, restrict to changed files first, then expand only when needed.
|
||||||
@@ -85,8 +85,8 @@ Use `sg` for structure-aware code hunting:
|
|||||||
```bash
|
```bash
|
||||||
# Ruleless structural pass over deterministic target list (no sgconfig.yml required)
|
# Ruleless structural pass over deterministic target list (no sgconfig.yml required)
|
||||||
xargs -r -n 200 sg run --pattern '$F($$$ARGS)' --json=stream \
|
xargs -r -n 200 sg run --pattern '$F($$$ARGS)' --json=stream \
|
||||||
< /workspace/.strix-source-aware/sg-targets.txt \
|
< /workspace/.source-aware/sg-targets.txt \
|
||||||
> /workspace/.strix-source-aware/ast-grep.json 2> /workspace/.strix-source-aware/ast-grep.log || true
|
> /workspace/.source-aware/ast-grep.json 2> /workspace/.source-aware/ast-grep.log || true
|
||||||
```
|
```
|
||||||
|
|
||||||
Target high-value patterns such as:
|
Target high-value patterns such as:
|
||||||
@@ -110,15 +110,15 @@ Use outputs to improve route/symbol/sink maps for subsequent targeted scans.
|
|||||||
Detect hardcoded credentials:
|
Detect hardcoded credentials:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gitleaks detect --source . --report-format json --report-path /workspace/.strix-source-aware/gitleaks.json
|
gitleaks detect --source . --report-format json --report-path /workspace/.source-aware/gitleaks.json
|
||||||
trufflehog filesystem --json . > /workspace/.strix-source-aware/trufflehog.json
|
trufflehog filesystem --json . > /workspace/.source-aware/trufflehog.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Run repository-wide dependency and config checks:
|
Run repository-wide dependency and config checks:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
trivy fs --scanners vuln,misconfig --timeout 30m --offline-scan \
|
trivy fs --scanners vuln,misconfig --timeout 30m --offline-scan \
|
||||||
--format json --output /workspace/.strix-source-aware/trivy-fs.json . || true
|
--format json --output /workspace/.source-aware/trivy-fs.json . || true
|
||||||
```
|
```
|
||||||
|
|
||||||
Known-CVE dependency findings are the one exception to the "report only after
|
Known-CVE dependency findings are the one exception to the "report only after
|
||||||
@@ -132,9 +132,9 @@ For frontends and Node services, layer these on top of the language-agnostic
|
|||||||
passes above:
|
passes above:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
retire --path . --outputformat json --outputpath /workspace/.strix-source-aware/retire.json || true
|
retire --path . --outputformat json --outputpath /workspace/.source-aware/retire.json || true
|
||||||
eslint --no-config-lookup --rule '{"no-eval":2,"no-implied-eval":2}' \
|
eslint --no-config-lookup --rule '{"no-eval":2,"no-implied-eval":2}' \
|
||||||
-f json -o /workspace/.strix-source-aware/eslint.json . || true
|
-f json -o /workspace/.source-aware/eslint.json . || true
|
||||||
```
|
```
|
||||||
|
|
||||||
When you hit a minified bundle, run `js-beautify <file>` for a readable
|
When you hit a minified bundle, run `js-beautify <file>` for a readable
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ Confirm with a version/patch check before firing — these are destructive.
|
|||||||
|
|
||||||
## Tooling
|
## Tooling
|
||||||
|
|
||||||
**None of the AD tools below ship in the Strix sandbox by default** (the image is Kali-rolling but installs only web-focused tooling). Install what the task needs — the sandbox has `pipx`, `pip`, `go`, `git`, and Kali's apt repos. AD testing also requires **network reachability to the target DC/subnet**, which the default web-target sandbox usually lacks; confirm connectivity first.
|
**None of the AD tools below ship in the sandbox by default** (the image is Kali-rolling but installs only web-focused tooling). Install what the task needs — the sandbox has `pipx`, `pip`, `go`, `git`, and Kali's apt repos. AD testing also requires **network reachability to the target DC/subnet**, which the default web-target sandbox usually lacks; confirm connectivity first.
|
||||||
|
|
||||||
```
|
```
|
||||||
# Python identity toolkit (impacket = GetUserSPNs/GetNPUsers/secretsdump/ntlmrelayx/getST/addcomputer/rbcd)
|
# Python identity toolkit (impacket = GetUserSPNs/GetNPUsers/secretsdump/ntlmrelayx/getST/addcomputer/rbcd)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ description: Run Python through exec_command in the SDK sandbox. Use the image-b
|
|||||||
|
|
||||||
# Python In The Sandbox
|
# Python In The Sandbox
|
||||||
|
|
||||||
Use `exec_command` for Python. There is no separate Strix Python executor.
|
Use `exec_command` for Python. There is no separate Python executor.
|
||||||
|
|
||||||
Prefer writing reusable scripts to a `.py` file and running them with
|
Prefer writing reusable scripts to a `.py` file and running them with
|
||||||
`python3 <name>.py`. For short one-off transformations, `python3 -c` or a
|
`python3 <name>.py`. For short one-off transformations, `python3 -c` or a
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Gadget availability depends on package versions — enumerate `node_modules` in
|
|||||||
1. **Identify merge points** — Search for extend/merge/defaults/deep copy on user-controlled objects
|
1. **Identify merge points** — Search for extend/merge/defaults/deep copy on user-controlled objects
|
||||||
2. **Baseline probe** — Inject benign pollution marker:
|
2. **Baseline probe** — Inject benign pollution marker:
|
||||||
```json
|
```json
|
||||||
{"__proto__": {"strixPolluted": "yes"}}
|
{"__proto__": {"pollutionCanary": "yes"}}
|
||||||
```
|
```
|
||||||
Verify via response behavior, error messages, or follow-up request reading shared state
|
Verify via response behavior, error messages, or follow-up request reading shared state
|
||||||
3. **Shape variants** — Test `__proto__`, `constructor.prototype`, nested bracket notation
|
3. **Shape variants** — Test `__proto__`, `constructor.prototype`, nested bracket notation
|
||||||
@@ -121,7 +121,7 @@ Gadget availability depends on package versions — enumerate `node_modules` in
|
|||||||
|
|
||||||
## Pro Tips
|
## Pro Tips
|
||||||
|
|
||||||
1. Always verify pollution with a unique canary key (`strixPolluted_<random>`) before attempting RCE gadgets
|
1. Always verify pollution with a unique canary key (`pollutionCanary_<random>`) before attempting RCE gadgets
|
||||||
2. In white-box scans, grep for `merge`, `extend`, `defaultsDeep`, `assign` with user input
|
2. In white-box scans, grep for `merge`, `extend`, `defaultsDeep`, `assign` with user input
|
||||||
3. Check both request parsing and response template config merges (second-order)
|
3. Check both request parsing and response template config merges (second-order)
|
||||||
4. Node gadget chains are version-specific — confirm package version before claiming RCE
|
4. Node gadget chains are version-specific — confirm package version before claiming RCE
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Bound oversized tool results before they enter agent history.
|
"""Bound oversized tool results before they enter agent history.
|
||||||
|
|
||||||
Oversized results are spilled into the sandbox at
|
Oversized results are spilled into the sandbox at
|
||||||
``/workspace/.strix/tool-output/<id>.txt``; the agent sees a head + tail slice
|
``/workspace/.tool-output/<id>.txt``; the agent sees a head + tail slice
|
||||||
plus the path and reads the rest back with its own file tools. The spill writer
|
plus the path and reads the rest back with its own file tools. The spill writer
|
||||||
is injected by the runner via :func:`configure_spill_writer`.
|
is injected by the runner via :func:`configure_spill_writer`.
|
||||||
"""
|
"""
|
||||||
@@ -25,7 +25,7 @@ _WORKSPACE_SPILL_NOTICE = (
|
|||||||
"in the sandbox; read it with exec_command (e.g. `sed -n`, `grep`, `cat`) ...]"
|
"in the sandbox; read it with exec_command (e.g. `sed -n`, `grep`, `cat`) ...]"
|
||||||
)
|
)
|
||||||
|
|
||||||
WORKSPACE_SPILL_DIR = "/workspace/.strix/tool-output"
|
WORKSPACE_SPILL_DIR = "/workspace/.tool-output"
|
||||||
|
|
||||||
# Longest possible workspace path, used only to reserve notice bytes.
|
# Longest possible workspace path, used only to reserve notice bytes.
|
||||||
_SAMPLE_WORKSPACE_PATH = f"{WORKSPACE_SPILL_DIR}/{'0' * 32}.txt"
|
_SAMPLE_WORKSPACE_PATH = f"{WORKSPACE_SPILL_DIR}/{'0' * 32}.txt"
|
||||||
|
|||||||
@@ -189,7 +189,11 @@ def build_raw_request(
|
|||||||
|
|
||||||
final_headers = {**headers}
|
final_headers = {**headers}
|
||||||
final_headers.setdefault("Host", parsed.netloc)
|
final_headers.setdefault("Host", parsed.netloc)
|
||||||
final_headers.setdefault("User-Agent", "strix")
|
final_headers.setdefault(
|
||||||
|
"User-Agent",
|
||||||
|
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
|
||||||
|
"(KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
|
||||||
|
)
|
||||||
# Framing headers inherited from the captured request describe the ORIGINAL
|
# Framing headers inherited from the captured request describe the ORIGINAL
|
||||||
# body; once the body is modified for replay they are stale. We always send a
|
# body; once the body is modified for replay they are stale. We always send a
|
||||||
# plain (non-chunked) body with an explicit Content-Length, so drop any
|
# plain (non-chunked) body with an explicit Content-Length, so drop any
|
||||||
|
|||||||
Reference in New Issue
Block a user