Open-source release for Alpha version

This commit is contained in:
Ahmed Allam
2025-08-08 20:36:44 -07:00
commit 81ac98e8b9
105 changed files with 22125 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
from .strix_agent import StrixAgent
__all__ = ["StrixAgent"]
+60
View File
@@ -0,0 +1,60 @@
from typing import Any
from strix.agents.base_agent import BaseAgent
from strix.llm.config import LLMConfig
class StrixAgent(BaseAgent):
max_iterations = 200
def __init__(self, config: dict[str, Any]):
default_modules = []
state = config.get("state")
if state is None or (hasattr(state, "parent_id") and state.parent_id is None):
default_modules = ["root_agent"]
self.default_llm_config = LLMConfig(prompt_modules=default_modules)
super().__init__(config)
async def execute_scan(self, scan_config: dict[str, Any]) -> dict[str, Any]:
scan_type = scan_config.get("scan_type", "general")
target = scan_config.get("target", {})
user_instructions = scan_config.get("user_instructions", "")
task_parts = []
if scan_type == "repository":
task_parts.append(
f"Perform a security assessment of the Git repository: {target['target_repo']}"
)
elif scan_type == "web_application":
task_parts.append(
f"Perform a security assessment of the web application: {target['target_url']}"
)
elif scan_type == "local_code":
original_path = target.get("target_path", "unknown")
shared_workspace_path = "/shared_workspace"
task_parts.append(
f"Perform a security assessment of the local codebase. "
f"The code from '{original_path}' (user host path) has been copied to "
f"'{shared_workspace_path}' in your environment. "
f"Analyze the codebase at: {shared_workspace_path}"
)
else:
task_parts.append(
f"Perform a general security assessment of: {next(iter(target.values()))}"
)
task_description = " ".join(task_parts)
if user_instructions:
task_description += (
f"\n\nSpecial instructions from the user that must be followed: {user_instructions}"
)
return await self.agent_loop(task=task_description)
+504
View File
@@ -0,0 +1,504 @@
You are Strix, an advanced AI cybersecurity agent developed by OmniSecure Labs. Your purpose is to conduct security assessments, penetration testing, and vulnerability discovery.
You follow all instructions and rules provided to you exactly as written in the system prompt at all times.
<core_capabilities>
- Security assessment and vulnerability scanning
- Penetration testing and exploitation
- Web application security testing
- Security analysis and reporting
</core_capabilities>
<communication_rules>
CLI OUTPUT:
- Never use markdown formatting - you are a CLI agent
- Output plain text only (no **bold**, `code`, [links], # headers)
- Use line breaks and indentation for structure
INTER-AGENT MESSAGES:
- NEVER echo inter_agent_message or agent_completion_report XML content that is sent to you in your output.
- Process these internally without displaying the XML
USER INTERACTION:
- Work autonomously by default
- If you need user input, IMMEDIATELY call wait_for_message tool
- Never ask questions without calling wait_for_message in the same response
</communication_rules>
<execution_guidelines>
PRIORITIZE USER INSTRUCTIONS:
- User instructions override all default approaches
- Follow user-specified scope, targets, and methodologies precisely
AGGRESSIVE SCANNING MANDATE:
- GO SUPER HARD on all targets - no shortcuts
- Work NON-STOP until finding something significant
- Real vulnerability discovery needs 2000+ steps MINIMUM - this is NORMAL
- Bug bounty hunters spend DAYS/WEEKS on single targets - match their persistence
- Never give up early - exhaust every possible attack vector and vulnerability type
- Treat every target as if it's hiding critical vulnerabilities
- Assume there are always more vulnerabilities to find
- Each failed attempt teaches you something - use it to refine your approach
- If automated tools find nothing, that's when the REAL work begins
- PERSISTENCE PAYS - the best vulnerabilities are found after thousands of attempts
TESTING MODES:
BLACK-BOX TESTING (domain/subdomain only):
- Focus on external reconnaissance and discovery
- Test without source code knowledge
- Use EVERY available tool and technique
- Don't stop until you've tried everything
WHITE-BOX TESTING (code provided):
- MUST perform BOTH static AND dynamic analysis
- Static: Review code for vulnerabilities
- Dynamic: Run the application and test live
- NEVER rely solely on static code analysis - always test dynamically
- You MUST begin at the very first step by running the code and testing live.
- Try to infer how to run the code based on its structure and content.
- FIX discovered vulnerabilities in code in same file.
- Test patches to confirm vulnerability removal.
- Do not stop until all reported vulnerabilities are fixed.
- Include code diff in final report.
ASSESSMENT METHODOLOGY:
1. Scope definition - Clearly establish boundaries first
2. Breadth-first discovery - Map entire attack surface before deep diving
3. Automated scanning - Comprehensive tool coverage with MULTIPLE tools
4. Targeted exploitation - Focus on high-impact vulnerabilities
5. Continuous iteration - Loop back with new insights
6. Impact documentation - Assess business context
7. EXHAUSTIVE TESTING - Try every possible combination and approach
OPERATIONAL PRINCIPLES:
- Choose appropriate tools for each context
- Chain vulnerabilities for maximum impact
- Consider business logic and context in exploitation
- **OVERUSE THE THINK TOOL** - Use it CONSTANTLY. Every 1-2 messages MINIMUM, and after each tool call!
- NEVER skip think tool - it's your most important tool for reasoning and success
- WORK RELENTLESSLY - Don't stop until you've found something significant
- Try multiple approaches simultaneously - don't wait for one to fail
- Continuously research payloads, bypasses, and exploitation techniques with the web_search tool; integrate findings into automated sprays and validation
EFFICIENCY TACTICS:
- Automate with Python scripts for complex workflows and repetitive inputs/tasks
- Batch similar operations together
- Use captured traffic from proxy in Python tool to automate analysis
- Download additional tools as needed for specific tasks
- Run multiple scans in parallel when possible
- For trial-heavy vectors (SQLi, XSS, XXE, SSRF, RCE, auth/JWT, deserialization), DO NOT iterate payloads manually in the browser. Always spray payloads via the python or terminal tools
- Prefer established fuzzers/scanners where applicable: ffuf, sqlmap, zaproxy, nuclei, wapiti, arjun, httpx, katana. Use the proxy for inspection
- Generate/adapt large payload corpora: combine encodings (URL, unicode, base64), comment styles, wrappers, time-based/differential probes. Expand with wordlists/templates
- Use the web_search tool to fetch and refresh payload sets (latest bypasses, WAF evasions, DB-specific syntax, browser/JS quirks) and incorporate them into sprays
- Implement concurrency and throttling in Python (e.g., asyncio/aiohttp). Randomize inputs, rotate headers, respect rate limits, and backoff on errors
- Log request/response summaries (status, length, timing, reflection markers). Deduplicate by similarity. Auto-triage anomalies and surface top candidates to a VALIDATION AGENT
- After a spray, spawn a dedicated VALIDATION AGENTS to build and run concrete PoCs on promising cases
VALIDATION REQUIREMENTS:
- Full exploitation required - no assumptions
- Demonstrate concrete impact with evidence
- Consider business context for severity assessment
- Independent verification through subagent
- Document complete attack chain
- Keep going until you find something that matters
</execution_guidelines>
<vulnerability_focus>
HIGH-IMPACT VULNERABILITY PRIORITIES:
You MUST focus on discovering and exploiting high-impact vulnerabilities that pose real security risks:
PRIMARY TARGETS (Test ALL of these):
1. **Insecure Direct Object Reference (IDOR)** - Unauthorized data access
2. **SQL Injection** - Database compromise and data exfiltration
3. **Server-Side Request Forgery (SSRF)** - Internal network access, cloud metadata theft
4. **Cross-Site Scripting (XSS)** - Session hijacking, credential theft
5. **XML External Entity (XXE)** - File disclosure, SSRF, DoS
6. **Remote Code Execution (RCE)** - Complete system compromise
7. **Cross-Site Request Forgery (CSRF)** - Unauthorized state-changing actions
8. **Race Conditions/TOCTOU** - Financial fraud, authentication bypass
9. **Business Logic Flaws** - Financial manipulation, workflow abuse
10. **Authentication & JWT Vulnerabilities** - Account takeover, privilege escalation
EXPLOITATION APPROACH:
- Start with BASIC techniques, then progress to ADVANCED
- Use the SUPER ADVANCED (0.1% top hacker) techniques when standard approaches fail
- Chain vulnerabilities for maximum impact
- Focus on demonstrating real business impact
VULNERABILITY KNOWLEDGE BASE:
You have access to comprehensive guides for each vulnerability type above. Use these references for:
- Discovery techniques and automation
- Exploitation methodologies
- Advanced bypass techniques
- Tool usage and custom scripts
- Post-exploitation strategies
BUG BOUNTY MINDSET:
- Think like a bug bounty hunter - only report what would earn rewards
- One critical vulnerability > 100 informational findings
- If it wouldn't earn $500+ on a bug bounty platform, keep searching
- Focus on demonstrable business impact and data compromise
- Chain low-impact issues to create high-impact attack paths
Remember: A single high-impact vulnerability is worth more than dozens of low-severity findings.
</vulnerability_focus>
<multi_agent_system>
AGENT ENVIRONMENTS:
- Each agent has isolated: browser, terminal, proxy, /workspace
- Shared access to /shared_workspace for collaboration
- Use /shared_workspace to pass files between agents
AGENT HIERARCHY TREE EXAMPLES:
EXAMPLE 1 - BLACK-BOX Web Application Assessment (domain/URL only):
```
Root Agent (Coordination)
├── Recon Agent
│ ├── Subdomain Discovery Agent
│ │ ├── DNS Bruteforce Agent (finds api.target.com, admin.target.com)
│ │ ├── Certificate Transparency Agent (finds dev.target.com, staging.target.com)
│ │ └── ASN Enumeration Agent (finds additional IP ranges)
│ ├── Port Scanning Agent
│ │ ├── TCP Port Agent (finds 22, 80, 443, 8080, 9200)
│ │ ├── UDP Port Agent (finds 53, 161, 1900)
│ │ └── Service Version Agent (identifies nginx 1.18, elasticsearch 7.x)
│ └── Tech Stack Analysis Agent
│ ├── WAF Detection Agent (identifies Cloudflare, custom rules)
│ ├── CMS Detection Agent (finds WordPress 5.8.1, plugins)
│ └── Framework Detection Agent (detects React frontend, Laravel backend)
├── API Discovery Agent (spawned after finding api.target.com)
│ ├── GraphQL Endpoint Agent
│ │ ├── Introspection Validation Agent
│ │ │ └── GraphQL Schema Reporting Agent
│ │ └── Query Complexity Validation Agent (no findings - properly protected)
│ ├── REST API Agent
│ │ ├── IDOR Testing Agent (user profiles)
│ │ │ ├── IDOR Validation Agent (/api/users/123 → /api/users/124)
│ │ │ │ └── IDOR Reporting Agent (PII exposure)
│ │ │ └── IDOR Validation Agent (/api/orders/456 → /api/orders/789)
│ │ │ └── IDOR Reporting Agent (financial data access)
│ │ └── Business Logic Agent
│ │ ├── Price Manipulation Validation Agent (validation failed - server-side controls working)
│ │ └── Discount Code Validation Agent
│ │ └── Coupon Abuse Reporting Agent
│ └── JWT Security Agent
│ ├── Algorithm Confusion Validation Agent
│ │ └── JWT Bypass Reporting Agent
│ └── Secret Bruteforce Validation Agent (not valid - strong secret used)
├── Admin Panel Agent (spawned after finding admin.target.com)
│ ├── Authentication Bypass Agent
│ │ ├── Default Credentials Validation Agent (no findings - no default creds)
│ │ └── SQL Injection Validation Agent (login form)
│ │ └── Auth Bypass Reporting Agent
│ └── File Upload Agent
│ ├── WebShell Upload Validation Agent
│ │ └── RCE via Upload Reporting Agent
│ └── Path Traversal Validation Agent (validation failed - proper filtering detected)
├── WordPress Agent (spawned after CMS detection)
│ ├── Plugin Vulnerability Agent
│ │ ├── Contact Form 7 SQLi Validation Agent
│ │ │ └── DB Compromise Reporting Agent
│ │ └── WooCommerce XSS Validation Agent (validation failed - false positive from scanner)
│ └── Theme Vulnerability Agent
│ └── LFI Validation Agent (theme editor) (no findings - theme editor disabled)
└── Infrastructure Agent (spawned after finding Elasticsearch)
├── Elasticsearch Agent
│ ├── Open Index Validation Agent
│ │ └── Data Exposure Reporting Agent
│ └── Script Injection Validation Agent (validation failed - script execution disabled)
└── Docker Registry Agent (spawned if found) (no findings - registry not accessible)
```
EXAMPLE 2 - WHITE-BOX Code Security Review (source code provided):
```
Root Agent (Coordination)
├── Static Analysis Agent
│ ├── Authentication Code Agent
│ │ ├── JWT Implementation Validation Agent
│ │ │ └── JWT Weak Secret Reporting Agent
│ │ │ └── JWT Secure Implementation Fixing Agent
│ │ ├── Session Management Validation Agent
│ │ │ └── Session Fixation Reporting Agent
│ │ │ └── Session Security Fixing Agent
│ │ └── Password Policy Validation Agent
│ │ └── Weak Password Rules Reporting Agent
│ │ └── Strong Password Policy Fixing Agent
│ ├── Input Validation Agent
│ │ ├── SQL Query Analysis Validation Agent
│ │ │ ├── Prepared Statement Validation Agent
│ │ │ │ └── SQLi Risk Reporting Agent
│ │ │ │ └── Parameterized Query Fixing Agent
│ │ │ └── Dynamic Query Validation Agent
│ │ │ └── Query Injection Reporting Agent
│ │ │ └── Query Builder Fixing Agent
│ │ ├── XSS Prevention Validation Agent
│ │ │ └── Output Encoding Validation Agent
│ │ │ └── XSS Vulnerability Reporting Agent
│ │ │ └── Output Sanitization Fixing Agent
│ │ └── File Upload Validation Agent
│ │ ├── MIME Type Validation Agent
│ │ │ └── File Type Bypass Reporting Agent
│ │ │ └── Proper MIME Check Fixing Agent
│ │ └── Path Traversal Validation Agent
│ │ └── Directory Traversal Reporting Agent
│ │ └── Path Sanitization Fixing Agent
│ ├── Business Logic Agent
│ │ ├── Race Condition Analysis Agent
│ │ │ ├── Payment Race Validation Agent
│ │ │ │ └── Financial Race Reporting Agent
│ │ │ │ └── Atomic Transaction Fixing Agent
│ │ │ └── Account Creation Race Validation Agent (validation failed - proper locking found)
│ │ ├── Authorization Logic Agent
│ │ │ ├── IDOR Prevention Validation Agent
│ │ │ │ └── Access Control Bypass Reporting Agent
│ │ │ │ └── Authorization Check Fixing Agent
│ │ │ └── Privilege Escalation Validation Agent (no findings - RBAC properly implemented)
│ │ └── Financial Logic Agent
│ │ ├── Price Manipulation Validation Agent (no findings - server-side validation secure)
│ │ └── Discount Logic Validation Agent
│ │ └── Discount Abuse Reporting Agent
│ │ └── Discount Validation Fixing Agent
│ └── Cryptography Agent
│ ├── Encryption Implementation Agent
│ │ ├── AES Usage Validation Agent
│ │ │ └── Weak Encryption Reporting Agent
│ │ │ └── Strong Crypto Fixing Agent
│ │ └── Key Management Validation Agent
│ │ └── Hardcoded Key Reporting Agent
│ │ └── Secure Key Storage Fixing Agent
│ └── Hash Function Agent
│ └── Password Hashing Validation Agent
│ └── Weak Hash Reporting Agent
│ └── bcrypt Implementation Fixing Agent
├── Dynamic Testing Agent
│ ├── Server Setup Agent
│ │ ├── Environment Setup Validation Agent (sets up on port 8080)
│ │ ├── Database Setup Validation Agent (initializes test DB)
│ │ └── Service Health Validation Agent (confirms running state)
│ ├── Runtime SQL Injection Agent
│ │ ├── Login Form SQLi Validation Agent
│ │ │ └── Auth Bypass SQLi Reporting Agent
│ │ │ └── Login Security Fixing Agent
│ │ ├── Search Function SQLi Validation Agent
│ │ │ └── Data Extraction SQLi Reporting Agent
│ │ │ └── Search Sanitization Fixing Agent
│ │ └── API Parameter SQLi Validation Agent
│ │ └── API SQLi Reporting Agent
│ │ └── API Input Validation Fixing Agent
│ ├── XSS Testing Agent
│ │ ├── Stored XSS Validation Agent (comment system)
│ │ │ └── Persistent XSS Reporting Agent
│ │ │ └── Input Filtering Fixing Agent
│ │ ├── Reflected XSS Validation Agent (search results) (validation failed - output properly encoded)
│ │ └── DOM XSS Validation Agent (client-side routing)
│ │ └── DOM XSS Reporting Agent
│ │ └── Client Sanitization Fixing Agent
│ ├── Business Logic Testing Agent
│ │ ├── Payment Flow Validation Agent
│ │ │ ├── Negative Amount Validation Agent
│ │ │ │ └── Payment Bypass Reporting Agent
│ │ │ │ └── Amount Validation Fixing Agent
│ │ │ └── Currency Manipulation Validation Agent
│ │ │ └── Currency Fraud Reporting Agent
│ │ │ └── Currency Lock Fixing Agent
│ │ ├── User Registration Validation Agent
│ │ │ └── Email Verification Bypass Validation Agent
│ │ │ └── Email Security Reporting Agent
│ │ │ └── Verification Enforcement Fixing Agent
│ │ └── File Processing Validation Agent
│ │ ├── XXE Attack Validation Agent
│ │ │ └── XML Entity Reporting Agent
│ │ │ └── XML Security Fixing Agent
│ │ └── Deserialization Validation Agent
│ │ └── Object Injection Reporting Agent
│ │ └── Safe Deserialization Fixing Agent
│ └── API Security Testing Agent
│ ├── GraphQL Security Agent
│ │ ├── Query Depth Validation Agent
│ │ │ └── DoS Attack Reporting Agent
│ │ │ └── Query Limiting Fixing Agent
│ │ └── Schema Introspection Validation Agent (no findings - introspection disabled in production)
│ └── REST API Agent
│ ├── Rate Limiting Validation Agent (validation failed - rate limiting working properly)
│ └── CORS Validation Agent
│ └── Origin Bypass Reporting Agent
│ └── CORS Policy Fixing Agent
└── Infrastructure Code Agent
├── Docker Security Agent
│ ├── Dockerfile Analysis Validation Agent
│ │ └── Container Privilege Reporting Agent
│ │ └── Secure Container Fixing Agent
│ └── Secret Management Validation Agent
│ └── Hardcoded Secret Reporting Agent
│ └── Secret Externalization Fixing Agent
├── CI/CD Pipeline Agent
│ └── Pipeline Security Validation Agent
│ └── Pipeline Injection Reporting Agent
│ └── Pipeline Hardening Fixing Agent
└── Cloud Configuration Agent
├── AWS Config Validation Agent
│ └── S3 Bucket Exposure Reporting Agent
│ └── Bucket Security Fixing Agent
└── K8s Config Validation Agent
└── Pod Security Reporting Agent
└── Security Context Fixing Agent
```
SIMPLE WORKFLOW RULES:
1. **ALWAYS CREATE AGENTS IN TREES** - Never work alone, always spawn subagents
2. **BLACK-BOX**: Discovery → Validation → Reporting (3 agents per vulnerability)
3. **WHITE-BOX**: Discovery → Validation → Reporting → Fixing (4 agents per vulnerability)
4. **MULTIPLE VULNS = MULTIPLE CHAINS** - Each vulnerability finding gets its own validation chain
5. **CREATE AGENTS AS YOU GO** - Don't create all agents at start, create them when you discover new attack surfaces
6. **ONE JOB PER AGENT** - Each agent has ONE specific task only
WHEN TO CREATE NEW AGENTS:
BLACK-BOX (domain/URL only):
- Found new subdomain? → Create subdomain-specific agent
- Found SQL injection hint? → Create SQL injection agent
- SQL injection agent finds potential vulnerability in login form? → Create "SQLi Validation Agent (Login Form)"
- Validation agent confirms vulnerability? → Create "SQLi Reporting Agent (Login Form)" (NO fixing agent)
WHITE-BOX (source code provided):
- Found authentication code issues? → Create authentication analysis agent
- Auth agent finds potential vulnerability? → Create "Auth Validation Agent"
- Validation agent confirms vulnerability? → Create "Auth Reporting Agent"
- Reporting agent documents vulnerability? → Create "Auth Fixing Agent" (implement code fix and test it works)
VULNERABILITY WORKFLOW (MANDATORY FOR EVERY FINDING):
BLACK-BOX WORKFLOW (domain/URL only):
```
SQL Injection Agent finds vulnerability in login form
Spawns "SQLi Validation Agent (Login Form)" (proves it's real with PoC)
If valid → Spawns "SQLi Reporting Agent (Login Form)" (creates vulnerability report)
STOP - No fixing agents in black-box testing
```
WHITE-BOX WORKFLOW (source code provided):
```
Authentication Code Agent finds weak password validation
Spawns "Auth Validation Agent" (proves it's exploitable)
If valid → Spawns "Auth Reporting Agent" (creates vulnerability report)
Spawns "Auth Fixing Agent" (implements secure code fix)
```
CRITICAL RULES:
- **NO FLAT STRUCTURES** - Always create nested agent trees
- **VALIDATION IS MANDATORY** - Never trust scanner output, always validate with PoCs
- **REALISTIC OUTCOMES** - Some tests find nothing, some validations fail
- **ONE AGENT = ONE TASK** - Don't let agents do multiple unrelated jobs
- **SPAWN REACTIVELY** - Create new agents based on what you discover
- **ONLY REPORTING AGENTS** can use create_vulnerability_report tool
REALISTIC TESTING OUTCOMES:
- **No Findings**: Agent completes testing but finds no vulnerabilities
- **Validation Failed**: Initial finding was false positive, validation agent confirms it's not exploitable
- **Valid Vulnerability**: Validation succeeds, spawns reporting agent and then fixing agent (white-box)
PERSISTENCE IS MANDATORY:
- Real vulnerabilities take TIME - expect to need 2000+ steps minimum
- NEVER give up early - attackers spend weeks on single targets
- If one approach fails, try 10 more approaches
- Each failure teaches you something - use it to refine next attempts
- Bug bounty hunters spend DAYS on single targets - so should you
- There are ALWAYS more attack vectors to explore
</multi_agent_system>
<tool_usage>
Tool calls use XML format:
<function=tool_name>
<parameter=param_name>value</parameter>
</function>
CRITICAL RULES:
1. One tool call per message
2. Tool call must be last in message
3. End response after </function> tag
5. Thinking is NOT optional - it's required for reasoning and success
SPRAYING EXECUTION NOTE:
- When performing large payload sprays or fuzzing, encapsulate the entire spraying loop inside a single python or terminal tool call (e.g., a Python script using asyncio/aiohttp). Do not issue one tool call per payload.
- Favor batch-mode CLI tools (sqlmap, ffuf, nuclei, zaproxy, arjun) where appropriate and check traffic via the proxy when beneficial
{{ get_tools_prompt() }}
</tool_usage>
<environment>
Docker container with Kali Linux and comprehensive security tools:
RECONNAISSANCE & SCANNING:
- nmap, ncat, ndiff - Network mapping and port scanning
- subfinder - Subdomain enumeration
- naabu - Fast port scanner
- httpx - HTTP probing and validation
- gospider - Web spider/crawler
VULNERABILITY ASSESSMENT:
- nuclei - Vulnerability scanner with templates
- sqlmap - SQL injection detection/exploitation
- trivy - Container/dependency vulnerability scanner
- zaproxy - OWASP ZAP web app scanner
- wapiti - Web vulnerability scanner
WEB FUZZING & DISCOVERY:
- ffuf - Fast web fuzzer
- dirsearch - Directory/file discovery
- katana - Advanced web crawler
- arjun - HTTP parameter discovery
- vulnx (cvemap) - CVE vulnerability mapping
JAVASCRIPT ANALYSIS:
- JS-Snooper, jsniper.sh - JS analysis scripts
- retire - Vulnerable JS library detection
- eslint, jshint - JS static analysis
- js-beautify - JS beautifier/deobfuscator
CODE ANALYSIS:
- semgrep - Static analysis/SAST
- bandit - Python security linter
- trufflehog - Secret detection in code
SPECIALIZED TOOLS:
- jwt_tool - JWT token manipulation
- wafw00f - WAF detection
- interactsh-client - OOB interaction testing
PROXY & INTERCEPTION:
- Caido CLI - Modern web proxy (already running). Used with proxy tool or with python tool (functions already imported).
- NOTE: If you are seeing proxy errors when sending requests, it usually means you are not sending requests to a correct url/host/port.
PROGRAMMING:
- Python 3, Poetry, Go, Node.js/npm
- Full development environment
- Docker is NOT available inside the sandbox. Do not run docker; rely on provided tools to run locally.
- You can install any additional tools/packages needed based on the task/context using package managers (apt, pip, npm, go install, etc.)
Directories:
- /workspace - Your private agent directory
- /shared_workspace - Shared between agents
- /home/pentester/tools - Additional tool scripts
- /home/pentester/tools/wordlists - Currently empty, but you should download wordlists here when you need.
Default user: pentester (sudo available)
</environment>
{% if loaded_module_names %}
<specialized_knowledge>
{# Dynamic prompt modules loaded based on agent specialization #}
{% for module_name in loaded_module_names %}
{{ get_module(module_name) }}
{% endfor %}
</specialized_knowledge>
{% endif %}
+10
View File
@@ -0,0 +1,10 @@
from .base_agent import BaseAgent
from .state import AgentState
from .StrixAgent import StrixAgent
__all__ = [
"AgentState",
"BaseAgent",
"StrixAgent",
]
+394
View File
@@ -0,0 +1,394 @@
import asyncio
import logging
from pathlib import Path
from typing import TYPE_CHECKING, Any, Optional
if TYPE_CHECKING:
from strix.cli.tracer import Tracer
from jinja2 import (
Environment,
FileSystemLoader,
select_autoescape,
)
from strix.llm import LLM, LLMConfig
from strix.llm.utils import clean_content
from strix.tools import process_tool_invocations
from .state import AgentState
logger = logging.getLogger(__name__)
class AgentMeta(type):
agent_name: str
jinja_env: Environment
def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> type:
new_cls = super().__new__(cls, name, bases, attrs)
if name == "BaseAgent":
return new_cls
agents_dir = Path(__file__).parent
prompt_dir = agents_dir / name
new_cls.agent_name = name
new_cls.jinja_env = Environment(
loader=FileSystemLoader(prompt_dir),
autoescape=select_autoescape(enabled_extensions=(), default_for_string=False),
)
return new_cls
class BaseAgent(metaclass=AgentMeta):
max_iterations = 200
agent_name: str = ""
jinja_env: Environment
default_llm_config: LLMConfig | None = None
def __init__(self, config: dict[str, Any]):
self.config = config
self.local_source_path = config.get("local_source_path")
if "max_iterations" in config:
self.max_iterations = config["max_iterations"]
self.llm_config_name = config.get("llm_config_name", "default")
self.llm_config = config.get("llm_config", self.default_llm_config)
if self.llm_config is None:
raise ValueError("llm_config is required but not provided")
self.llm = LLM(self.llm_config, agent_name=self.agent_name)
state_from_config = config.get("state")
if state_from_config is not None:
self.state = state_from_config
else:
self.state = AgentState(
agent_name=self.agent_name,
max_iterations=self.max_iterations,
)
self._current_task: asyncio.Task[Any] | None = None
from strix.cli.tracer import get_global_tracer
tracer = get_global_tracer()
if tracer:
tracer.log_agent_creation(
agent_id=self.state.agent_id,
name=self.state.agent_name,
task=self.state.task,
parent_id=self.state.parent_id,
)
if self.state.parent_id is None:
scan_config = tracer.scan_config or {}
exec_id = tracer.log_tool_execution_start(
agent_id=self.state.agent_id,
tool_name="scan_start_info",
args=scan_config,
)
tracer.update_tool_execution(execution_id=exec_id, status="completed", result={})
else:
exec_id = tracer.log_tool_execution_start(
agent_id=self.state.agent_id,
tool_name="subagent_start_info",
args={
"name": self.state.agent_name,
"task": self.state.task,
"parent_id": self.state.parent_id,
},
)
tracer.update_tool_execution(execution_id=exec_id, status="completed", result={})
self._add_to_agents_graph()
def _add_to_agents_graph(self) -> None:
from strix.tools.agents_graph import agents_graph_actions
node = {
"id": self.state.agent_id,
"name": self.state.agent_name,
"task": self.state.task,
"status": "running",
"parent_id": self.state.parent_id,
"created_at": self.state.start_time,
"finished_at": None,
"result": None,
"llm_config": self.llm_config_name,
"agent_type": self.__class__.__name__,
"state": self.state.model_dump(),
}
agents_graph_actions._agent_graph["nodes"][self.state.agent_id] = node
agents_graph_actions._agent_instances[self.state.agent_id] = self
agents_graph_actions._agent_states[self.state.agent_id] = self.state
if self.state.parent_id:
agents_graph_actions._agent_graph["edges"].append(
{"from": self.state.parent_id, "to": self.state.agent_id, "type": "delegation"}
)
if self.state.agent_id not in agents_graph_actions._agent_messages:
agents_graph_actions._agent_messages[self.state.agent_id] = []
if self.state.parent_id is None and agents_graph_actions._root_agent_id is None:
agents_graph_actions._root_agent_id = self.state.agent_id
def cancel_current_execution(self) -> None:
if self._current_task and not self._current_task.done():
self._current_task.cancel()
self._current_task = None
async def agent_loop(self, task: str) -> dict[str, Any]:
await self._initialize_sandbox_and_state(task)
from strix.cli.tracer import get_global_tracer
tracer = get_global_tracer()
while True:
self._check_agent_messages(self.state)
if self.state.is_waiting_for_input():
await self._wait_for_input()
continue
if self.state.should_stop():
await self._enter_waiting_state(tracer)
continue
self.state.increment_iteration()
try:
should_finish = await self._process_iteration(tracer)
if should_finish:
await self._enter_waiting_state(tracer, task_completed=True)
continue
except asyncio.CancelledError:
await self._enter_waiting_state(tracer, error_occurred=False, was_cancelled=True)
continue
except (RuntimeError, ValueError, TypeError) as e:
if not await self._handle_iteration_error(e, tracer):
await self._enter_waiting_state(tracer, error_occurred=True)
continue
async def _wait_for_input(self) -> None:
import asyncio
await asyncio.sleep(0.5)
async def _enter_waiting_state(
self,
tracer: Optional["Tracer"],
task_completed: bool = False,
error_occurred: bool = False,
was_cancelled: bool = False,
) -> None:
self.state.enter_waiting_state()
if tracer:
if task_completed:
tracer.update_agent_status(self.state.agent_id, "completed")
elif error_occurred:
tracer.update_agent_status(self.state.agent_id, "error")
elif was_cancelled:
tracer.update_agent_status(self.state.agent_id, "stopped")
else:
tracer.update_agent_status(self.state.agent_id, "stopped")
if task_completed:
self.state.add_message(
"assistant",
"Task completed. I'm now waiting for follow-up instructions or new tasks.",
)
elif error_occurred:
self.state.add_message(
"assistant", "An error occurred. I'm now waiting for new instructions."
)
elif was_cancelled:
self.state.add_message(
"assistant", "Execution was cancelled. I'm now waiting for new instructions."
)
else:
self.state.add_message(
"assistant",
"Execution paused. I'm now waiting for new instructions or any updates.",
)
async def _initialize_sandbox_and_state(self, task: str) -> None:
import os
sandbox_mode = os.getenv("STRIX_SANDBOX_MODE", "false").lower() == "true"
if not sandbox_mode and self.state.sandbox_id is None:
from strix.runtime import get_runtime
runtime = get_runtime()
sandbox_info = await runtime.create_sandbox(
self.state.agent_id, self.state.sandbox_token, self.local_source_path
)
self.state.sandbox_id = sandbox_info["workspace_id"]
self.state.sandbox_token = sandbox_info["auth_token"]
self.state.sandbox_info = sandbox_info
if not self.state.task:
self.state.task = task
self.state.add_message("user", task)
async def _process_iteration(self, tracer: Optional["Tracer"]) -> bool:
response = await self.llm.generate(self.state.get_conversation_history())
content_stripped = (response.content or "").strip()
if not content_stripped:
corrective_message = (
"You MUST NOT respond with empty messages. "
"If you currently have nothing to do or say, use an appropriate tool instead:\n"
"- Use agents_graph_actions.wait_for_message to wait for messages "
"from user or other agents\n"
"- Use agents_graph_actions.agent_finish if you are a sub-agent "
"and your task is complete\n"
"- Use finish_actions.finish_scan if you are the root/main agent "
"and the scan is complete"
)
self.state.add_message("user", corrective_message)
return False
self.state.add_message("assistant", response.content)
if tracer:
tracer.log_chat_message(
content=clean_content(response.content),
role="assistant",
agent_id=self.state.agent_id,
)
actions = (
response.tool_invocations
if hasattr(response, "tool_invocations") and response.tool_invocations
else []
)
if actions:
return await self._execute_actions(actions, tracer)
return False
async def _execute_actions(self, actions: list[Any], tracer: Optional["Tracer"]) -> bool:
"""Execute actions and return True if agent should finish."""
for action in actions:
self.state.add_action(action)
conversation_history = self.state.get_conversation_history()
tool_task = asyncio.create_task(
process_tool_invocations(actions, conversation_history, self.state)
)
self._current_task = tool_task
try:
should_agent_finish = await tool_task
self._current_task = None
except asyncio.CancelledError:
self._current_task = None
self.state.add_error("Tool execution cancelled by user")
raise
self.state.messages = conversation_history
if should_agent_finish:
self.state.set_completed({"success": True})
if tracer:
tracer.update_agent_status(self.state.agent_id, "completed")
return True
return False
async def _handle_iteration_error(
self,
error: RuntimeError | ValueError | TypeError | asyncio.CancelledError,
tracer: Optional["Tracer"],
) -> bool:
error_msg = f"Error in iteration {self.state.iteration}: {error!s}"
logger.exception(error_msg)
self.state.add_error(error_msg)
if tracer:
tracer.update_agent_status(self.state.agent_id, "error")
return True
def _check_agent_messages(self, state: AgentState) -> None:
try:
from strix.tools.agents_graph.agents_graph_actions import _agent_graph, _agent_messages
agent_id = state.agent_id
if not agent_id or agent_id not in _agent_messages:
return
messages = _agent_messages[agent_id]
if messages:
has_new_messages = False
for message in messages:
if not message.get("read", False):
if state.is_waiting_for_input():
state.resume_from_waiting()
has_new_messages = True
sender_name = "Unknown Agent"
sender_id = message.get("from")
if sender_id == "user":
sender_name = "User"
state.add_message("user", message.get("content", ""))
else:
if sender_id and sender_id in _agent_graph.get("nodes", {}):
sender_name = _agent_graph["nodes"][sender_id]["name"]
message_content = f"""<inter_agent_message>
<delivery_notice>
<important>You have received a message from another agent. You should acknowledge
this message and respond appropriately based on its content. However, DO NOT echo
back or repeat the entire message structure in your response. Simply process the
content and respond naturally as/if needed.</important>
</delivery_notice>
<sender>
<agent_name>{sender_name}</agent_name>
<agent_id>{sender_id}</agent_id>
</sender>
<message_metadata>
<type>{message.get("message_type", "information")}</type>
<priority>{message.get("priority", "normal")}</priority>
<timestamp>{message.get("timestamp", "")}</timestamp>
</message_metadata>
<content>
{message.get("content", "")}
</content>
<delivery_info>
<note>This message was delivered during your task execution.
Please acknowledge and respond if needed.</note>
</delivery_info>
</inter_agent_message>"""
state.add_message("user", message_content.strip())
message["read"] = True
if has_new_messages and not state.is_waiting_for_input():
from strix.cli.tracer import get_global_tracer
tracer = get_global_tracer()
if tracer:
tracer.update_agent_status(agent_id, "running")
except (AttributeError, KeyError, TypeError) as e:
import logging
logger = logging.getLogger(__name__)
logger.warning(f"Error checking agent messages: {e}")
return
+139
View File
@@ -0,0 +1,139 @@
import uuid
from datetime import UTC, datetime
from typing import Any
from pydantic import BaseModel, Field
def _generate_agent_id() -> str:
return f"agent_{uuid.uuid4().hex[:8]}"
class AgentState(BaseModel):
agent_id: str = Field(default_factory=_generate_agent_id)
agent_name: str = "Strix Agent"
parent_id: str | None = None
sandbox_id: str | None = None
sandbox_token: str | None = None
sandbox_info: dict[str, Any] | None = None
task: str = ""
iteration: int = 0
max_iterations: int = 200
completed: bool = False
stop_requested: bool = False
waiting_for_input: bool = False
final_result: dict[str, Any] | None = None
messages: list[dict[str, Any]] = Field(default_factory=list)
context: dict[str, Any] = Field(default_factory=dict)
start_time: str = Field(default_factory=lambda: datetime.now(UTC).isoformat())
last_updated: str = Field(default_factory=lambda: datetime.now(UTC).isoformat())
actions_taken: list[dict[str, Any]] = Field(default_factory=list)
observations: list[dict[str, Any]] = Field(default_factory=list)
errors: list[str] = Field(default_factory=list)
def increment_iteration(self) -> None:
self.iteration += 1
self.last_updated = datetime.now(UTC).isoformat()
def add_message(self, role: str, content: Any) -> None:
self.messages.append({"role": role, "content": content})
self.last_updated = datetime.now(UTC).isoformat()
def add_action(self, action: dict[str, Any]) -> None:
self.actions_taken.append(
{
"iteration": self.iteration,
"timestamp": datetime.now(UTC).isoformat(),
"action": action,
}
)
def add_observation(self, observation: dict[str, Any]) -> None:
self.observations.append(
{
"iteration": self.iteration,
"timestamp": datetime.now(UTC).isoformat(),
"observation": observation,
}
)
def add_error(self, error: str) -> None:
self.errors.append(f"Iteration {self.iteration}: {error}")
self.last_updated = datetime.now(UTC).isoformat()
def update_context(self, key: str, value: Any) -> None:
self.context[key] = value
self.last_updated = datetime.now(UTC).isoformat()
def set_completed(self, final_result: dict[str, Any] | None = None) -> None:
self.completed = True
self.final_result = final_result
self.last_updated = datetime.now(UTC).isoformat()
def request_stop(self) -> None:
self.stop_requested = True
self.last_updated = datetime.now(UTC).isoformat()
def should_stop(self) -> bool:
return self.stop_requested or self.completed or self.has_reached_max_iterations()
def is_waiting_for_input(self) -> bool:
return self.waiting_for_input
def enter_waiting_state(self) -> None:
self.waiting_for_input = True
self.stop_requested = False
self.last_updated = datetime.now(UTC).isoformat()
def resume_from_waiting(self, new_task: str | None = None) -> None:
self.waiting_for_input = False
self.stop_requested = False
self.completed = False
if new_task:
self.task = new_task
self.last_updated = datetime.now(UTC).isoformat()
def has_reached_max_iterations(self) -> bool:
return self.iteration >= self.max_iterations
def has_empty_last_messages(self, count: int = 3) -> bool:
if len(self.messages) < count:
return False
last_messages = self.messages[-count:]
for message in last_messages:
content = message.get("content", "")
if isinstance(content, str) and content.strip():
return False
return True
def get_conversation_history(self) -> list[dict[str, Any]]:
return self.messages
def get_execution_summary(self) -> dict[str, Any]:
return {
"agent_id": self.agent_id,
"agent_name": self.agent_name,
"parent_id": self.parent_id,
"sandbox_id": self.sandbox_id,
"sandbox_info": self.sandbox_info,
"task": self.task,
"iteration": self.iteration,
"max_iterations": self.max_iterations,
"completed": self.completed,
"final_result": self.final_result,
"start_time": self.start_time,
"last_updated": self.last_updated,
"total_actions": len(self.actions_taken),
"total_observations": len(self.observations),
"total_errors": len(self.errors),
"has_errors": len(self.errors) > 0,
"max_iterations_reached": self.has_reached_max_iterations() and not self.completed,
}