Pentest Script Generator — SOP (Strix-native v2)
Generate two professional Python scripts for each vuln-XXXX.md report.
Updated from analysis of 196 real-world vulnerabilities.
Language rule: All skill instructions and generated script code use English.
Final summary presented to the user must be in Vietnamese.
Step 1 — Parse vuln-XXXX.md (Strix schema)
Schema produced by tracer.py → create_vulnerability_report():
# <title>
**ID:** vuln-XXXX
**Severity:** CRITICAL | HIGH | MEDIUM | LOW
**Found:** <ISO timestamp UTC>
**Target:** <base URL>
**Endpoint:** <path> ← optional
**Method:** <HTTP method> ← optional
**CVE:** CVE-YYYY-NNNNN ← optional
**CWE:** CWE-NNN ← optional
**CVSS:** <float>
## Description
## Impact
## Technical Analysis
## Proof of Concept
<poc_description>
```<poc_script_code — ALWAYS PRESENT>```
## Code Analysis ← optional, whitebox
## Remediation
Key rule: poc_script_code is always present — use it as the primary source for test logic.
If Endpoint is missing → extract from Technical Analysis or PoC code.
Step 2 — Identify vulnerability type
Authorization / Access Control
| Type |
Trigger Keywords |
TC Pattern |
| BFLA |
admin endpoint, non-admin users can access, BFLA |
Low-priv token → admin route |
| IDOR/BOLA |
cross-user, order id, user_id param |
Swap resource ID to another user |
| Unauth API |
unauthenticated access, no auth required |
Request with no Authorization header |
| Supabase PostgREST |
anon apikey, PostgREST, RLS bypass |
Call REST with public apikey |
| Firestore Rules |
Firestore, RLS misconfiguration |
Read/write with anonymous user |
| Unauth Order Ops |
order cancellation, order status |
GET/POST order endpoint without token |
Business Logic
| Type |
Trigger Keywords |
TC Pattern |
| Price Tampering |
price tampering, client-side price |
POST order with price=1 |
| Payment Bypass |
payment bypass, free license, paid without |
Create order, skip payment step |
| Negative Total |
negative totals, wallet credit |
Send negative amount |
| Rounding Error |
rounding error, free credit |
Try decimal edge-case values |
| Rate Limit Bypass |
X-Forwarded-For, IP spoofing |
Add X-Forwarded-For: 1.2.3.X header |
| OTP Brute Force |
missing OTP brute-force protection |
Send many wrong OTPs in sequence |
| Registration Farming |
unlimited trial, credit farming |
Create multiple accounts for trial |
Injection / XSS
| Type |
Trigger Keywords |
TC Pattern |
| Stored XSS |
stored xss, innerHTML, marked.parse |
Upload payload with unique marker |
| DOM XSS |
DOM-based, innerHTML, url param |
Playwright + javascript: URL |
| Reflected XSS |
reflected xss, POST body reflection |
GET/POST with payload in param |
| JSONP Injection |
JSONP callback, arbitrary JS |
Call callback with random function name |
| Script Injection |
installer script, key parameter |
Send bash command substitution payload |
| SQLi |
SQL injection, remember_token cookie |
SQLi payload via cookie/param |
SSRF
| Type |
Trigger Keywords |
TC Pattern |
| Blind SSRF |
blind SSRF, OAST, webhook |
Send webhook.site domain |
| SSRF IMDS |
cloud metadata, IMDS, 169.254 |
Send http://169.254.169.254/ |
| SSRF Internal |
internal network, port scanning |
Send 127.0.0.1.nip.io variants |
| SSRF xmlrpc |
wordpress xmlrpc, pingback |
POST xmlrpc.php with internal URL |
Account Takeover
| Type |
Trigger Keywords |
TC Pattern |
| Password Reset Leak |
plaintext password, password in response |
POST forgot-password → check response for password field |
| Account Enumeration |
differential error, user enumeration |
Try existing vs non-existing email, compare response |
| Session Fixation |
PHPSESSID not rotated, session fixation |
Capture session before login, verify PHPSESSID changes after |
| Token Not Revoked |
token remains valid after logout |
Logout → replay old token on API |
| OTP Disclosed |
OTP in response, OTP disclosed |
POST forgot → check response for OTP field |
| Default Credentials |
default credentials, admin:admin |
Login with default credential pairs |
CORS / Cookie
| Type |
Trigger Keywords |
TC Pattern |
| CORS Arbitrary Origin |
arbitrary origin reflection, CORS misconfiguration |
Send Origin: https://evil.com, check Access-Control-Allow-Origin |
| Cookie Missing Secure |
missing Secure flag, session cookie HTTP |
Send HTTP request, check Set-Cookie flags |
| CSRF |
CSRF, state-changing GET |
Send request without CSRF token |
Information Disclosure
| Type |
Trigger Keywords |
TC Pattern |
| Source Map |
sourcemap, sourcesContent |
GET .js.map file, check sourcesContent |
| Hardcoded Key in JS |
hardcoded API key, JS bundle |
Fetch JS file, grep for key patterns |
| Laravel Debug |
Laravel debug, stack trace, Ignition |
GET endpoint with Accept: text/html |
| Vite Dev Server |
Vite dev server, /@fs |
GET /@vite/client, /@fs/etc/passwd |
| Backup Archive |
backup archive, .zip, .sql dump |
GET /htdocs.zip, /backup.sql |
| phpinfo Exposure |
phpinfo, /info.php |
GET /info.php |
Infrastructure
| Type |
Trigger Keywords |
TC Pattern |
| Cloudflare Origin Bypass |
origin exposure, WAF bypass |
Resolve subdomain, call origin IP directly |
| Exposed DB |
exposed MySQL, MariaDB, Redis public |
Check open ports, read banner |
| Kubernetes Exposed |
Kubernetes API, TCP/6443 |
GET /version, /healthz |
| WordPress User Enum |
WordPress REST API, user enumeration |
GET /wp-json/wp/v2/users |
Step 3 — Identify auth mechanism
| PoC Signal |
Auth Type |
How to obtain |
Authorization: Bearer eyJ... |
JWT |
register → login → access_token |
apikey= or x-api-key |
API Key |
From config/profile endpoint |
Supabase anon key |
Supabase anon |
From JS bundle or network tab |
Cookie PHPSESSID / session |
PHP session |
Login form → capture cookie |
recaptchaToken: "" |
reCAPTCHA bypass |
Send empty string |
| No token in PoC |
Unauthenticated |
No Authorization header needed |
X-Forwarded-For |
Rate limit bypass |
Add spoofed IP header |
Step 4 — Standard code template (use for all pentest scripts)
#!/usr/bin/env python3
"""
============================================================================
Penetration Test Script — vuln-XXXX — <title>
Target : <target>
Severity : <SEVERITY> | CVSS: <score>
CWE : <CWE-NNN>
============================================================================
Description: <1-2 sentences>
Test Cases:
TC-01: ...
TC-0N: Cleanup
Usage:
pip install requests colorama
python pentest_TYPE_vulnXXXX.py [--base-url URL] [--dry-run] [--output-dir DIR]
⚠️ RUN ONLY ON AUTHORIZED TEST TARGETS ⚠️
============================================================================
"""
import argparse, json, os, time, sys
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Any, Optional
try:
import requests; from requests.exceptions import RequestException
except ImportError:
print("[!] pip install requests"); sys.exit(1)
try:
from colorama import Fore, Style, init as colorama_init; colorama_init(autoreset=True)
except ImportError:
class _Stub:
def __getattr__(self, _): return ""
Fore = Style = _Stub()
class Verdict(Enum):
VULN="VULNERABLE"; SAFE="SAFE"; ERROR="ERROR"; INFO="INFO"; SKIP="SKIPPED"
@dataclass
class TestResult:
test_id: str; name: str; verdict: Verdict
status_code: Optional[int]=None; detail: str=""
response_preview: str=""; raw_response: Any=None
timestamp: str=field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
def _print_result(r: TestResult):
c={Verdict.VULN:Fore.RED,Verdict.SAFE:Fore.GREEN,Verdict.ERROR:Fore.YELLOW,
Verdict.INFO:Fore.BLUE,Verdict.SKIP:Fore.WHITE}.get(r.verdict,"")
i={Verdict.VULN:"✗ VULNERABLE",Verdict.SAFE:"✓ SAFE",Verdict.ERROR:"⚠ ERROR",
Verdict.INFO:"ℹ INFO",Verdict.SKIP:"⊘ SKIPPED"}.get(r.verdict,"?")
print(f"\n{c}[{r.test_id}] {r.name}\n Result : {i}")
if r.status_code: print(f" HTTP : {r.status_code}")
if r.detail: print(f" Detail : {r.detail}")
if r.response_preview: print(f" Response: {r.response_preview[:300]}")
def _summary(results, vuln_id):
v=sum(1 for r in results if r.verdict==Verdict.VULN)
s=sum(1 for r in results if r.verdict==Verdict.SAFE)
e=sum(1 for r in results if r.verdict==Verdict.ERROR)
print(f"\n{'═'*68}\n SUMMARY — {vuln_id}")
for r in results:
c=Fore.RED if r.verdict==Verdict.VULN else Fore.GREEN if r.verdict==Verdict.SAFE \
else Fore.YELLOW if r.verdict==Verdict.ERROR else Fore.BLUE
print(f" {c}[{r.verdict.value:12s}] {r.test_id}: {r.name}")
print(f"\n Vulnerable: {v} | Safe: {s} | Error: {e}")
if v: print(f"\n {Fore.RED}⚠ CONCLUSION: VULNERABILITY CONFIRMED ({v} endpoint(s))")
def _export(results, vuln_id, target, output_dir):
os.makedirs(output_dir, exist_ok=True)
p = os.path.join(output_dir, f"pentest_{vuln_id}_report.json")
with open(p,"w",encoding="utf-8") as f:
json.dump({"vulnerability_id":vuln_id,"target":target,
"timestamp":datetime.now(timezone.utc).isoformat(),
"summary":{"total":len(results),
"vulnerable":sum(1 for r in results if r.verdict==Verdict.VULN),
"safe":sum(1 for r in results if r.verdict==Verdict.SAFE)},
"results":[{"test_id":r.test_id,"name":r.name,"verdict":r.verdict.value,
"status_code":r.status_code,"detail":r.detail,
"raw_response":r.raw_response,"timestamp":r.timestamp}
for r in results]},f,indent=2,ensure_ascii=False,default=str)
print(f"\n {Fore.CYAN}📄 Report: {p}")
Step 5 — TC patterns by vulnerability type
BFLA / IDOR
TC-01: Register test account (recaptchaToken="" if bypass available)
TC-02: Login → capture JWT access_token
TC-03: Decode JWT → confirm role = "user"
TC-04: Call admin endpoint with user token → expect 403; 200 = VULNERABLE
TC-05: Control: call properly-enforced endpoint → confirm 403
TC-06: (IDOR) Swap resource ID to another user's resource
TC-07: Cleanup
Unauthenticated API / Supabase
TC-01: GET endpoint with NO Authorization header → expect 401/403; 200 = VULNERABLE
TC-02: GET with valid token → expect 200 (confirm endpoint functions)
TC-03: GET with invalid token → expect 401
# Supabase variant:
TC-01: GET /rest/v1/{table} with header "apikey: <anon_key>" → inspect returned data
TC-02: No apikey header → expect 401
Business Logic — Price Tampering
TC-01: Create order with original price → expect success (baseline)
TC-02: Create order with price=1 (tampered) → if success = VULNERABLE
TC-03: Create order with price=-1 (negative) → observe response
TC-04: Cleanup — cancel created orders
Business Logic — Payment Bypass
TC-01: Check if confirm-payment endpoint requires valid payment token
TC-02: POST confirm with arbitrary order_id → expect 403/404; 200 = VULNERABLE
TC-03: Check order status after confirm
TC-04: Cleanup
Account Takeover — Password Reset Leak
TC-01: POST /forgot-password with victim email
TC-02: Check response body for "password" field → VULNERABLE if present
TC-03: Attempt login with password from response → confirms full ATO
TC-04: (Optional) Try non-existent email → compare response (enumeration check)
Account Takeover — Token Not Revoked After Logout
TC-01: Login → capture access_token
TC-02: Call authenticated API → expect 200 (token valid)
TC-03: POST /logout (or /api/auth/logout)
TC-04: Replay old token on authenticated API → expect 401; 200 = VULNERABLE
Rate Limit Bypass via X-Forwarded-For
TC-01: Send N requests with real IP → record when blocked
TC-02: Send N+1 requests with X-Forwarded-For: <random_IP> → if not blocked = VULNERABLE
TC-03: Test X-Real-IP, CF-Connecting-IP header variants
CORS Arbitrary Origin
TC-01: GET endpoint with Origin: https://evil.com
→ check Access-Control-Allow-Origin: https://evil.com = VULNERABLE
TC-02: GET with Origin: null → check response
TC-03: GET with no Origin → baseline
TC-04: If credentials: check Access-Control-Allow-Credentials: true (escalates severity)
Stored XSS (Upload)
TC-01: Get auth token (if required)
TC-02: Upload SVG/HTML file with payload + unique marker
TC-03: Fetch CDN URL → check Content-Type and payload presence
TC-04: (Playwright) Browser-verify JS execution via dialog event
TC-05: Cleanup — DELETE uploaded file
SSRF (Blind)
TC-01: Get auth token
TC-02: Trigger with OAST domain (webhook.site) → print manual check instructions
TC-03: Trigger with 127.0.0.1.nip.io, 10.0.0.1.nip.io
TC-04: (if applicable) Trigger with http://169.254.169.254/latest/meta-data/
TC-05: Print manual checklist
TC-06: Cleanup
Information Disclosure — Source Map
TC-01: GET /main-XXXX.js → check for "//# sourceMappingURL=" comment
TC-02: GET /main-XXXX.js.map → check for "sourcesContent" field
TC-03: Analyze sourcesContent for hardcoded secrets (key, password, apikey)
Information Disclosure — Laravel Debug / Vite Dev Server
TC-01: GET endpoint with Accept: text/html → check for Ignition/debug page
TC-02: GET /@vite/client → 200 = Vite dev server exposed
TC-03: GET /@fs/etc/passwd → check for file read
TC-04: GET /info.php → check for phpinfo() output
WordPress
TC-01: GET /wp-json/wp/v2/users?per_page=100 → user enumeration
TC-02: GET /?author=1 → redirect-based user enumeration
TC-03: POST /xmlrpc.php with system.listMethods payload
TC-04: POST /xmlrpc.php with pingback SSRF payload → OAST domain
Cloudflare Origin Bypass
TC-01: Resolve subdomain (e.g., api.example.com) → obtain origin IP
TC-02: GET http://<origin_IP>/ directly → compare with CDN response
TC-03: Check WAF/rate-limit bypass on direct origin access
Session Fixation
TC-01: GET login page → capture PHPSESSID from Set-Cookie
TC-02: POST login with credentials + same pre-login session cookie
TC-03: Check PHPSESSID after login → UNCHANGED = VULNERABLE
Step 6 — Generate verify_vulnXXXX.py
Minimal script: 1–3 requests, exit 0/1/2:
#!/usr/bin/env python3
"""
Verify Script — vuln-XXXX — <title>
Exit codes: 0=SAFE 1=VULNERABLE 2=ERROR
Usage: python verify_vulnXXXX.py [--base-url URL]
"""
import sys, argparse, requests
requests.packages.urllib3.disable_warnings()
DEFAULT = "<TARGET>"
def verify(base_url: str) -> int:
try:
r = requests.get(f"{base_url}/endpoint", timeout=15, verify=False)
if r.status_code == 200:
print(f"[VULNERABLE] {r.status_code} — <reason>")
print(f" {r.text[:300]}")
return 1
elif r.status_code in (401, 403):
print(f"[SAFE] {r.status_code} — endpoint properly protected")
return 0
print(f"[UNKNOWN] {r.status_code}")
return 2
except Exception as e:
print(f"[ERROR] {e}"); return 2
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--base-url", default=DEFAULT)
sys.exit(verify(p.parse_args().base_url))
Step 7 — File naming convention
| Vulnerability Type |
Type Prefix |
| BFLA |
bfla |
| IDOR / BOLA |
idor |
| Unauthenticated API |
unauth |
| Stored XSS |
xss_stored |
| DOM XSS |
xss_dom |
| Reflected XSS |
xss_reflected |
| SSRF |
ssrf |
| Business Logic (price/payment) |
bizlogic |
| Account Takeover |
ato |
| CORS |
cors |
| SQL Injection |
sqli |
| Information Disclosure |
infodisclosure |
| Rate Limit |
ratelimit |
| Session/Cookie |
session |
| WordPress-specific |
wordpress |
| Supabase-specific |
supabase |
| Infrastructure |
infra |
Save output to: <project_dir>/vulnerabilities/
Step 8 — Workflow
1. READ → Parse vuln-XXXX.md (or description / raw HTTP request)
2. DETECT → Identify vuln type from trigger keywords
3. AUTH → Identify auth mechanism from PoC signals
4. WRITE → Generate pentest_TYPE_vulnXXXX.py
- Header with metadata (ID, Severity, CVSS, CWE, Target)
- Verdict enum + TestResult dataclass
- TC-01..TC-N methods (exploit + control + cleanup)
- _save_evidence() helper
- _summary() and _export() helpers
- main() with argparse (--base-url, --dry-run, --output-dir)
5. WRITE → Generate verify_vulnXXXX.py (minimal, exit 0/1/2)
6. REPORT → Present final summary to user IN VIETNAMESE (see Step 9)
Step 9 — Final report to user (ALWAYS in Vietnamese)
After generating both files, present this summary in Vietnamese:
✅ Đã tạo xong cho vuln-XXXX (<tiêu đề>):
📄 vulnerabilities/vuln-XXXX.md (Severity: X, CVSS: Y)
🐍 vulnerabilities/pentest_TYPE_vulnXXXX.py (N test cases)
⚡ vulnerabilities/verify_vulnXXXX.py (quick verify, exit 0/1/2)
▶ Cách chạy:
python vulnerabilities/pentest_TYPE_vulnXXXX.py --base-url https://target.com
python vulnerabilities/verify_vulnXXXX.py --base-url https://target.com
📋 Tóm tắt:
- Loại lỗ hổng : <TYPE>
- Auth mechanism: <auth type>
- Số test cases : N
- Cleanup : ✅ included
Anti-Patterns
| ❌ Don't |
✅ Do |
| Hardcode credentials in script |
Use argparse + env vars |
| Skip cleanup TC |
Always add cleanup as last TC |
| Claim vuln without HTTP evidence |
Log status_code + response preview |
Use requests.get without timeout |
Always timeout=15 |
| Skip dry-run mode |
Always support --dry-run flag |
| Generate script without verify script |
Always generate both |
| Present results to user in English |
Always present final summary in Vietnamese |