webapp-probe
Skill153 starsChanged 44 days agoMITView on GitHub
Probe a web app for what it exposes or leaks - passively from captured traffic and actively against the target. Use to assess a web app's exposure or review Burp/ZAP history.
- Reads credentials
In this repository41 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- broken-access-controlSkill
- cdn-peekSkill
- http-request-smugglingSkill
- jwt-attacksSkill
- ssrf-oobSkill
- blockchain-forensicsSkill
- foundry-pocSkill
- safe-huntSkill
- smart-contract-auditSkill
- cloud-bucket-bruteSkill
- infrastructure-auditSkill
- dylib-hijack-scanSkill
- endpoint-threat-huntSkill
- parse-securitySkill
- agentic-seoSkill
- agent-onboardingSkill
- context-window-to-skillSkill
- git-commitSkill
- keen-eyesSkill
- no-aispeakSkill
- secure-1pass-accessSkill
- self-improveSkill
- shadow-partnerSkill
- training-guideSkill
- variant-tableSkill
- auditor-quizSkill
- audit-scopeSkill
- evidence-captureSkill
- external-enumerationSkill
- gdocs-audit-reportSkill
- hackerone-reportSkill
- nuclei-suggestSkill
- pre-bountySkill
- sandboxed-audit-runnerSkill
- tiny-auditorSkill
- vm-labSkill
- llm-fuzz-toolsSkill
- mcp-server-pentestSkill
- prompt-injection-auditSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 2 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
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
- Distinctive: line 26
Only run against a web application the user owns or is contractually engaged to test.
- Very specific: line 64
Look only at cookies that look session-bearing - the cookie name (case-insensitive) contains sess, token, auth, jwt or sid.
- Very specific: line 76
Run the secret-regex set in references/secret-regexes.md over every captured response body.
- Very specific: line 86
Run the error-signature set in references/error-signatures.md over every captured response body.
- Distinctive: line 134
If every signature matches (hit count == number of signatures), discard the whole domain - the server answers 200 to everything and none of …
- Very specific: line 187
if two-or-more segments remain: when the second segment is one of src, es, esm, lib, dist, node_modules, the package is just the first …
- Very specific: line 189
Keep a derived package name as a company-owned candidate when fuzz.ratio(package_name, company_root_label) > 50 (thefuzz / …
≈ “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.
Files
Contents
- Scope & authorization (blast-radius labels)
- Passive analysis of captured traffic:
- Missing or weak security headers
- Insecure session cookies
- Hardcoded secrets & API tokens in bodies
- Improper error handling (stack traces, DB errors, debug pages)
- Outdated / dev-mode technology fingerprints
- RCE-prone parameters in captured requests
- Active probing of the live target: 7. Disclosure-path brute (.git/config/logs, CVE paths) 8. Outdated / vulnerable software port probe 9. Wayback forgotten-endpoint mining + re-probe 10. Dependency confusion (sourcemaps -> npm)
- Runnable snippets
- Output
- Reference files:
references/secret-regexes.md,references/error-signatures.md,references/directory-signatures.md
Scope & authorization
Only run against a web application the user owns or is contractually engaged to test. This skill has two halves, each labelled by blast radius:
- Passive (classes 1-6) - inspects responses and requests you already captured (proxy history, an authenticated crawl, a saved sitemap, files on disk). Sends no new HTTP requests, mutates nothing, and is safe against a frozen capture.
- Active (checks 7-10) - sends live requests to the target and, for Wayback (9) and dependency confirmation (10), to third-party services (the Internet Archive, the npm registry). Check 8 is aggressive (multi-port sweep). Run these only in scope, and prefer a low-traffic window.
Take inputs as whatever you already hold: captured responses/requests for the passive half, and the target's domains / domain:port pairs for the active half. Report a finding exactly where each section says "Report a finding when...".
Passive analysis of captured traffic
Each class is one pass over the capture; each yields per-target findings.
0. Extensive attack surface flushout and coverage
Work through the given scope of the target, and work to maximize all the attack surface expansion via all techniques that comes to mind.
Take a webapp for example - seeing a 404 is one thing, but subdomain enumeration expanding the targets, on each running available browser tools to get extended sitemap, available source code, backup files, flush errors and stack traces with unexpected inputs and more.
Coverage is most important as you have to invent and act on lots of variations per the target type tailored to any customization opportunity you may discover that can further the search (e.g. if its next.js version xyz do we know how to trigger errors on there).
1. Missing or weak security headers
For every captured response, case-insensitively collect the response header names and report each of the ten headers below that is absent. Report a finding when: a response is missing any of these. Remediation is "add the <Header> in responses returning from the server".
| Header | Why it matters |
| X-Frame-Options | Blocks embedding the site in iframes (clickjacking). |
| Content-Security-Policy | Controls which resources (e.g. JS) the page may load. |
| Strict-Transport-Security | Forces HTTPS, including on the initial HTTP connection. |
| Permissions-Policy | Disables specific browser APIs; propagates to iframes. |
| X-Content-Type-Options | Stops MIME sniffing; browser trusts only the declared Content-Type. |
| Referrer-Policy | Prevents leaking sensitive query params via the Referer to third parties. |
| Cross-Origin-Resource-Policy | (xs-leaks) Restricts cross-origin access to the document's resources. |
| Cross-Origin-Embedder-Policy | (xs-leaks) Blocks loading cross-origin resources that don't grant permission via CORP/CORS. |
| Cross-Origin-Opener-Policy | (xs-leaks) Stops popup/opener documents from reaching the page's global object. |
| Cache-Control | Prevents responses being cached in intermediary proxies and leaked to other users. |
2. Insecure session cookies
Look only at cookies that look session-bearing - the cookie name (case-insensitive) contains sess, token, auth, jwt or sid. For each such Set-Cookie with a non-empty value, report a finding when any of:
- No attributes at all - the cookie string has no
;or no=. The whole cookie is insecure. - Missing
HttpOnly-Cookie '<name>' doesn't have the HTTPOnly attribute set. Fix: set HttpOnly on important cookies. - Missing
Secure-Cookie '<name>' doesn't have the Secure attribute set. Fix: set Secure. SameSite=None-Cookie '<name>' has the SameSite attribute set to 'none'. Fix: set SameSite=Strict, or at least Lax.- Long lifetime - an
Expires(parsed as a unix timestamp here) more than 14 days out.Cookie '<name>' has a long expiration date set of more than N days. Fix: give important cookies a short-lived expiration.
Cookies whose name matches none of those, and empty-valued cookies, are skipped to keep the signal high.
3. Hardcoded secrets & API tokens in bodies
Run the secret-regex set in references/secret-regexes.md over every captured response body. Report an INSIGHT (not a hard finding - these are high-value leads that need confirmation) when: any pattern matches. Record <secret name> ( <matched value(s)> ) while requesting <paths>; de-duplicate matches per target and truncate the joined match string to 400 chars.
The set (~60 patterns) covers provider credentials and identifiers: OpenAI legacy/sk-proj-/sk-svcacct- and Anthropic sk-ant-, npm npm_, Discord bot tokens & webhooks, DB connection URIs with embedded creds (MongoDB, Redis, PostgreSQL, MySQL, MSSQL), Azure Blob / GCS / Firebase Storage bucket URLs, Slack tokens/webhooks, GitHub classic/fine-grained PATs and git+https URIs, AWS access-key IDs / MWS tokens / S3 bucket URLs, Google API keys / OAuth / GCP service-account JSON / ya29. access tokens, Stripe/Square/PayPal Braintree/Picatic/Mailgun/MailChimp payment & mail keys, DigitalOcean, HuggingFace, Grafana Cloud, Segment, Okta, Fullstory, Adobe, Heroku, Telegram, Firebase URLs, and a generic "Password": "..." JSON pattern. Full patterns in the reference file.
The reference file's False-positive gates section is not optional - it is what decides whether a match is worth reporting: a credential-keyword gate on the generic connection string, a placeholder/localhost filter on the connection URIs (without it those five rows are net-negative), a snowflake decode for Discord tokens, a repetition floor on the remaining unanchored rows, and the rule that rows tagged (identifier) are public by design and get an insight with a next step attached, never a credential finding.
Secrets in third-party JS may be intentional publics (e.g. a Google Maps browser key) - verify before reporting as a leak; treat the finding as a lead.
4. Improper error handling - stack traces, DB errors, debug pages
Run the error-signature set in references/error-signatures.md over every captured response body. First skip responses that are JavaScript bundles (they produce false positives): skip the body if it matches sourceMappingURL|window\.addEventListener|window\.document|webpackJsonp|jQuery. Report a finding when: any signature matches; record <signature name> ( <match> ) while requesting <paths>.
The set (~130 signatures) spans: SQL/DB errors (MySQL, MSSQL OLE DB, PostgreSQL, Oracle ORA-, DB2, SQLite, MongoDB E11000, Elasticsearch mapper_parsing_exception); language runtime exceptions (Java java.lang.*/java.io.*/java.sql.*, Python Traceback/ValueError/KeyError/etc., Ruby, C++ std::*, .NET System.*); framework error pages (Django, Flask/Werkzeug, Laravel/Symfony, Spring/Spring Boot/Hibernate, Rails ActionView::Template::Error, Express.js, ASP.NET "Server Error in '/' Application"); insecure-deserialization gadget-chain traces (Java ObjectInputStream.readObject, InvokerTransformer/LazyMap/ChainedTransformer, readObject/writeObject, Python pickle/yaml.load, Ruby Marshal.load/YAML.load, PHP unserialize(, C# BinaryFormatter, Go encoding/gob, Jackson); config/secret disclosure (<compilation debug="true", DATABASES = {...}, secret_key_base, Web.config, Node config errors); and CSRF/JWT errors. Full name+pattern table in the reference file.
5. Outdated / dev-mode technology fingerprints
Because this is a passive body-string search (not endpoint probing), the patterns are deliberately precise. Run over every captured response body; report an INSIGHT when any matches (<name> ( <match> ) while requesting <paths>). This is the passive counterpart to the active port probe in check 8 - a passive hit tells you where to point check 8.
| Fingerprint | Body regex | Meaning | ||
| Tomcat Dev Interface | tomcat\.gif | Default Tomcat page/manager exposed. | ||
| Jenkins Dev Interface | Welcome to Jenkins! | Jenkins UI reachable. | ||
| Werkzeug Dev Interface | Werkzeug powered traceback interpreter | Flask/Werkzeug interactive debugger (RCE-prone). | ||
| AD Self Service Management Server | adscsrf | ADSelfService Plus portal. | ||
| Frontend Code Editor | `ace_editor | codemirror | monaco-editor` | In-page code editor surface. |
| Pulse Secure File Read | dana-na\/css | Pulse Secure (CVE-2019-11510 arbitrary file read). |
Reference: nuclei-templates http/cves/2019/CVE-2019-11510.yaml.
6. RCE-prone parameters in captured requests
Over captured requests, inspect query-string params and body params (parsed by Content-Type: XML tags, JSON keys, or x-www-form-urlencoded keys). Report an INSIGHT when: a parameter key matches the RCE-suggestive wordlist below, or a parameter value equals ##class (a common template/gadget marker). Record which location matched, e.g. Query parameter key 'cmd' was found at path '<path>' or JSON body parameter key 'exec' was found at path '<path>'. These names don't prove a vuln - they flag parameters worth targeted, authorized command-injection testing.
Parameter keys (case-sensitive match, as captured):
daemon, execute, cmd, cli, ip, xp_cmdshell, CSPCHD, exec, func, function,
command, eval, shell, shell_exec, popen, proc_open, bash, python, system,
payload, cmdline, exe, execcommand, exec_code, exec_cmd, executeshell,
cmd_exec, cmd_inject, cmd_shell, cmd_script, run, runcmd, runcommand,
shellcode, shellexec, shellcmd, command_prompt, process, terminal,
execute_command, exec_file, load_module, load_script, proc_cmdline,
runtime_exec, shell_execute, system_command, sys_commandParameter values: ##class.
Requests with a body but no Content-Type, or an unrecognized Content-Type, are skipped.
Active probing of the live target
These send live requests. Confirm scope first; they leave logs on the target (and, for 9-10, on third parties).
7. Disclosure-path brute - active
For each domain, GET a curated set of source/config/log/known-CVE paths (no redirects, TLS verification off, 10s). Each signature carries a path, an expected status regex and a body regex; a match must satisfy both. The full 30-signature table lives in references/directory-signatures.md (e.g. /.git/config, /.git/config~, /.git, /.svn, /package.json, /jsconfig.json, /config.json, /info.php, /phpinfo.php, /web.config, /global.asa, /storage/logs/laravel.log, /wp-content/debug.log, Eclipse Jetty /WEB-INF/web.xml and its /%2e/-prefixed traversal variant, Telerik /Telerik.Web.UI.WebResource.axd?type=rau, Pulse /dana-na/, /adminer.php, /phinx.yml, the .env family, /.npmrc, ten Swagger/OpenAPI doc paths, and Django-debug /djgo expecting a 4xx page containing DEBUG =).
False-positive controls (essential - catch-all responders are common):
- Drop any response whose body contains
404 Not FoundorThis page can't be displayed. - Hash (MD5) each matching response body; collapse duplicates so one generic page counted many times becomes one hit.
- If every signature matches (hit count == number of signatures), discard the whole domain - the server answers 200 to everything and none of it is real.
Report a finding when: at least one - but not all - signatures match after dedup. Severity: Information Disclosure (rate individually; exposed .git/.svn or a live source/config/log file is often high impact).
8. Outdated / vulnerable software port probe - aggressive
For each domain, probe management interfaces of RCE-prone stacks across their typical ports, matching a substring in the response body. Cache each port's response and reuse it so overlapping port lists don't re-request. On 80/443 use plain http://host / https://host; on any other port try both http and https (label the hit port (HTTP) / port (HTTPS)).
| Service (RCE surface) | Path | Body substring | Ports |
| Apache Tomcat | / | Tomcat | 80, 443, 8080, 8081, 8089, 8090, 9090, 9091 |
| Jenkins | /login | Jenkins | 80, 443, 8080, 8081, 8089, 8090, 9090, 9091, 7443, 8443, 9443 |
| Werkzeug debugger | /console | Werkzeug powered traceback interpreter | 80, 443, 8080, 4000 |
| ManageEngine ADSelfService | /showLogin.cc | adscsrf | 8080, 8889 |
| InterSystems Caché | / | CSPCHD | 443 |
| ASP.NET ViewState | / | __VIEWSTATE | 443 |
| Jolokia / Java RMI | /jolokia | jolokia | 443 |
| Plone CMS | / | Plone | 443 |
Report a finding when: any service substring appears. Severity: potential RCE insight - report "<service> found on port(s) <list>". The Werkzeug /console interactive debugger and an exposed Jolokia agent are directly exploitable; the rest are version-review leads.
9. Wayback forgotten-endpoint mining + re-probe - active-3rdparty (harvest), then active (re-probe)
Harvest (active-3rdparty). Query the Internet Archive CDX index per domain:
https://web.archive.org/cdx/search/cdx?url={domain}*&collapse=urlkey&limit=40000&fl=urlkey,timestamp,original,mimetype,statuscode,length&output=jsonThe archive rate-limits ~15 req/min and imposes a ~5-minute block; use a retry/backoff of 5m -> 10m -> 20m on HTTP 429. Drop static/noise by mimetype (application/javascript, text/javascript, application/x-javascript, text/css, image/png, image/gif, font/woff) and by extension in the URL (.png .js .css .jpg .JPG .jpeg .gif .ttf .tif .eot .woff .woff2 .pdf .otf .svg .ico .html .swf .styl).
Filter to the interesting URLs (this de-noising is the point):
- Skip URLs longer than 1000 chars.
- Skip "cache-buster / hash-looking" URLs: those matching
^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?!.*\?)(?!.*\=)(?!.*\&)(?!.*\_).*$(mixed-case+digits, no query, no underscore). - Skip boring path substrings:
how-it-works, promotions, images, google-tag-manager-cart, terms-of, -products, frequently-asked-questions, wewaw, news, wp-json, wp-admin, diy. - Require a query string (
?...); keep only distinct(path, frozenset(query-param-names))tuples. - Compute the 20 most common path segments / query-param names across the survivors; keep an element only if it recurs >5 times and its length is >3 and <11; then drop any URL that contains one of those common elements - i.e. keep the unusual endpoints, discard the site-wide boilerplate.
Report the surviving URL set as an Information Disclosure insight (archived, possibly-still-live parameterized endpoints worth manual testing).
Targeted re-probe (active). For any surviving URL whose path matches a fingerprint below, send a live GET (5s) to the target and match status + body:
| Fingerprint | Path regex | Status | Body regex | Meaning |
| Telerik Web UI | Telerik | 2.* | .* | Telerik UI present (CVE-2019-18935 lineage) |
| Java Server Pages / JSF | javax\.faces\.resource|javax\.faces\.ViewState | 2.* | .* | JSF ViewState deserialization surface |
| Pulse Secure File Read | dana-na | 2.* | dana-na\/css | Pulse Connect Secure (CVE-2019-11510 arbitrary file read) |
Report a finding when: a re-probed URL still returns 2xx and matches its body regex. Severity: potential RCE (HIGH) - flag URL (fingerprint description) for manual confirmation.
10. Dependency confusion: sourcemap -> company package -> npm - active (harvest), active-3rdparty (registry check)
Harvest private package names (active). For each domain:port on 443, GET the homepage, parse every <script src="...js">, and request the co-located sourcemap src + ".map" (resolved absolute). Only fetch maps whose URL is same-origin (domain in map_url). From each map's sources[], keep entries containing ../node_modules; take the path after ../node_modules/, split on /, and:
- skip if the first segment is
src; - drop any
.jssegment; - if two-or-more segments remain: when the second segment is one of
src, es, esm, lib, dist, node_modules, the package is just the first segment; otherwise treat it as a scoped package@scope/name->{seg0}/{seg1}.
Keep a derived package name as a company-owned candidate when fuzz.ratio(package_name, company_root_label) > 50 (thefuzz / Levenshtein-style ratio) - i.e. the dependency's name resembles the company's own name, the tell-tale of an internal package leaked into a public bundle.
Confirm dependency confusion (active-3rdparty). For each candidate, query the public npm registry (https://registry.npmjs.org/<name>, URL-encode a @scope/name). If it returns 404 / not found, the private name is unclaimed on the public registry and is dependency-confusion-claimable; if it resolves to a package not owned by the target org, it may already be squatted.
Report a finding when: a company-resembling node_modules package name derived from a target's own bundle is unregistered (or third-party-owned) on the public registry. Severity: dependency confusion (a malicious publish of that name can execute in the target's build/runtime). Also flag the exposed sourcemaps themselves as an information-disclosure insight.
Runnable snippets
Passive sweep (no requests sent)
These operate on a directory of already-captured responses/requests. Assume CAPDIR holds saved response bodies (e.g. *.body) and sibling *.headers files. Adapt the loader to your proxy's export format.
# 1 missing security headers - scan saved *.headers files (name: value per line)
python3 - "$CAPDIR" <<'PY'
import sys,glob,os
req=["x-frame-options","content-security-policy","strict-transport-security","permissions-policy","x-content-type-options","referrer-policy","cross-origin-resource-policy","cross-origin-embedder-policy","cross-origin-opener-policy","cache-control"]
for f in glob.glob(os.path.join(sys.argv[1],"*.headers")):
have={l.split(":",1)[0].strip().casefold() for l in open(f,errors="ignore") if ":" in l}
miss=[h for h in req if h not in have]
if miss: print(os.path.basename(f),"MISSING:",", ".join(miss))
PY# 2 insecure session cookies - parse Set-Cookie lines from saved *.headers
python3 - "$CAPDIR" <<'PY'
import sys,glob,os,time
for f in glob.glob(os.path.join(sys.argv[1],"*.headers")):
for line in open(f,errors="ignore"):
if not line.lower().startswith("set-cookie:"): continue
c=line.split(":",1)[1].strip()
if ";" not in c or "=" not in c: print(os.path.basename(f),"no-attributes:",c); continue
parts=c.split(";"); nv=parts[0]; name=nv.split("=")[0]
if not nv.split("=",1)[1]: continue
if not any(p in name.casefold() for p in ("sess","token","auth","jwt","sid")): continue
attrs=[a.strip().casefold() for a in parts[1:] if a.strip()]
if "httponly" not in attrs: print(os.path.basename(f),name,"missing HttpOnly")
if "secure" not in attrs: print(os.path.basename(f),name,"missing Secure")
if "samesite=none" in attrs:print(os.path.basename(f),name,"SameSite=None")
for a in attrs:
if a.startswith("expires="):
try:
d=(int(a.split("=",1)[1])-time.time())/86400
if d>14: print(os.path.basename(f),name,"long expiry %d days"%d)
except ValueError: pass
PY# 3 secrets & 4 error signatures & 5 tech fingerprints - one regex sweep over bodies
# put the patterns from references/secret-regexes.md + references/error-signatures.md into rules.txt
# as "name<TAB>pattern" lines (prefix error-signature names with ERR:), then:
python3 - "$CAPDIR" rules.txt <<'PY'
import sys,glob,os,re
rules=[l.rstrip("\n").split("\t",1) for l in open(sys.argv[2]) if "\t" in l]
rules=[(n,re.compile(p)) for n,p in rules]
jsskip=re.compile(r"sourceMappingURL|window\.addEventListener|window\.document|webpackJsonp|jQuery")
for f in glob.glob(os.path.join(sys.argv[1],"*.body")):
body=open(f,errors="ignore").read()
isjs=bool(jsskip.search(body))
for n,rx in rules:
if isjs and n.startswith("ERR:"): continue
m=rx.findall(body)
if m:
j=", ".join(sorted({x if isinstance(x,str) else "".join(x) for x in m}))
print(os.path.basename(f),n,"(",(j[:400]+"..") if len(j)>400 else j,")")
PY# 6 RCE-prone parameters - scan captured requests (one URL per line in reqs.txt)
python3 - reqs.txt <<'PY'
import sys,urllib.parse as u
keys={"daemon","execute","cmd","cli","ip","xp_cmdshell","CSPCHD","exec","func","function","command","eval","shell","shell_exec","popen","proc_open","bash","python","system","payload","cmdline","exe","execcommand","exec_code","exec_cmd","executeshell","cmd_exec","cmd_inject","cmd_shell","cmd_script","run","runcmd","runcommand","shellcode","shellexec","shellcmd","command_prompt","process","terminal","execute_command","exec_file","load_module","load_script","proc_cmdline","runtime_exec","shell_execute","system_command","sys_command"}
for line in open(sys.argv[1]):
q=u.urlsplit(line.strip()).query
for k,vs in u.parse_qs(q).items():
if k in keys: print("param key",k,"in",line.strip())
for v in vs:
if v=="##class": print("param value ##class in",line.strip())
PYActive probes (live requests to the target)
# 7 disclosure-path brute (no redirects; flag 2xx that isn't a soft-404)
for p in /.git/HEAD /.git/config /.svn /.env /.env.local /.env.production /.npmrc /package.json /config.json /info.php /phpinfo.php /web.config /storage/logs/laravel.log /wp-content/debug.log /adminer.php /phinx.yml /swagger.json /v3/api-docs /openapi.json; do
code=$(curl -sk -o /tmp/b -w '%{http_code}' --max-time 10 "https://TARGET$p")
grep -qE '404 Not Found|This page can.t be displayed' /tmp/b || { [ "${code:0:1}" = 2 ] && echo "$code $p md5=$(md5 -q /tmp/b 2>/dev/null || md5sum /tmp/b|cut -d' ' -f1)"; }
done # if EVERY path returns 2xx, the host is a catch-all -> discard all
# 8 outdated / vulnerable software port probe (body-substring per service)
for pp in "80 / Tomcat" "8080 /login Jenkins" "8080 /console Werkzeug" "443 /jolokia jolokia" "443 / __VIEWSTATE" "443 / Plone"; do
set -- $pp; port=$1; path=$2; sig=$3
for sch in http https; do curl -sk --max-time 5 "$sch://TARGET:$port$path" | grep -q "$sig" && echo "$sig on $port ($sch)"; done
done
# 9 Wayback harvest (respect 15/min; back off on 429)
curl -s "https://web.archive.org/cdx/search/cdx?url=example.com*&collapse=urlkey&limit=40000&fl=urlkey,timestamp,original,mimetype,statuscode,length&output=json" \
| python3 -c 'import sys,json;[print(r[2]) for r in json.load(sys.stdin)[1:] if r[3] not in ("application/javascript","text/javascript","application/x-javascript","text/css","image/png","image/gif","font/woff") and "?" in r[2]]'
# 10 sourcemap -> node_modules -> npm ownership
curl -s https://TARGET/ | grep -oE 'src="[^"]+\.js"' | sed 's/src="//;s/"//' | while read s; do
curl -s "https://TARGET/${s}.map" | python3 -c 'import sys,json;
d=json.load(sys.stdin);
[print(x.split("../node_modules/")[1]) for x in d.get("sources",[]) if "../node_modules" in x]' 2>/dev/null; done | sort -u
curl -s -o /dev/null -w '%{http_code}\n' "https://registry.npmjs.org/CANDIDATE_PACKAGE" # 404 => dependency-confusion-claimableOutput
Finish with a two-part ledger, then a verdict:
- Passive - per class (1-6): targets scanned and findings, distinguishing confirmed findings (classes 1, 2, 4) from insights/leads (classes 3, 5, 6) that need authorized follow-up.
- Active - per check (7-10): check / blast-radius / done? / result, with the confirming request for each hit (exposed path after dedup/catch-all filtering, fingerprinted software+port, still-live archived endpoint, claimable private package).
Report each class/check's true status - scanned, run, not-run, or rate-limited - so coverage is honest. A clean passive result only means the leak wasn't present in the captured traffic; never present an un-run or rate-limited active check as clean.
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
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.

