Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,20 @@ Strix are autonomous AI penetration testing agents that act just like real hacke

**Prerequisites:**
- Docker (running)
- An LLM API key from any [supported provider](https://docs.strix.ai/llm-providers/overview) (OpenAI, Anthropic, Google, etc.)
- Codex or Claude Code authenticated with your normal account, or an LLM API key for legacy provider mode

### Installation & First Scan

```bash
# Install Strix
curl -sSL https://strix.ai/install | bash

# Configure your AI provider
export STRIX_LLM="openai/gpt-5.4"
export LLM_API_KEY="your-api-key"

# Run your first security assessment
# Run through Codex or Claude Code; no model API key is needed
strix --target ./app-directory
```

When `STRIX_LLM` is unset, Strix launches an installed Codex or Claude Code CLI and exposes its security runtime through the local `strix-mcp` server. Every model call stays inside that coding agent. Use `--agent codex` or `--agent claude` to select one explicitly. See [coding-agent integration](docs/integrations/coding-agents.mdx) for standalone MCP and skill installation.

> [!NOTE]
> First run automatically pulls the sandbox Docker image. Results are saved to `strix_runs/<run-name>`

Expand Down Expand Up @@ -223,7 +221,9 @@ jobs:
> If diff-scope cannot resolve, ensure checkout uses full history (`fetch-depth: 0`) or pass
> `--diff-base` explicitly.

### Configuration
### Legacy Provider Configuration (Optional)

Codex/Claude agent mode requires no configuration here. For direct provider mode, set:

```bash
export STRIX_LLM="openai/gpt-5.4"
Expand Down
1 change: 1 addition & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
{
"group": "Integrations",
"pages": [
"integrations/coding-agents",
"integrations/github-actions",
"integrations/ci-cd"
]
Expand Down
6 changes: 1 addition & 5 deletions docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,7 @@ Strix uses a graph of specialized agents for comprehensive security testing:
# Install
curl -sSL https://strix.ai/install | bash

# Configure
export STRIX_LLM="openai/gpt-5.4"
export LLM_API_KEY="your-api-key"

# Scan
# Scan through an authenticated Codex or Claude Code CLI
strix --target ./your-app
```

Expand Down
393 changes: 393 additions & 0 deletions docs/integrations/coding-agents.mdx

Large diffs are not rendered by default.

12 changes: 10 additions & 2 deletions docs/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: "Install Strix and run your first security scan"
## Prerequisites

- Docker (running)
- An LLM API key from any [supported provider](/llm-providers/overview) (OpenAI, Anthropic, Google, etc.)
- Codex or Claude Code authenticated with your normal account, or an LLM API key for [legacy provider mode](/llm-providers/overview)

## Installation

Expand All @@ -25,7 +25,13 @@ description: "Install Strix and run your first security scan"

## Configuration

Set your LLM provider:
No model API key is required when Codex or Claude Code is installed and authenticated. Strix automatically selects a coding agent when `STRIX_LLM` is unset:

```bash
strix --target ./your-app
```

To use legacy direct-provider mode instead, set:

```bash
export STRIX_LLM="openai/gpt-5.4"
Expand All @@ -42,6 +48,8 @@ For best results, use `openai/gpt-5.4`, `anthropic/claude-opus-4-6`, or `openai/
strix --target ./your-app
```

See [Codex and Claude Code](/integrations/coding-agents) for explicit agent selection and standalone skill/MCP installation.

<Note>
First run pulls the Docker sandbox image automatically. Results are saved to `strix_runs/<run-name>`.
</Note>
Expand Down
17 changes: 17 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ classifiers = [
]
dependencies = [
"openai-agents[litellm]==0.14.6",
"mcp>=1.28.1",
"pydantic>=2.11.3",
"pydantic-settings>=2.13.0",
"rich",
Expand All @@ -46,6 +47,8 @@ dependencies = [

[project.scripts]
strix = "strix.interface.main:main"
strix-mcp = "strix.mcp.server:main"
strix-skill-path = "strix.mcp.install:print_skill_path"

[dependency-groups]
dev = [
Expand All @@ -57,6 +60,7 @@ dev = [
"pyinstaller>=6.17.0; python_version >= '3.12' and python_version < '3.15'",
"pytest>=8.3",
"pytest-asyncio>=0.24",
"types-pygments>=2.20.0.20260518",
]

[tool.pytest.ini_options]
Expand All @@ -69,6 +73,9 @@ build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["strix"]

[tool.hatch.build.targets.wheel.force-include]
"skills/strix-security" = "strix/agent_skills/strix-security"

# ============================================================================
# Type Checking Configuration
# ============================================================================
Expand Down Expand Up @@ -112,6 +119,16 @@ disable_error_code = ["import-untyped"]
[[tool.mypy.overrides]]
module = ["tests.*"]
disallow_untyped_decorators = false
# Tests intentionally monkeypatch imported module collaborators that are not
# part of those modules' public export surface.
disable_error_code = ["attr-defined"]

# Textual's runtime-defined widget/event APIs do not currently match its strict
# type surface. Keep the legacy TUI isolated until it receives a dedicated
# typing migration; all other Strix modules remain under strict checking.
[[tool.mypy.overrides]]
module = ["strix.interface.tui.app"]
ignore_errors = true

# ============================================================================
# Ruff Configuration (Fast Python Linter & Formatter)
Expand Down
29 changes: 29 additions & 0 deletions skills/strix-security/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
name: strix-security
description: Run authorized Strix application-security assessments through a coding agent and the Strix MCP server, including source review, reconnaissance, browser/API testing, exploit validation, vulnerability reporting, and resumable final reports. Use when asked to pentest, security-test, scan, assess, or find and validate vulnerabilities in a local codebase, repository, web application, domain, or IP address with Strix.
---

# Strix Security

Use the connected coding agent for all reasoning. Use only Strix MCP tools for the scan lifecycle, isolated offensive commands, proxy operations, findings, and report persistence. Never request a separate model API key or invoke a model API from Strix.

## Run the assessment

1. Confirm the targets are explicitly authorized. Treat the targets returned by `start_scan` as the hard scope; user instructions may narrow but never expand it.
2. Call `start_scan` once. For a prior run, pass its name with `resume=true`. Record the returned sandbox paths and output directory.
3. Call `load_knowledge` for `scan_modes/<mode>`. Load technology, framework, protocol, tooling, and vulnerability modules only when evidence makes them relevant.
4. Build a short test plan covering attack-surface discovery, authentication/authorization, input handling, data exposure, business logic, dependencies, and infrastructure as applicable.
5. Execute security commands with `sandbox_exec`. Source targets are under the returned `/workspace/<name>` paths. Drive the browser with the `agent-browser` CLI through `sandbox_exec`; inspect and replay its captured traffic with the proxy tools.
6. Validate every suspected issue with a concrete, reproducible proof of concept. Prefer safe demonstrations and avoid destructive actions, persistence, denial of service, or access beyond the authorized scope.
7. Call `list_findings` before filing. Call `create_vulnerability_report` once per distinct verified root cause. For white-box findings, include repository-relative `code_locations`, exact line ranges, and actionable fixes.
8. Continue until the selected scan mode is satisfied. Call `finish_scan` with customer-facing executive summary, methodology, consolidated technical analysis, and prioritized recommendations. Report the returned output directory.

## Quality bar

- Do not report scanner output, weak signals, version banners, missing headers, or theoretical code paths without exploitability and impact evidence.
- Distinguish separate endpoints, parameters, privileges, and root causes. Do not duplicate a finding with different wording.
- Keep customer-facing reports free of internal paths, agent/tool names, prompts, sandbox details, and model commentary.
- Preserve evidence in commands and reports, but never expose credentials or unrelated sensitive data.
- If blocked or interrupted, call `stop_scan` so artifacts and resume state remain usable.

Read [references/mcp-tools.md](references/mcp-tools.md) when tool selection, arguments, or the browser/proxy workflow is unclear.
10 changes: 10 additions & 0 deletions skills/strix-security/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
interface:
display_name: "Strix Security"
short_description: "Agent-native application security testing"
default_prompt: "Use $strix-security to run an authorized security assessment of this project."
dependencies:
tools:
- type: "mcp"
value: "strix"
description: "Local Strix security sandbox, proxy, knowledge, and reporting server"
transport: "stdio"
39 changes: 39 additions & 0 deletions skills/strix-security/references/mcp-tools.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Strix MCP tools

## Lifecycle

- `start_scan`: initialize targets, report state, source mappings, and the Docker sandbox. Pass `targets`, `mounts`, `scan_mode`, `instruction`, and optional `run_name`. To resume, pass `run_name` and `resume=true`.
- `scan_status`: inspect active state, output path, configuration, and finding count.
- `stop_scan`: persist an incomplete run and tear down its sandbox.
- `finish_scan`: write `penetration_test_report.md`, `run.json`, vulnerability Markdown/CSV/JSON, and SARIF, then tear down the sandbox.

## Execution and knowledge

- `sandbox_exec`: pass an argv array, never a shell command string. Examples: `["bash", "-lc", "cd /workspace/app && semgrep scan --config auto"]`, `["agent-browser", "open", "https://target.example"]`.
- `list_knowledge`: list built-in Strix modules.
- `load_knowledge`: load a module by exact name, such as `frameworks/nextjs`, `protocols/graphql`, `vulnerabilities/idor`, or `tooling/agent_browser`.

## HTTP proxy

All HTTP(S) traffic from sandbox commands is routed through Caido.

1. Generate traffic with curl, Python, or `agent-browser` through `sandbox_exec`.
2. Use `list_proxy_requests` with an optional Caido HTTPQL filter.
3. Use `view_proxy_request` to inspect request or response content.
4. Use `repeat_proxy_request` with field-level modifications to test authorization, input handling, cookies, headers, or bodies.
5. Use `list_sitemap` and `view_sitemap_entry` to enumerate captured application structure.
6. Use `manage_scope` to create or update proxy allowlists and denylists.

## Findings

- `list_findings`: review existing reports before filing another.
- `create_vulnerability_report`: requires title, description, impact, target, technical analysis, PoC description, actual PoC code/payload, remediation, and all eight CVSS 3.1 base metrics. Optional fields include endpoint, method, CVE, CWE, and code locations.

CVSS keys and values:

- `attack_vector`: `N`, `A`, `L`, or `P`
- `attack_complexity`: `L` or `H`
- `privileges_required`: `N`, `L`, or `H`
- `user_interaction`: `N` or `R`
- `scope`: `U` or `C`
- `confidentiality`, `integrity`, `availability`: `N`, `L`, or `H`
6 changes: 4 additions & 2 deletions strix/core/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import logging
import math
from typing import TYPE_CHECKING, Any

from agents.lifecycle import RunHooks
Expand All @@ -27,8 +28,9 @@ class ReportUsageHooks(RunHooks[dict[str, Any]]):
"""Persist SDK-native usage after every model response."""

def __init__(self, *, model: str, max_budget_usd: float | None = None) -> None:
import math
if max_budget_usd is not None and (not math.isfinite(max_budget_usd) or max_budget_usd <= 0):
if max_budget_usd is not None and (
not math.isfinite(max_budget_usd) or max_budget_usd <= 0
):
raise ValueError("max_budget_usd must be a finite number greater than 0")
self._model = model
self._max_budget_usd = max_budget_usd
Expand Down
13 changes: 12 additions & 1 deletion strix/interface/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
from .main import main
"""User interfaces for Strix.

Keep package import lightweight: the MCP service reuses target utilities and
must not initialize the legacy model stack during stdio startup.
"""


def main() -> None:
"""Load and run the CLI entry point lazily."""
from .main import main as run

run()


__all__ = ["main"]
120 changes: 120 additions & 0 deletions strix/interface/agent_launcher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""Launch Strix through an authenticated coding-agent CLI."""

from __future__ import annotations

import json
import os
import shutil
import subprocess
import sys
from pathlib import Path
from typing import Any

from strix.config import load_settings
from strix.mcp.install import skill_path


def uses_coding_agent(args: Any) -> bool:
"""Return whether this invocation should delegate reasoning to a coding agent."""
requested = str(getattr(args, "agent", "auto") or "auto")
if requested == "legacy":
return False
if requested in {"codex", "claude"}:
return True
return not bool(load_settings().llm.model)


def resolve_agent(requested: str) -> str:
"""Resolve ``auto`` to an installed, authenticated-agent-capable CLI."""
if requested != "auto":
if shutil.which(requested) is None:
raise RuntimeError(f"Requested coding agent CLI is not installed: {requested}")
return requested
for candidate in (os.environ.get("STRIX_AGENT"), "codex", "claude"):
if candidate and candidate in {"codex", "claude"} and shutil.which(candidate):
return candidate
raise RuntimeError(
"No coding agent CLI found. Install Codex or Claude Code, or configure legacy "
"provider mode with STRIX_LLM."
)


def _scan_prompt(args: Any) -> str:
instructions_path = skill_path() / "SKILL.md"
targets = [] if args.resume else list(args.target or [])
mounts = [] if args.resume else list(args.mount or [])
call = {
"targets": targets,
"mounts": mounts,
"scan_mode": args.scan_mode,
"instruction": args.instruction or "",
"run_name": args.resume,
"resume": bool(args.resume),
"scope_mode": args.scope_mode,
"diff_base": args.diff_base,
"non_interactive": args.non_interactive,
}
return (
"Run a Strix security assessment now. Read the complete skill file at "
f"{instructions_path} and follow it exactly. Use the connected Strix MCP tools for the "
"scan "
"lifecycle, isolated security commands, proxy traffic, findings, and final report. "
"Do not call any model API or ask for a model API key. Begin by calling start_scan with "
f"these arguments: {json.dumps(call, ensure_ascii=False)}. Continue until finish_scan "
"succeeds, unless authorization or a material blocker requires user input."
)


def _mcp_command() -> tuple[str, list[str]]:
return sys.executable, ["-m", "strix.mcp.server"]


def build_agent_command(args: Any, agent: str) -> list[str]:
"""Build a coding-agent command with an ephemeral Strix MCP server."""
python, server_args = _mcp_command()
prompt = _scan_prompt(args)
cwd = str(Path.cwd())
if agent == "codex":
command = [
"codex",
"-C",
cwd,
"-c",
f"mcp_servers.strix.command={json.dumps(python)}",
"-c",
f"mcp_servers.strix.args={json.dumps(server_args)}",
"-c",
"mcp_servers.strix.startup_timeout_sec=120",
"-c",
"mcp_servers.strix.tool_timeout_sec=900",
]
if args.non_interactive:
command.insert(1, "exec")
command.append(prompt)
return command

config = json.dumps(
{
"mcpServers": {
"strix": {"type": "stdio", "command": python, "args": server_args, "env": {}}
}
}
)
command = ["claude", "--mcp-config", config]
if args.non_interactive:
command.append("--print")
if args.max_budget_usd is not None:
command.extend(["--max-budget-usd", str(args.max_budget_usd)])
# ``--mcp-config`` accepts multiple values. Without an option terminator,
# Claude consumes the positional prompt as another config path.
command.extend(["--", prompt])
return command


def launch_agent_scan(args: Any) -> int:
"""Run Strix in the selected coding agent and return its exit status."""
agent = resolve_agent(str(args.agent or "auto"))
command = build_agent_command(args, agent)
command[0] = shutil.which(agent) or command[0]
result = subprocess.run(command, check=False) # noqa: S603
return result.returncode
Loading