stryx-cli 0.1.0__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.
Files changed (74) hide show
  1. stryx/__init__.py +35 -0
  2. stryx/ai/__init__.py +5 -0
  3. stryx/ai/attack_planner.py +199 -0
  4. stryx/ai/payload_generator.py +212 -0
  5. stryx/ai/prompts.py +85 -0
  6. stryx/ai/providers.py +249 -0
  7. stryx/attacks/__init__.py +6 -0
  8. stryx/attacks/attack_chain.py +111 -0
  9. stryx/attacks/replay.py +186 -0
  10. stryx/auth/__init__.py +1 -0
  11. stryx/auth/session_manager.py +335 -0
  12. stryx/cli.py +675 -0
  13. stryx/comparison/__init__.py +1 -0
  14. stryx/comparison/differ.py +255 -0
  15. stryx/config/__init__.py +6 -0
  16. stryx/config/default_config.yaml +12 -0
  17. stryx/config/loader.py +111 -0
  18. stryx/config/schema.py +80 -0
  19. stryx/crawler/__init__.py +5 -0
  20. stryx/crawler/discovery.py +178 -0
  21. stryx/crawler/graphql_discovery.py +86 -0
  22. stryx/crawler/html_crawler.py +294 -0
  23. stryx/crawler/js_endpoints.py +165 -0
  24. stryx/crawler/openapi.py +76 -0
  25. stryx/crawler/sitemap.py +94 -0
  26. stryx/orchestrator.py +347 -0
  27. stryx/payloads/cmdi.txt +31 -0
  28. stryx/payloads/header_injection.txt +15 -0
  29. stryx/payloads/ldap.txt +19 -0
  30. stryx/payloads/nosqli.txt +21 -0
  31. stryx/payloads/open_redirect.txt +23 -0
  32. stryx/payloads/path_traversal.txt +26 -0
  33. stryx/payloads/sqli.txt +31 -0
  34. stryx/payloads/ssrf.txt +30 -0
  35. stryx/payloads/ssti.txt +21 -0
  36. stryx/payloads/xss.txt +48 -0
  37. stryx/payloads/xxe.txt +35 -0
  38. stryx/plugins/__init__.py +5 -0
  39. stryx/plugins/base.py +85 -0
  40. stryx/policy/__init__.py +1 -0
  41. stryx/policy/engine.py +201 -0
  42. stryx/py.typed +0 -0
  43. stryx/reports/__init__.py +5 -0
  44. stryx/reports/generator.py +122 -0
  45. stryx/reports/json_report.py +72 -0
  46. stryx/reports/markdown_report.py +101 -0
  47. stryx/reports/sarif_report.py +200 -0
  48. stryx/reports/templates/report.html.j2 +163 -0
  49. stryx/reports/terminal_report.py +138 -0
  50. stryx/scanners/__init__.py +17 -0
  51. stryx/scanners/auth.py +444 -0
  52. stryx/scanners/authorization.py +220 -0
  53. stryx/scanners/blind.py +328 -0
  54. stryx/scanners/cloud_ssrf.py +208 -0
  55. stryx/scanners/cors.py +158 -0
  56. stryx/scanners/dependencies.py +296 -0
  57. stryx/scanners/disclosure.py +339 -0
  58. stryx/scanners/fuzz.py +391 -0
  59. stryx/scanners/graphql.py +309 -0
  60. stryx/scanners/injection.py +511 -0
  61. stryx/scanners/race.py +257 -0
  62. stryx/signatures/framework_fingerprints.yaml +122 -0
  63. stryx/signatures/known_vulns.yaml +210 -0
  64. stryx/utils/__init__.py +7 -0
  65. stryx/utils/evidence.py +109 -0
  66. stryx/utils/http_client.py +159 -0
  67. stryx/utils/logging.py +51 -0
  68. stryx/utils/rate_limiter.py +37 -0
  69. stryx_cli-0.1.0.dist-info/METADATA +236 -0
  70. stryx_cli-0.1.0.dist-info/RECORD +74 -0
  71. stryx_cli-0.1.0.dist-info/WHEEL +5 -0
  72. stryx_cli-0.1.0.dist-info/entry_points.txt +2 -0
  73. stryx_cli-0.1.0.dist-info/licenses/LICENSE +190 -0
  74. stryx_cli-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,109 @@
1
+ """Evidence and Finding data models -- the core data types for all scan results.
2
+
3
+ Every scanner MUST produce Findings with populated Evidence. This is enforced
4
+ at the data-model level: constructing a Finding without Evidence raises ValueError.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass, field
10
+ from enum import StrEnum
11
+ from typing import Any
12
+
13
+
14
+ class Severity(StrEnum):
15
+ """Severity levels for findings."""
16
+
17
+ CRITICAL = "critical"
18
+ HIGH = "high"
19
+ MEDIUM = "medium"
20
+ LOW = "low"
21
+ INFO = "info"
22
+
23
+
24
+ @dataclass
25
+ class Evidence:
26
+ """Evidence supporting a security finding.
27
+
28
+ Every Finding MUST contain a non-empty Evidence. This ensures no
29
+ heuristic-only findings are reported without supporting data.
30
+ """
31
+
32
+ request_method: str
33
+ request_url: str
34
+ request_headers: dict[str, str] = field(default_factory=dict)
35
+ request_body: str | None = None
36
+ response_status: int = 0
37
+ response_headers: dict[str, str] = field(default_factory=dict)
38
+ response_body: str = ""
39
+ response_snippet: str = ""
40
+ payload: str = ""
41
+ confidence: float = 0.0 # 0.0 to 1.0
42
+
43
+ def __post_init__(self) -> None:
44
+ if not self.request_method or not self.request_url:
45
+ raise ValueError("Evidence must have request_method and request_url")
46
+ if not self.response_snippet and self.response_body:
47
+ # Auto-generate snippet from response body
48
+ self.response_snippet = self.response_body[:500]
49
+
50
+ def to_dict(self) -> dict[str, Any]:
51
+ """Convert to dictionary for serialization."""
52
+ return {
53
+ "request_method": self.request_method,
54
+ "request_url": self.request_url,
55
+ "request_headers": self.request_headers,
56
+ "request_body": self.request_body,
57
+ "response_status": self.response_status,
58
+ "response_headers": self.response_headers,
59
+ "response_body": self.response_body[:2000], # cap for storage
60
+ "response_snippet": self.response_snippet,
61
+ "payload": self.payload,
62
+ "confidence": self.confidence,
63
+ }
64
+
65
+
66
+ @dataclass
67
+ class Finding:
68
+ """A security finding with mandatory evidence.
69
+
70
+ This is the universal output type for all scanners. No scanner may emit
71
+ a Finding without populated Evidence -- this is enforced by __post_init__.
72
+ """
73
+
74
+ title: str
75
+ severity: Severity
76
+ evidence: Evidence
77
+ description: str = ""
78
+ remediation: str = ""
79
+ cwe: str = ""
80
+ owasp: str = ""
81
+ endpoint: str = ""
82
+ scanner: str = ""
83
+ tags: list[str] = field(default_factory=list)
84
+
85
+ def __post_init__(self) -> None:
86
+ if not self.evidence:
87
+ raise ValueError(
88
+ f"Finding '{self.title}' has no evidence. "
89
+ "All findings MUST include supporting Evidence."
90
+ )
91
+ if self.evidence.confidence < 0.0 or self.evidence.confidence > 1.0:
92
+ raise ValueError("Confidence must be between 0.0 and 1.0")
93
+ if not self.endpoint:
94
+ self.endpoint = self.evidence.request_url
95
+
96
+ def to_dict(self) -> dict[str, Any]:
97
+ """Convert to dictionary for JSON serialization."""
98
+ return {
99
+ "title": self.title,
100
+ "severity": self.severity.value,
101
+ "description": self.description,
102
+ "remediation": self.remediation,
103
+ "cwe": self.cwe,
104
+ "owasp": self.owasp,
105
+ "endpoint": self.endpoint,
106
+ "scanner": self.scanner,
107
+ "tags": self.tags,
108
+ "evidence": self.evidence.to_dict(),
109
+ }
@@ -0,0 +1,159 @@
1
+ """Async HTTP client wrapper with session cookies, rate limiting, and evidence collection."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from stryx.utils.evidence import Evidence
10
+ from stryx.utils.rate_limiter import RateLimiter
11
+
12
+
13
+ class HttpClient:
14
+ """Async HTTP client with session cookie jar, rate limiting, and evidence collection.
15
+
16
+ Maintains cookies across requests (Set-Cookie responses update the jar)
17
+ so authenticated sessions persist naturally.
18
+ """
19
+
20
+ def __init__(
21
+ self,
22
+ timeout: int = 10,
23
+ proxy: str | None = None,
24
+ rate_limit: int | None = None,
25
+ headers: dict[str, str] | None = None,
26
+ cookies: str | None = None,
27
+ ):
28
+ self.timeout = timeout
29
+ self.proxy = proxy
30
+ self.base_headers = headers or {}
31
+ self.rate_limiter = RateLimiter(rate_limit) if rate_limit else None
32
+ self._cookie_jar: dict[str, str] = {}
33
+
34
+ # Parse initial cookies from string
35
+ if cookies:
36
+ for pair in cookies.split(";"):
37
+ if "=" in pair:
38
+ k, v = pair.split("=", 1)
39
+ self._cookie_jar[k.strip()] = v.strip()
40
+
41
+ def _format_cookies(self) -> str:
42
+ """Format cookie jar as Cookie header string."""
43
+ return "; ".join(f"{k}={v}" for k, v in self._cookie_jar.items())
44
+
45
+ def _update_cookies_from_response(self, response: httpx.Response) -> None:
46
+ """Extract Set-Cookie headers and update the jar."""
47
+ for cookie in response.cookies.items():
48
+ self._cookie_jar[cookie[0]] = cookie[1]
49
+
50
+ async def request(
51
+ self,
52
+ method: str,
53
+ url: str,
54
+ headers: dict[str, str] | None = None,
55
+ body: str | None = None,
56
+ json_data: dict | None = None,
57
+ cookies: dict[str, str] | None = None,
58
+ follow_redirects: bool = True,
59
+ ) -> tuple[httpx.Response, Evidence]:
60
+ """Make an HTTP request and return response with Evidence.
61
+
62
+ Cookies from the jar are sent automatically. Set-Cookie responses
63
+ update the jar for subsequent requests (session persistence).
64
+ """
65
+ if self.rate_limiter:
66
+ await self.rate_limiter.acquire()
67
+
68
+ merged_headers = dict(self.base_headers)
69
+ if headers:
70
+ merged_headers.update(headers)
71
+
72
+ # Merge explicit cookies into jar
73
+ if cookies:
74
+ self._cookie_jar.update(cookies)
75
+
76
+ request_headers = dict(merged_headers)
77
+
78
+ # Add cookies from jar
79
+ cookie_str = self._format_cookies()
80
+ if cookie_str:
81
+ merged_headers["Cookie"] = cookie_str
82
+
83
+ kwargs: dict[str, Any] = {
84
+ "timeout": httpx.Timeout(self.timeout),
85
+ "follow_redirects": follow_redirects,
86
+ "verify": False,
87
+ }
88
+ if self.proxy:
89
+ kwargs["proxy"] = self.proxy
90
+
91
+ try:
92
+ async with httpx.AsyncClient(**kwargs) as client:
93
+ response = await client.request(
94
+ method=method,
95
+ url=url,
96
+ headers=merged_headers,
97
+ content=body,
98
+ json=json_data,
99
+ )
100
+
101
+ # Update cookie jar from response
102
+ self._update_cookies_from_response(response)
103
+
104
+ response_headers = dict(response.headers)
105
+ response_text = response.text
106
+
107
+ evidence = Evidence(
108
+ request_method=method,
109
+ request_url=url,
110
+ request_headers=request_headers,
111
+ request_body=body,
112
+ response_status=response.status_code,
113
+ response_headers=response_headers,
114
+ response_body=response_text,
115
+ response_snippet=response_text[:500],
116
+ confidence=0.0,
117
+ )
118
+ return response, evidence
119
+
120
+ except httpx.RequestError as e:
121
+ evidence = Evidence(
122
+ request_method=method,
123
+ request_url=url,
124
+ request_headers=request_headers,
125
+ request_body=body,
126
+ response_status=0,
127
+ response_body=str(e),
128
+ response_snippet=str(e)[:500],
129
+ confidence=0.0,
130
+ )
131
+ error_response = httpx.Response(
132
+ status_code=0,
133
+ request=httpx.Request(method=method, url=url),
134
+ )
135
+ return error_response, evidence
136
+
137
+ async def get(self, url: str, **kwargs: Any) -> tuple[httpx.Response, Evidence]:
138
+ """Send GET request."""
139
+ return await self.request("GET", url, **kwargs)
140
+
141
+ async def post(self, url: str, **kwargs: Any) -> tuple[httpx.Response, Evidence]:
142
+ """Send POST request."""
143
+ return await self.request("POST", url, **kwargs)
144
+
145
+ async def put(self, url: str, **kwargs: Any) -> tuple[httpx.Response, Evidence]:
146
+ """Send PUT request."""
147
+ return await self.request("PUT", url, **kwargs)
148
+
149
+ async def delete(self, url: str, **kwargs: Any) -> tuple[httpx.Response, Evidence]:
150
+ """Send DELETE request."""
151
+ return await self.request("DELETE", url, **kwargs)
152
+
153
+ async def head(self, url: str, **kwargs: Any) -> tuple[httpx.Response, Evidence]:
154
+ """Send HEAD request."""
155
+ return await self.request("HEAD", url, **kwargs)
156
+
157
+ async def patch(self, url: str, **kwargs: Any) -> tuple[httpx.Response, Evidence]:
158
+ """Send PATCH request."""
159
+ return await self.request("PATCH", url, **kwargs)
stryx/utils/logging.py ADDED
@@ -0,0 +1,51 @@
1
+ """Logging configuration for STRYX using Rich."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+
7
+ from rich.console import Console
8
+ from rich.logging import RichHandler
9
+ from rich.theme import Theme
10
+
11
+ # Custom theme for STRYX
12
+ STRYX_THEME = Theme({
13
+ "info": "cyan",
14
+ "warning": "yellow",
15
+ "error": "bold red",
16
+ "critical": "bold white on red",
17
+ "success": "bold green",
18
+ "severity.critical": "bold red",
19
+ "severity.high": "red",
20
+ "severity.medium": "yellow",
21
+ "severity.low": "blue",
22
+ "severity.info": "dim",
23
+ })
24
+
25
+ console = Console(theme=STRYX_THEME)
26
+
27
+
28
+ def setup_logging(level: str = "INFO") -> logging.Logger:
29
+ """Configure Rich-based logging for STRYX."""
30
+ logger = logging.getLogger("stryx")
31
+ if logger.handlers:
32
+ return logger
33
+
34
+ logger.setLevel(getattr(logging, level.upper(), logging.INFO))
35
+
36
+ handler = RichHandler(
37
+ console=console,
38
+ show_path=False,
39
+ show_time=True,
40
+ markup=True,
41
+ rich_tracebacks=True,
42
+ )
43
+ handler.setFormatter(logging.Formatter("%(message)s"))
44
+ logger.addHandler(handler)
45
+
46
+ return logger
47
+
48
+
49
+ def get_logger(name: str = "stryx") -> logging.Logger:
50
+ """Get a named logger under the stryx namespace."""
51
+ return logging.getLogger(f"stryx.{name}" if name != "stryx" else "stryx")
@@ -0,0 +1,37 @@
1
+ """Async rate limiter for controlling request frequency."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import time
7
+ from collections import deque
8
+
9
+
10
+ class RateLimiter:
11
+ """Token-bucket style async rate limiter.
12
+
13
+ Limits to `max_requests` requests per `window_seconds` period.
14
+ """
15
+
16
+ def __init__(self, max_requests: int = 20, window_seconds: float = 1.0):
17
+ self.max_requests = max_requests
18
+ self.window_seconds = window_seconds
19
+ self._timestamps: deque[float] = deque()
20
+ self._lock = asyncio.Lock()
21
+
22
+ async def acquire(self) -> None:
23
+ """Wait until a request slot is available."""
24
+ async with self._lock:
25
+ now = time.monotonic()
26
+ # Remove expired timestamps
27
+ while self._timestamps and self._timestamps[0] <= now - self.window_seconds:
28
+ self._timestamps.popleft()
29
+
30
+ if len(self._timestamps) >= self.max_requests:
31
+ # Wait until the oldest request expires
32
+ wait_time = self._timestamps[0] + self.window_seconds - now
33
+ if wait_time > 0:
34
+ await asyncio.sleep(wait_time)
35
+ self._timestamps.popleft()
36
+
37
+ self._timestamps.append(time.monotonic())
@@ -0,0 +1,236 @@
1
+ Metadata-Version: 2.4
2
+ Name: stryx-cli
3
+ Version: 0.1.0
4
+ Summary: AI-Powered Dynamic Application Security Testing (DAST) -- part of the MEDUSA security platform
5
+ Author-email: Akhilesh Varma <akhverm@gmail.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/Medusa-Security/stryx
8
+ Project-URL: Repository, https://github.com/Medusa-Security/stryx
9
+ Project-URL: Issues, https://github.com/Medusa-Security/stryx/issues
10
+ Project-URL: Documentation, https://github.com/Medusa-Security/stryx/blob/main/docs/USAGE.md
11
+ Project-URL: Changelog, https://github.com/Medusa-Security/stryx/blob/main/CHANGELOG.md
12
+ Keywords: security,dast,dynamic-analysis,vulnerability-scanner,penetration-testing,web-security,api-security,owasp,sast,application-security
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Information Technology
16
+ Classifier: License :: OSI Approved :: Apache Software License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Security
23
+ Classifier: Topic :: Software Development :: Testing
24
+ Classifier: Topic :: System :: Networking
25
+ Classifier: Framework :: AsyncIO
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.11
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: click<9,>=8.1
31
+ Requires-Dist: rich<14,>=13.0
32
+ Requires-Dist: httpx[socks]<1,>=0.25
33
+ Requires-Dist: pydantic<3,>=2.0
34
+ Requires-Dist: pyyaml<7,>=6.0
35
+ Requires-Dist: jinja2<4,>=3.1
36
+ Requires-Dist: openai<2,>=1.0
37
+ Requires-Dist: anthropic<1,>=0.25
38
+ Requires-Dist: groq<1,>=0.4
39
+ Provides-Extra: dev
40
+ Requires-Dist: pytest>=7.0; extra == "dev"
41
+ Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
42
+ Requires-Dist: black>=23.0; extra == "dev"
43
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
44
+ Requires-Dist: fastapi>=0.100; extra == "dev"
45
+ Requires-Dist: uvicorn>=0.20; extra == "dev"
46
+ Requires-Dist: respx>=0.21; extra == "dev"
47
+ Provides-Extra: xml
48
+ Requires-Dist: lxml<6,>=4.9; extra == "xml"
49
+ Provides-Extra: all
50
+ Requires-Dist: stryx[xml]; extra == "all"
51
+ Dynamic: license-file
52
+
53
+ # STRYX
54
+
55
+ **AI-Powered Dynamic Application Security Testing (DAST)**
56
+
57
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
58
+ [![Python Version](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
59
+ [![Build Status](https://github.com/medusa-Security/stryx/actions/workflows/ci.yml/badge.svg)](https://github.com/medusa-Security/stryx/actions)
60
+
61
+ STRYX is a developer-first, AI-assisted DAST engine that crawls, maps, and tests the live attack surface of web applications. It discovers hidden endpoints, simulates real attacker behavior, and detects exploitable vulnerabilities with minimal false positives. Every finding carries full evidence (request, response, status code, payload, confidence score) -- no heuristic-only results.
62
+
63
+ **Design philosophy: high signal, low noise.**
64
+
65
+ ## How It Fits Into MEDUSA
66
+
67
+ - **Remy** -- SAST, analyzes source code pre-deployment.
68
+ - **STRYX** -- DAST, validates a running application's live attack surface and exploitability.
69
+ - **MEDUSA** -- Aggregates findings from both, correlates static and runtime issues, estimates business impact, provides centralized security management.
70
+
71
+ ## Architecture
72
+
73
+ ```
74
+ CLI -> Configuration -> Attack Orchestrator -> { Endpoint Discovery }
75
+ |
76
+ Authentication Engine
77
+ Authorization Engine
78
+ Injection Engine
79
+ API Fuzzer
80
+ AI Attack Planner
81
+ Evidence Collector
82
+ Report Generator
83
+ |
84
+ Target Application
85
+ ```
86
+
87
+ ## Installation
88
+
89
+ ```bash
90
+ # From PyPI
91
+ pip install stryx
92
+
93
+ # From source
94
+ git clone https://github.com/medusa-Security/stryx.git
95
+ cd stryx
96
+ pip install -e .
97
+ ```
98
+
99
+ ## Quickstart
100
+
101
+ ```bash
102
+ # Run a full scan
103
+ stryx scan http://localhost:8000
104
+
105
+ # Output:
106
+ # STRYX Scan Results
107
+ # Target: http://localhost:8000
108
+ # Total Findings: 3
109
+ # Breakdown: CRITICAL: 1 | HIGH: 1 | MEDIUM: 1
110
+ ```
111
+
112
+ ## Core Modules
113
+
114
+ | Module | Purpose |
115
+ |--------|---------|
116
+ | Endpoint Discovery | Crawls targets, extracts APIs from OpenAPI/Swagger, sitemaps, JS files, GraphQL |
117
+ | Authentication Scanner | Tests missing auth, weak JWTs, session fixation, cookie security |
118
+ | Authorization Scanner | Tests IDOR, privilege escalation, admin access, multi-tenant escape |
119
+ | Injection Engine | SQL, NoSQL, command, SSRF, path traversal, XXE, SSTI, LDAP injection |
120
+ | API Fuzzer | Parameter mutation, boundary values, type confusion, nested JSON |
121
+ | CORS Scanner | Detects misconfigured CORS policies and origin reflection |
122
+ | GraphQL Scanner | Tests introspection exposure, query depth limiting |
123
+ | AI Attack Planner | Constructs multi-step attack chains across findings |
124
+ | Evidence Engine | Enforces evidence requirements on every finding |
125
+
126
+ ## CLI Reference
127
+
128
+ ### Commands
129
+
130
+ | Command | Description |
131
+ |---------|-------------|
132
+ | `stryx scan <url>` | Run full security scan |
133
+ | `stryx crawl <url>` | Crawl and discover endpoints |
134
+ | `stryx auth <url>` | Run authentication tests |
135
+ | `stryx fuzz <url>` | Run API fuzzing tests |
136
+ | `stryx report <url>` | Generate reports |
137
+ | `stryx config` | View/update configuration |
138
+ | `stryx providers` | List supported AI providers |
139
+ | `stryx update` | Update STRYX |
140
+
141
+ ### Flags
142
+
143
+ | Flag | Description |
144
+ |------|-------------|
145
+ | `--deep` | Enable deep scanning |
146
+ | `--json <file>` | Output JSON report |
147
+ | `--html <file>` | Output HTML report |
148
+ | `--markdown <file>` | Output Markdown report |
149
+ | `--threads <n>` | Concurrent threads (1-200) |
150
+ | `--timeout <s>` | HTTP timeout in seconds |
151
+ | `--headers <json>` | Custom headers |
152
+ | `--cookies <str>` | Authentication cookies |
153
+ | `--proxy <url>` | HTTP proxy |
154
+ | `--wordlist <file>` | Custom wordlist |
155
+ | `--rate <n>` | Requests per second limit |
156
+
157
+ ## Configuration
158
+
159
+ ```yaml
160
+ provider: groq
161
+ model: llama-3.3-70b-versatile
162
+ threads: 20
163
+ timeout: 10
164
+ crawl_depth: 5
165
+ respect_robots: false
166
+ ai_attack_planning: true
167
+ modules:
168
+ auth: true
169
+ authorization: true
170
+ injection: true
171
+ fuzzing: true
172
+ ```
173
+
174
+ Supported AI providers: Groq, OpenAI, Anthropic, OpenRouter, Ollama, XAI, NVIDIA NIM.
175
+
176
+ ## Sample Report
177
+
178
+ ```
179
+ +--------------------------------------------------------------------+
180
+ | STRYX Scan Results |
181
+ | Target: http://localhost:8000 |
182
+ | Total Findings: 3 |
183
+ | Breakdown: CRITICAL: 1 | HIGH: 1 | MEDIUM: 1 |
184
+ +--------------------------------------------------------------------+
185
+
186
+ [#] [CRITICAL] Unauthenticated access to /admin
187
+ Endpoint: http://localhost:8000/admin
188
+ CWE: CWE-306 | Scanner: auth
189
+ Confidence: 70%
190
+ Evidence: GET http://localhost:8000/admin -> 200
191
+ ```
192
+
193
+ ## Roadmap
194
+
195
+ ### v0.1 (this build)
196
+
197
+ - [ ] HTTP crawler
198
+ - [ ] Endpoint discovery
199
+ - [ ] Authentication scanning
200
+ - [ ] Authorization testing
201
+ - [ ] Basic injection testing
202
+ - [ ] JSON/HTML reports
203
+
204
+ ### v0.5
205
+
206
+ - [ ] Browser automation
207
+ - [ ] GraphQL support
208
+ - [ ] Multi-threaded fuzzing
209
+ - [ ] AI attack planning
210
+ - [ ] Custom payloads
211
+ - [ ] Plugin SDK
212
+
213
+ ### v1.0
214
+
215
+ - [ ] Autonomous attack chaining
216
+ - [ ] Headless browser exploitation
217
+ - [ ] CI/CD integration
218
+ - [ ] Distributed scanning
219
+ - [ ] Cloud dashboards (MEDUSA integration)
220
+ - [ ] AI-powered exploit reasoning
221
+
222
+ ## Contributing
223
+
224
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
225
+
226
+ ## Security Policy
227
+
228
+ See [SECURITY.md](SECURITY.md) for reporting vulnerabilities in STRYX itself.
229
+
230
+ ## License
231
+
232
+ Apache License 2.0. See [LICENSE](LICENSE).
233
+
234
+ ## Author
235
+
236
+ Built by Akhilesh Varma (ak495867) under Medusa Security.
@@ -0,0 +1,74 @@
1
+ stryx/__init__.py,sha256=S_izSu_FrzL4EFF0E2_Nd_hNYoTBgxL4zpdAVygT55A,1156
2
+ stryx/cli.py,sha256=Et1hU9UhYQVTYkmaYs6kqhHrlgM0LmQQg3TvGyiLDl8,24111
3
+ stryx/orchestrator.py,sha256=hdERxQQ64MR-7nZHeHqI0s854yARRj04sGuIKIFkm_0,13485
4
+ stryx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ stryx/ai/__init__.py,sha256=N4agk2G5KbVO9_uGLJyzjkGVIOOzmv-McDCYFY7fKhc,132
6
+ stryx/ai/attack_planner.py,sha256=BhEo3EtyZDEreHPulysJYC6E6aHusrXJ3XufghNFzgI,7331
7
+ stryx/ai/payload_generator.py,sha256=F88a9nHzCXkIhnVXhJdM4PA655Mhx4FwnP2q7Z9oH7U,6705
8
+ stryx/ai/prompts.py,sha256=Ip8tvSygFDfZeXjewxCoa39PJ93JnndzNAlAnoZSq-Y,2931
9
+ stryx/ai/providers.py,sha256=bO5tbN0wriRUGwlJCqYSFfVnExIW31vyp3xxHTbuJFM,9067
10
+ stryx/attacks/__init__.py,sha256=O44X9KOBHdXnFbpakiZihAncrrSqmiJ-fxeRdoH6sHQ,193
11
+ stryx/attacks/attack_chain.py,sha256=0zHEAAbeMiKty5SleVTJv9cE_VJBpkG2mRxE87r0Jh0,4123
12
+ stryx/attacks/replay.py,sha256=wbNFPv1ZswXxAnbKkvfuwIytOgPY8wxyTB7SrYaz0Fc,7024
13
+ stryx/auth/__init__.py,sha256=QgMP1kRWoVXpyzJzQaR6bsLOi5w8_fyckwUanAALE5k,55
14
+ stryx/auth/session_manager.py,sha256=wtXoabxwe_hJ9YdVZh9jj_kSa8I2-CRAK9YjrtdFSnM,12803
15
+ stryx/comparison/__init__.py,sha256=sGfy6rwPOo9bd5oV0Rs2KDPKYBS6Ehr4FXHknyY3a_Y,67
16
+ stryx/comparison/differ.py,sha256=koUzauoMiZifVyDpnPXhvXUEJlwTXsUZ--l0n9rOe18,8895
17
+ stryx/config/__init__.py,sha256=R_mHNoQOEqY61KAnI-btysnSzpBm4_rwayR11DwgKAY,219
18
+ stryx/config/default_config.yaml,sha256=HkaAX1F5QL1xM1lrvIdbL95kMDG8HKGXMFqQA6ypPuI,206
19
+ stryx/config/loader.py,sha256=KSgzJO03-xAzBJXKXhWO4-ytAu6Oj2RI4VDdkW_Mg7U,3864
20
+ stryx/config/schema.py,sha256=LtBY0oT0DbHorcGgjk8GdxCb8DedUWkpXediOewdX7s,2642
21
+ stryx/crawler/__init__.py,sha256=7aX59WiOKvIJhiu-IviCvUSEyjpTBfoBDY48U0i8BzE,171
22
+ stryx/crawler/discovery.py,sha256=BwgRNpcY7mBajldqIIV5bVBat29T7BVRRE5BiqZizxU,6223
23
+ stryx/crawler/graphql_discovery.py,sha256=wJfK_QSjFkkKLUPWxJsRmhmxV2g33ndNfJH7gstVOMU,2590
24
+ stryx/crawler/html_crawler.py,sha256=DGkPucwBX3xkqpX1t9YzEVJJqyo-TP-1eDj_zZhBVF0,10395
25
+ stryx/crawler/js_endpoints.py,sha256=AVKrS5m-D636xGgYxXAgWveVk8ulGFJ-pB25qy3Fp8I,6463
26
+ stryx/crawler/openapi.py,sha256=tus4jYhezh9pItFHXshEiwKwfRlo61NErUZLf47YSxA,2466
27
+ stryx/crawler/sitemap.py,sha256=yiR1i2DnYrFeNuzk-gfTFr0DSzSEOWVdL_8SOFCXRak,3214
28
+ stryx/payloads/cmdi.txt,sha256=hMMuUgc2_aOOPEEegyAXN4q_fvEh-I0k6HHbZFKteow,462
29
+ stryx/payloads/header_injection.txt,sha256=mohHBpMdv6xGWDn62SzS3gXMdmX4Oow7rbTbzAc1AXI,599
30
+ stryx/payloads/ldap.txt,sha256=FvyGR4mUbl6wpWkCWLUPp237nS8pLLs5pc5-IhOOwNY,351
31
+ stryx/payloads/nosqli.txt,sha256=hpBlSHImpoLRErpk5JPLC8v0x-CjSgppPHrJHUf6mBU,617
32
+ stryx/payloads/open_redirect.txt,sha256=AkudcGqfeLxA37_l0mr-QNbqh3mXHjPGF2CpvaYTMVE,424
33
+ stryx/payloads/path_traversal.txt,sha256=sTld--0__8f_QPvAdbMt3zK9sMXx-rJSLjdVg6DMV_c,647
34
+ stryx/payloads/sqli.txt,sha256=ctDMdoakCn8WbIqkBIcopZLtUcrerEtObxyaOd_-j4c,936
35
+ stryx/payloads/ssrf.txt,sha256=sfXyI856nZ4_udEr6OuJmMOM_1JJ_dAAZMXTTY3jO7Q,637
36
+ stryx/payloads/ssti.txt,sha256=x4g7N8KGp0MJXmO3pWYwcYTyjRwDITkxnt9OqKvMkvM,813
37
+ stryx/payloads/xss.txt,sha256=Co0_Q7H9VDj4Ahem7QQriqmZ12VXTP4QtU5vhLBLvf0,1814
38
+ stryx/payloads/xxe.txt,sha256=NkzyZ3aHjMK6Osf4zbhwMkKmMGoHksgZQh3Gz_Oq5Vg,1395
39
+ stryx/plugins/__init__.py,sha256=ypeTW9tc68QqwcnpG09_xl2w6W2Zt6nYsJfP73gVFE0,178
40
+ stryx/plugins/base.py,sha256=6Wz7HR2gUk5p1a37FV2iiFdsm4qgKhdiys12i51WqN4,2335
41
+ stryx/policy/__init__.py,sha256=qoY4uVnwSqVw7bjo8t6st54i8NXizsek714KzseNj0M,45
42
+ stryx/policy/engine.py,sha256=mEOVlF15mQ2EFDvjW-KwxMqGZ47ICNRIj6GA9bGt5Y8,6733
43
+ stryx/reports/__init__.py,sha256=jUHz6kg7J_5h78SAS71FAWUFZ-PTqp09SEaDfgGImFM,127
44
+ stryx/reports/generator.py,sha256=Z7iZJVvYYexj8y6M947rH2cHWPhlvAkfALlT3dielqI,4245
45
+ stryx/reports/json_report.py,sha256=L2dFNkuXImvEN66EreYuMmIs-wdp-ELPp4sbLFZloko,2458
46
+ stryx/reports/markdown_report.py,sha256=oYthgmWR25gJR_j7CqJQ6CUqhfWAgVNAD_J3LkRVmsw,3750
47
+ stryx/reports/sarif_report.py,sha256=FavrrnlppE1Ke4093kRl0dVYDsDscgiXtGWmfeBoPI8,6910
48
+ stryx/reports/terminal_report.py,sha256=fsl634ZLrC5X8QLemmVv_NQa9XoNyKo_AQL_sEp37Oo,4893
49
+ stryx/reports/templates/report.html.j2,sha256=UD3YAdly4uJKCXO3ro2tAm083cjZVSPw6R-UIEjYKuw,8480
50
+ stryx/scanners/__init__.py,sha256=0Hmecn71GmRO3Di53ty4IrZE_6jB43GWOWndUnY-8_Q,478
51
+ stryx/scanners/auth.py,sha256=xh51nxCl9a8CXP3qEbf7JUdIDsB2a-Qzf1tOo_oYmec,17078
52
+ stryx/scanners/authorization.py,sha256=Hl_I2LmlPfpVgp4ZIcVA1nk72qcBqp_SLBssF235rmQ,8113
53
+ stryx/scanners/blind.py,sha256=M3h3ELkefwbpkqv0dUTzJn3P63_TyUvxgva1fzGpPEU,14009
54
+ stryx/scanners/cloud_ssrf.py,sha256=McINdyoaKRYu5Hv3yOxKFk_ppissdiQV0N5GfChNNDk,8137
55
+ stryx/scanners/cors.py,sha256=Y5PC6lrLtwpYi3mVsHgF3aipDbGIBXPq9xBGhNRWzTw,5869
56
+ stryx/scanners/dependencies.py,sha256=V1ly0-3TsQYA4LcVLdvDm2Zvr7CkizCUlQxzeBcET5k,12191
57
+ stryx/scanners/disclosure.py,sha256=FWjYgUoSRTKkosTmT8Pygi0xqoSkrs4aJ82Ys1QfhaU,15342
58
+ stryx/scanners/fuzz.py,sha256=vkrSDmFtiymUPTm1g_42kCsl9jp2BoCqc9i40I5SJiI,15279
59
+ stryx/scanners/graphql.py,sha256=Ux71PFtPfF_IREdvOYH7vSdkgSRqkH6wF9tmm7EZtsU,12244
60
+ stryx/scanners/injection.py,sha256=Xoi0BUNMXTX4_wSlYg9gPgcR3F5Wcdw-AW7_ujw0y8o,19129
61
+ stryx/scanners/race.py,sha256=lTX1utTq8Fd78YfEN6jOBKdTZcAEOkFJbq8pIPR2gu4,9894
62
+ stryx/signatures/framework_fingerprints.yaml,sha256=pdh_upEFMh7trgRCkqDHeN7aiPDLX5mN8iUgpN5qBcw,2479
63
+ stryx/signatures/known_vulns.yaml,sha256=WW4hqJKHp-E-MGK3RcjcW2_tYIBCnpxsybe7xiYya3g,6309
64
+ stryx/utils/__init__.py,sha256=43l-UFX8ifc9dF7DSRUoMyD1kSxqCQRnLjyd-sL3f70,245
65
+ stryx/utils/evidence.py,sha256=WbcqPh_GKbuEibP97qKL8jiy6nYj02ulMBQ4W5efAZA,3598
66
+ stryx/utils/http_client.py,sha256=Mmd2OLGwwPxqdf8D4aDzLttzgpunEKDyUgdR3d8kyOY,5612
67
+ stryx/utils/logging.py,sha256=ttmZBCrBO9HEfxyH4_IoFRoKZpPx2kRIPVKZauYoeNs,1304
68
+ stryx/utils/rate_limiter.py,sha256=L6H_xq-KYapoh4WRpOK08gT-irRnNKbj2Dcy138QXic,1251
69
+ stryx_cli-0.1.0.dist-info/licenses/LICENSE,sha256=Ey3jWLx-ooBQMHASeVds3kmg6D6Ecakbg76Sev2_bPc,10765
70
+ stryx_cli-0.1.0.dist-info/METADATA,sha256=jiNW8yYaDXNabi5-e6b2fKaMlZrtQVN3efIR4giXTh4,8345
71
+ stryx_cli-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
72
+ stryx_cli-0.1.0.dist-info/entry_points.txt,sha256=yD7annfJT3nYuGQAQ2LmhByIZtTcl68xGXgH3eX7vaQ,41
73
+ stryx_cli-0.1.0.dist-info/top_level.txt,sha256=IAEyYP-Fs3MI8cybsIUFdFESepI90IKy7xqmkabIyzI,6
74
+ stryx_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ stryx = stryx.cli:main