discover
AGENTS.md3.9k starsChanged 3 days agoMITView on GitHub
Conventions agreed with the operator for Discover development. Read and follow this file. When we discuss and agree on a durable rule (layout, install order, Update UX, host-scan gating, etc.), add or update it here in the same change set when practical—do not leave it only in chat history.
- Reads credentials
- Installs packages
We split this AGENTS.md into the rules it gives an agent
16 rules. About 0 are common, 4 are distinctive, and 12 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
12
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 15
Nested
if: keep it tight against the parent then / else / elif and the parent fi. - Very specific: line 34
Do not put new Discover features, helpers, or data files under old/.
- Very specific: line 48
Always record timestamps in UTC: when a scan runs or any engagement event is written (audit log, host-scan meta started/finished / *_utc, …
- Very specific: line 84
After a successful Import, the Audit page reloads so KPI totals, charts, Target scans, and the log match the rebuilt audit.htm.
- Very specific: line 134
Operator name: read/write ~/.discover/operator-name (1–10 letters).
- Distinctive: line 137
After a successful Save, that panel’s Back (or Cancel) and Save buttons are removed.
- Very specific: line 145
When designing or tweaking report page layouts (especially Audit and other modern.css tables/containers):
- Very specific: line 147
Prefer px for widths, min/max-widths, padding, and gaps you are dialing in with the operator.
- Distinctive: line 158
Do not group by feature (e.g.
- Very specific: line 166
Before the tool runs, run-host-scan.sh does a curl HTTP/1.1 GET (15s max, same UA as the tool).
- Very specific: line 168
If no HTTP response (000 / timeout): do not launch the tool.
- Very specific: line 202
Auto-migrate: if $DISCOVER/.env or ~/.discover/.env still exist, Discover merges them into ~/.discover/api-keys (existing api-keys values …
- Very specific: line 204
Do not run discover-config.py set-api-keys, statusd POST /config/api-keys, or any write to ~/.discover/api-keys (or legacy .env key files) …
- Distinctive: line 205
Do not “verify” save paths against the operator’s real key file.
- Distinctive: line 206
Do not clear, overwrite, or restore keys unless the operator explicitly asks to save or change a specific key.
- Very specific: line 233
After import: refresh pages/subdomains.htm and pages/hosts.htm (unique public IPs).
≈ “Common” is an estimate: at least 1 in 5 of the 36,368 AGENTS.md 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
Discover agent notes
Conventions agreed with the operator for Discover development. Read and follow this file. When we discuss and agree on a durable rule (layout, install order, Update UX, host-scan gating, etc.), add or update it here in the same change set when practical—do not leave it only in chat history.
Writing (operator-facing text)
- Never use three periods in a row (
...) at the end of a sentence. End with a single period (.). - Same for Unicode ellipsis (
…) in operator-facing text (logs, UI status lines, scanoutput.txt, help copy): use a single.when finishing a sentence. Do not write “Running…”, “Updating…”, or “pre-check (15s)…”. - Mid-list “and more” truncation in docs/comments is fine when not sentence-final (e.g.
2xx,301,302,...as a list tail). Prefer plain ASCII over fancy punctuation in plain-text scan logs.
Shell (if)
- Blank line before and after an
if/fiblock (if/elif/else/fiis one block). - Skip the blank line before
ifwhen a comment sits immediately above it. Keep a blank line afterfi. - Nested
if: keep it tight against the parentthen/else/elifand the parentfi. No blank line betweenthenand the innerif, and none between the innerfiand the outerfi/else/elif:
if ! apt install -y arp-scan; then
if grep -qi '^ID=ubuntu' /etc/os-release; then
apt install -y arp-scan/questing
fi
fi- Sibling
ifblocks (an innerfifollowed by anotherifat the same level) still get a blank line between them.
Git commits
- Only commit when the operator explicitly asks (e.g. “do a commit”). Do not commit proactively after finishing a feature or when they only ask whether a commit is needed.
old/ folder
old/is not part of the Discover framework. It holds personal/legacy scripts from earlier work that are unrelated to Discover’s recon/scan/report flow.- Do not put new Discover features, helpers, or data files under
old/. - Live subdomain categorizer + rules live under
recon/(recon/subdomain-categorize.py,recon/subdomain-categories.tsv). Do not reintroduce Discover paths that point atold/. - Exact patterns match a whole hostname label or one hyphen-separated piece of a label.
dnsmatchesdns.example.comandaj-dns-02.example.com. First match still wins, so Dev is checked before Infrastructure. The same matcher is inlined inrecon/import-subdomains.sh. - A star suffix ignores trailing digits.
*devmatchesalmdev.example.comandalmdev2.example.com.development.example.comstays on the exactdevelopmentrule.deviceanddevopsdo not match.
Operator name (audit log)
- First name only, max 10 letters only, stored at
~/.discover/operator-name. - Prompted once when Discover starts if missing/invalid (
f_ensure_operator_nameindiscover.sh). - Audit lines:
mm/dd/yyyy - hh:mm Z | <name> | <egress IP> | <action>(f_audit_log/ host-scanf_audit). Dash-date stamps (mm-dd-yyyy - hh:mm Z), legacy (mm-dd-yyyy Z - hh:mm), and 3-field lines still parse on the Audit page. - Imported subdomains / Imported CSV list subdomains, Imported names (incl. titles/emails), and Imported operator package: Operator IP is always a dash (
-in the log,—on the Audit page). Do not record egress IP for those events. Ran Shodan enrichment, Updated Shodan data for an IP, and Updated software CVE data are not written to the audit log.
Timestamps (UTC write, view timezone)
- Always record timestamps in UTC when a scan runs or any engagement event is written (audit log, host-scan meta
started/finished/*_utc, status stamps, exportexported_at_utc, etc.). Human stamps aremm/dd/yyyy - hh:mm Z; ISO fields stayYYYY-MM-DDTHH:MM:SSZ. - Operators may choose a timezone for viewing (e.g. Audit Config → Time zone). That preference is display only for Audit/metrics.
- View timezone must not change how data is written — no local-time stamps in
tools/audit/log.txt, meta.json, or other on-disk artifacts. Convert only when rendering the report UI (and label the column, e.g. Time (UTC) vs local). - Export filename is the exception:
YYYYMMDD-HHMMindomain-kind-YYYYMMDD-HHMM.zip(or.csv) uses the operator view timezone (~/.discover/timezone). Ledgerexported_at_utcand the audit line stay UTC. - Preference store:
~/.discover/timezone(not inside a single engagement report), so it applies across engagements for that operator machine. UI: Audit Config → Time zone.
Passive tools
- Passive does not run Sublist3r.
misc/update.shdoes not install or update it.
Passive Names section
- Passive Names dump is name + title, aligned (
column -t). Emails stay in the Emails section; phone is not shown there. import-names.shandimport-names-titles-emails.shboth write that format when they refreshpages/passive.htm.
Optional nav pages (General / Files)
- Nav items are omitted when the matching
pages/*.htmfile is missing. Standard reports that include those pages keep the menu items. - Covered: General → Emails (
emails.htm); Files → Excel (xls.htm), PowerPoint (ppt.htm), Text (txt.htm), Word (doc.htm), PDF (pdf.htm). - Rebuilds of Audit / Active / Subdomains / Hosts copy Discover templates (full menus); writers strip items whose pages are absent.
Report homepage date (index.htm)
- Home hero date (
#DATE#/ firstinc-home-metavalue) is formatMonth DD, YYYY(same as DiscoverDATESTAMP). - Update to today whenever the engagement changes: Passive finish, Active, host-scan finish, Shodan enrich/Update, software CVE refresh, KEV catalog refresh, subdomain/names imports, operator package import.
- Helper:
recon/touch-report-date.py <report_dir>(also callable from Python viatouch_report_index_date).
Import hub (Audit page)
- Import button on Audit only when Discover-hosted (
http://127.0.0.1:17322/…). Label stays Import. Always targets the current engagement (statusdreport_root); no report path in the UI. - Hub choice rows: Operator scans · Names · Names, titles, and emails · Subdomains.
- Operator scans: path to unpacked other-operator report + their first name (1–10 letters). Backend:
POST /import-operator-package→recon/import-operator-package.py --dest <live> --source <path> --operator <Name> --json. Merges host-scans, gowitness, httpx/whatweb, new subdomains, audit lines for that name. Never copies theirpages/*.htmover the live tree. - Names: optional manual TSV path (default
tools/names-manual.tsvin the live report).POST /import-names→recon/import-names.sh --report <live> [--manual …] --json. - Names, titles, and emails: source file path.
POST /import-names-titles-emails→import-names-titles-emails.sh --report <live> --source … --json. - Subdomains: mode
existing|team-csv, import path (firefoxallowed), optionalrun_activefor CSV new public hosts.POST /import-subdomains→import-subdomains.sh --report … --mode … --import … [--run-active] --json. - Domain menu no longer lists import items 6–8; menu is 6 Active · 7 Open report · 8 Previous. Scripts remain for CLI.
- After a successful Import, the Audit page reloads so KPI totals, charts, Target scans, and the log match the rebuilt
audit.htm. - Assets:
inc-audit-import.js; bust?v=/modern.csson Audit after UI changes; import-report injects the script onaudit.htm. Restart statusd after endpoint changes.
Audit log operator filter
- Client-side dropdown next to Audit log heading: All operators + each unique name from the table.
- Rows use
data-audit-operator(fromaudit-build.py). Optional URL?operator=Name(case-insensitive; updates viahistory.replaceState). - Works on statusd and
file://. Asset:inc-audit-log-filter.js; bust?v=/modern.csson Audit after UI changes.
Audit log table (hidden rows)
- Still written to
tools/audit/log.txt. The Audit log table (and defender CSV) omit: Opened report in Discover, Exported …, nuclei pass-2, Imported operator package (imported lines stay), Finished robots (Finished robots in 2 sec./Finished robots on …). Started robots stays (command + TXT/WEB). Metrics still count Finished robots.
Audit log line delete
- Delete on each Audit log row only when Discover-hosted (
http://127.0.0.1:17322/…). Manualfile://never shows it. - Confirm modal:
<Operator>, are you sure you want to delete this line?(operator from~/.discover/operator-name/ GET/config) plus a short line preview. Cancel / Delete. - Backend: statusd
POST /audit-line-delete→audit-build.py --delete-line <sha256> <report> --json. Removes one matching line fromtools/audit/log.txt(hash of stripped raw line), rebuildspages/audit.htm(metrics + log). - Row markup:
data-audit-hash/data-audit-previewon each log<tr>fromaudit-build.py. Assets:inc-audit-line-delete.js; bust?v=/modern.csson Audit; import-report injects the script. Restart statusd after endpoint changes.
Audit page refresh
- Discover-hosted Audit (
http://127.0.0.1:17322/) reloads whenpages/audit.htmis rebuilt, so a new log line shows up, then scrolls to that newest row. The first status poll only records the revision. - An open Config, Import, Export, or delete dialog waits. The page reloads after it closes.
- The metrics range (Today, Yesterday, Last 7 days, Last week, All) is kept across that reload. A normal open still starts on All and stays at the top of the page.
- Manual
file://does not reload.GET /statusaddsaudit_rev(page mtime and size). Asset:inc-audit-status.js. Bust?v=on Audit after the script changes. Restart statusd after the/statuschange.
Audit last-7-days metrics (Option A strip)
- Shown above the Audit log on
pages/audit.htm(all report modes; built byaudit-build.py). - Range dropdown (aligned with By CVE / Targets scanned): Today · Yesterday · Last 7 days · Last week · All (default). Asset:
inc-audit-metrics-range.js. Live reports, Operator export, and Client export open on All.- Calendar windows use the operator view timezone (
~/.discover/timezone). Audit stamps stay UTC on disk. - Today: current calendar day in the view timezone (start = today 00:00).
- Yesterday: previous calendar day in the view timezone (yesterday 00:00 through today 00:00).
- Last 7 days: last 7 calendar days inclusive of today in the view timezone (start = today−6 00:00).
- Last week: previous full calendar week in the view timezone (Monday 00:00 through this Monday 00:00).
- All: no date filter (Scans per day chart capped at newest 60 calendar days of activity). That chart is one bar per day. With more than 12 days, the axis prints every 7th date plus the last day. Weekly dates are left-aligned on that bar. The last date is pinned to the end of the bars so it stays inside the pane. Hover a bar for that date and count.
- Calendar windows use the operator view timezone (
- KPI cards (compact row, centered): Targets scanned, Scans completed; Incomplete scans only when count > 0 (then three cards; otherwise two cards centered).
- Charts layout (top → bottom): KPI row; By CVE | By software (2 equal boxes); By tool | By category (2 equal boxes); Scans per day (full width of two-box row); By operator (full width of two-box row). Horizontal bar charts show top 10 entries each. Client export omits Scans per day and By operator. The live report and Operator export keep both.
- Data: host-scan Finished / Started lines in
tools/audit/log.txt; software from(software: …)on Finished lines; CVEs from nuclei pass-2meta.pass2.ids(canonicalCVE-YYYY-NNNNonly) for runs finished in the window; category fromtools/subdomains/tools/private-subshost→category lookup (empty →(none)). - By operator counts each host-scan Started line in the window (the scan that operator launched). A Finished line with no matching Started line for that operator, tool, and host still counts. Scans completed, By tool, By software, and By category stay on Finished lines.
- Incomplete: Started in the selected window with no Finished for the same tool+host at/after that start (Finished may be outside the window — e.g. started last week, finished this week is complete for Last week).
- Rebuild with Audit (host-scan finish, Open report, Config name rewrite, etc.). Bust
modern.css?v=on Audit after CSS changes.
Config (Audit page only)
- Config button on Audit only when Discover-hosted (
http://127.0.0.1:17322/…). Header order: Config · Import · Export. - Modal hub with five choice rows: Operator name, Time zone, APIs, Google Sheet, X.
- Backend:
recon/discover-config.pyvia statusdGET /config,POST /config/api-keys,POST /config/operator-name,POST /config/timezone,POST /config/op-notes,POST /config/op-notes-authorize,POST /config/x. - Operator name: read/write
~/.discover/operator-name(1–10 letters). On change, rewrite only audit lines whose Operator field matches the previous name (other operators’ lines untouched; do not rewrite names inside Action text). Rebuild Audit after rewrite. - Time zone: display preference (
~/.discover/timezone). UTC + US zones. Does not change written stamps (always UTC). Audit Time column converts in the browser. Metrics Today / Yesterday / Last 7 days / Last week use this timezone when Audit is built. Saving it rebuilds Audit. - APIs: show/edit/save
NVD_API_KEY,SHODAN_API_KEY,WPSCAN_API_TOKENin~/.discover/api-keys(chmod 600). The NVD row showshttps://nvd.nist.govto the right of the label. The Shodan row showshttps://www.shodan.io/to the right of the label. The WPScan row showshttps://wpscan.com/register/to the right of the label. Localhost only. Saving APIs leavesX_API_KEYin that file unchanged. theHarvester is a link (not a field) that opens~/.theHarvester/api-keys.yamlvia statusdPOST /config/open-theharvesterordiscover-theharvester:→misc/open-theharvester-keys.sh(open, elsexdg-open). If that file is missing, copy~/theHarvester/theHarvester/data/api-keys.yamlinto place (do not overwrite an existing file). Do not store theHarvester keys in Discoverapi-keys. - After a successful Save, that panel’s Back (or Cancel) and Save buttons are removed. Authorize on Google Sheet stays until Save. A failed save leaves the buttons. Opening the panel again shows them. The header close control stays.
- X: fifth Config row. Opens a second modal (the hub stays open behind it). Bearer token reads and writes
X_API_KEYin~/.discover/api-keys(chmod 600). Accounts are added and deleted in that modal, then Save writes~/.discover/x-accounts(one handle per line, chmod 600, at most 40). The list is alphabetical (A–Z, ignoring case) each time the modal opens, and a newly added handle is inserted in that order. A handle is 1–15 letters, numbers, or underscores.@nameand anx.comortwitter.comprofile URL are accepted and stored as the bare handle. Empty key clearsX_API_KEY. This is per user (~/.discover), not per engagement.POST /config/x. The APIs panel does not show this key. - theHarvester sources:
recon/passive.shsources_no_api/sources_apimust stay in lockstep withold/test-theHarvester.sh. Cover every name in~/theHarvesterSOURCE_SPECS. Split by theHarvester README API key column: No →sources_no_api; Required or Optional →sources_api. Domain menu 98 = free list, 99 = API list. After a theHarvester update, run option 99 leftover check (old/newModules.sh) and add any new engines to the matching list. - Google Sheet: per-engagement spreadsheet URL in
$REPORT_ROOT/tools/op-notes-url(chmod 600). Empty URL disables sync. Not stored in~/.discover/api-keys(machine-global). Do not read a report-root.env. OAuthclient_secret.json+google-token.jsonstay in~/.discover/(chmod 600). Authorize in this panel (browser OAuth); host-scan and Active appends never open a browser. Client/defender Export omittools/op-notes-url(and a stray report-root.envif present). Operator Export may keep the URL file. Host-scan:uv run misc/op_notes.py appendin the foreground before the tool starts (40s cap; Discover install providesuv). Active checks the sheet before probes and appends one row when the scan finishes (same 40s cap). Target is the engagement domain. Command isactive recon, oractive recon on imported hostsfor an import batch. Result is the probed and alive counts. Empty URL stays off and does not stop the scan. A configured sheet that is not authorized, is missinguvorop_notes.py, or fails to open or append prints the error and stops the scan. Columns A–E: date, operator, IP, target, command. Date is the scan time in the spreadsheet timezone,mm/dd/yyyy - hh:mm. Target is plain text. A hostname is not a link. When the Action cell wraps past one line, that row grows to fit the text. An nmap PORT table of more than one line grows that same row to fit column F (Courier New). If the command also wraps, the row uses the taller of the two. Each scan is a new row under the last filled date. A scan does not replace that row. Every cell in that row is top aligned. nmap checks that the sheet opens before the scan (no row yet), then waits until the scan finishes and writes the PORT table in column F (Result; Courier New, using the appendupdatedRangeso concurrent scans do not format the wrong cell). No open ports →No open ports.in the default font. nuclei writes the row before the scan. Whenoutput.txtends onNo vulnerabilities discovered., that same row’s column F becomesNonein the default font and the row height stays as it is. A skipped pass 2, or a finding on the last line, leaves column F empty. transom writes the row before the scan. Whentransom.htmcontains a software version or a disclosed internal address, that same row’s column F lists them in report order, one per line, in the default font. Several of those lines grow the row only when that is taller than the command. A result does not shrink the row. A software version is the Product:version label used on Active (for exampleMicrosoft ASP.NET:4.0.30319). An internal address is the address fromLocation discloses internal address. A report with neither leaves column F empty. Redact--api-tokenin logged commands. Bustinc-audit-config.js?v=/modern.csson Audit after UI changes. - Assets:
inc-audit-config.js; bust?v=/modern.csson Audit after UI changes; import-report injects the script onaudit.htm. Restart statusd after endpoint changes.
Report UI layout (CSS)
When designing or tweaking report page layouts (especially Audit and other modern.css tables/containers):
- Prefer
pxfor widths, min/max-widths, padding, and gaps you are dialing in with the operator. - Do not use
remfor layout sizing. Bootstrap setshtml { font-size: 10px }, so1rem = 10px(not 16px). That made earlier “rem” floors look far too narrow. %/width: 1%+nowrapis fine for shrink-to-content columns; once a column needs a fixed size, use px.- Names table: lift the generic 1200px container cap (
width: max-content; max-width: none) so Phone is not clipped. Do not assign column widths; Name / Title / Email stay auto/nowrap. Bustmodern.css?v=onnames.htmafter CSS changes. - Bust
modern.css?v=…on the affected page after CSS changes and deploy to the live engagement report when applicable. - Subdomains private table (top) uses the same columns as the public table beneath it: Subdomain, Category, IP Address. It is sized to that table’s width and column edges (
inc-data-table.js). The gap between the two tables is 56px: the 32px gap plus one text line.
misc/update.sh tool install order
Tool install/update blocks in misc/update.sh must stay in case-insensitive alphabetical order by tool/display name (e.g. DomainPasswordSpray → droopescan → Egress-Assess → … → WhatWeb → Windows Exploit Suggester → wpscan → xdotool).
- Do not group by feature (e.g. “CMS tools together”). Place new tools where the alphabet says, not next to a related tool.
- Comments already mark some blocks this way (e.g. CISA KEV after chromium, before curl); follow that convention.
- Same idea for README Update bullet lists when they mirror install order.
- nuclei-templates: Update is
sudo misc/update.sh. If~/nuclei-templatesexists, delete it (a symlink is removed without following it). Keep/opt/nuclei-templatesas a git clone ofprojectdiscovery/nuclei-templates. Each Update clones that path when it is missing or has no.git, otherwisegit pull --ff-only. Do not usenuclei -uthere: that only tracks release tags and would reset git HEAD. Point the operator’s~/.config/nuclei/.templates-config.jsonat/opt/nuclei-templates. Setdisable-update-check: truein~/.config/nuclei/config.yamlso a laternuclei -vdoes not zip-install the last release over the clone. Print Already up to date. (no commit hash or subject).
Host-scan reachability pre-check (expand dropdown only)
- Applies only to tools launched from the Subdomains expand panel: nuclei, robots, nikto, transom, ffuf, feroxbuster, plus droopescan / wpscan when shown. nmap does not use this HTTP gate.
- Before the tool runs,
run-host-scan.shdoes a curl HTTP/1.1 GET (15s max, same UA as the tool). One request records status and time (not two sequential GETs). Retry once on000. - robots probes
{origin}/robots.txt, not the site root (a slow/403 homepage must not skip a working robots.txt). - If no HTTP response (
000/ timeout): do not launch the tool. Write skip note in that run’soutput.txt, setmeta.skip_reason=host_unreachableand the same onstatus.json/latest.json, exit 1. - Expand panel shows Unreachable (red) under that tool box (plus txt link when present).
- Nikto HTM, Transom HTM, and robots WEB are omitted when
skip_reason=host_unreachable(no report / no Disallow list). - Nikto has no second internal pre-check (shared gate only).
- Help modals (ⓘ) and README host-scan section document this gate.
Host-scan expand (Subdomains)
- Host-scan chevrons appear only when the report is opened via Discover statusd HTTP (
http://127.0.0.1:17322/…, Open report / Active). Manualfile://open never shows chevrons, even if statusd is still running. Client export is the exception: the staged package shows the tool menu without Run and without the ⓘ button. TXT, HTM, and WEB in that package are ordinary links (web.htmfor WEB). The live operator report is not rewritten. - Chevrons on the full public Subdomains table (rows with HTTP status), not only
?software=/?cve=filtered views. - Title column: the default IIS start page (
IIS Windows Server) is omitted, along with other generic status titles (403 Forbidden,It works!). An empty title shows as-. - Software for expand:
?software=query wins; else fingerprint the row (Technologies tokens with version when present, title words soWelcome to nginx!matches nginx, web server, hostname labels — not only the first, souatapi.iis.example.commatches IIS). Priority products include CMS, Kibana, Grafana, Prometheus, Elasticsearch, Jenkins, Kafka UI / Kafbat UI / AKHQ, Filebrowser, SonarQube, RabbitMQ, Redis Commander, Kiali, Kubecost, Superset, GitLab / Gitea / Gogs, Keycloak, Rancher, Argo CD (hostnameargocd/argo-*), Eureka, Harbor, MinIO, Nexus, JFrog / Artifactory, Strapi, CloudBeaver, DBeaver, pgAdmin, UiPath (hostnameaccel360), Control-M (title / hostnamecontrol-m), Oracle (hostnameoci-adb-control/ realm OCI ADB Control; not the bareocicluster label), Tomcat, WildFly / JBoss, SharePoint, IIS, nginx, Apache, ASP.NET, PHP, Node.js, CrafterCMS, Java (not JavaScript). Named apps beat generic Java (SonarQube + Java → SonarQube). Citrix / NetScaler AAA (title NetScaler AAA, Unified Access, tech Citrix) is fingerprinted for nuclei (-tags citrix,netscaler). Not Cisco ASA VPN. Technologies display drops bare Java when a named Java app is already listed, dropsWindows Server, and aliases WappalyzerSonarQubesto SonarQube. - nuclei only when a product is known (filter or fingerprint). Do not offer nuclei for blind
-tags techwith empty software. Backendrun-host-scan.shrefuses nuclei when SOFTWARE is empty. Nucleioutput.txthas no Output: filesystem path (Pass 1 and Pass 2 both use Findings:). Prefix real match lines with[*]; leaveNo vulnerabilities discovered.unprefixed. Blank line before=== Pass 2. When that sentence is the last non-empty line ofoutput.txt, the Google Sheet Result cell for that scan isNone. - robots / nikto / transom / feroxbuster / ffuf always on expand when the UI is shown. nmap after robots when that IP has Shodan ports, or the row URL is http/https (then include 80 or 443 even if Shodan is empty /
not_found). Split TCP/UDP from Shodan host JSONdata[].transport; if transport is missing, ports on the SCANNINGUDP=list (scan/nmap.sh) are UDP, else TCP. Port 53 is always both TCP and UDP when it is in the Shodan set. TCP-only:nmap -Pn -n --open -sTV -p <ports> --stats-every 20 <host>(no sudo). Any UDP:sudo nmap --privileged -Pn -n --open -sTV -sUV -p T:<tcp>,U:<udp> --stats-every 20 <host>(sudo -vin the host-scan terminal if no cached ticket; abort if sudo fails — do not fall back to TCP-only). Already root skips sudo. No HTTP pre-check. If nmap raw logssendto Operation not permitted(typical on VPN/TUN), TXT warns and rewrites UDP rows (tcpwrappedis not a fingerprint; VERSIONUDP probe blocked locally). TCP rows stay. web (Firefox tabs) when SERVICE is http/https (ssl/httpandssl/unknown→ https). Order: robots → nmap (if Shodan ports or http/https) → nuclei (if product) → CMS tools → nikto → transom → feroxbuster → ffuf. - transom: box sits immediately to the right of nikto. Run scans the row URL only (
--timeout 10s, hard stop 11m). txt isoutput.txt; htm istransom.htmwhen the scan ran. A software version in that report is written to the Google Sheet Result cell as the same Product:version label Software Versions uses. A disclosed internal address is written there as the address. Each is one line, in report order. Other findings stay out of that cell. Update installs the git tree at/opt/transom. - robots: expand box label is robots.txt (not uppercased ROBOTS). Fetch
/robots.txt(same idea as multiTabs → Directories in robots.txt). txt = rawrobots.txtbody; web = open Disallow directories in Firefox viadiscover-robots:→misc/open-robots-tabs.sh(only whendisallow_count> 0). SkipDisallow: /(site root is not a directory to open). Keep query-string Disallow paths (Drupal/?q=admin/is not site root). Run does not open Firefox. Same web label on Audit. - ffuf / feroxbuster web: green web (Firefox tabs) only when the run has at least one finding URL. Auto-filter-only / empty JSON → txt only. Count stored as
meta.url_count. Same web label on Audit log and Target scans. - web on Windows / exported reports: Edge on Windows opens web as a normal
target="_blank"link toweb.htmin that run directory (same kind of link as Nikto htm).web.htmlists the same HTTP(S) URLs. The Discover host (statusd, browser not Windows) still opens Firefox throughdiscover-robots:/discover-ffuf:/discover-ferox:/discover-nmap-web:. Audit build writesweb.htm. A package exported before that file exists needs a new export. - droopescan / wpscan gate on CMS software (query or fingerprint). WordPress → wpscan only (no droopescan for WP). Drupal / Joomla / Moodle / Silverstripe still use droopescan when matched. Droopescan runs
--hide-progressbar; report TXT drops percent-bar lines ((0%)/12/4000) and leading[+], and writes URLs found. - Each tool box has a Unicode ⓘ help modal on the operator report. Client export omits it. Finished stamps use the Config Time zone (same display conversion as Audit; on-disk stamps stay UTC). Bust
inc-host-scan.js?v=…(andmodern.css?v=…on Subdomains) after changes and sync via Import when testing live reports.
Shodan panel Update (Subdomains)
- Shodan ▸ expand panel shows an Update button only on Discover-hosted pages (
http://127.0.0.1:17322/…). Manualfile://never shows it. - Backend: statusd
POST /shodan-refresh→recon/shodan-enrich.py <report> --ip <IP> --json(force host API lookup; rewrites that host cache + index; audit log line). - Requires
SHODAN_API_KEYfrom shell or~/.discover/api-keys. Bustinc-shodan.js?v=…/modern.css?v=…after UI changes; restart statusd (Open report) so the new endpoint is live. - Opening the panel on statusd calls
GET /shodan-status(api_keytrue/false only). If false, show where to add the key (~/.discover/api-keys) and disable Update.
API keys
- Preferred file:
~/.discover/api-keys(KEY=valuelines;chmod 600). Template:resource/api-keys.example. - Keys:
NVD_API_KEY,SHODAN_API_KEY,WPSCAN_API_TOKEN(optional free token for wpscan vuln DB;run-host-scan.shloads api-keys and passes--api-token),X_API_KEY(optional bearer token; Audit Config → X only, not the APIs panel),GITHUB_TOKEN(optional; threat-feed GitHub search only, not the APIs panel). Saving APIs leaves both of those keys unchanged. - Lookup order: shell export →
~/.discover/api-keys(first non-empty wins per key). - Update:
misc/update.shensures the file exists — if missing, copiesresource/api-keys.example→~/.discover/api-keys(chmod 600). Undersudo, seeds the invoking user’s home (SUDO_USER), not only root. If already present, only re-applieschmod 600(quiet). - Auto-migrate: if
$DISCOVER/.envor~/.discover/.envstill exist, Discover merges them into~/.discover/api-keys(existingapi-keysvalues win) and removes the legacy files. Implemented insoftware-cve.migrate_legacy_api_key_files()(also run from Active / Shodan shell loaders). - Agent / automation must never destroy live secrets:
- Do not run
discover-config.py set-api-keys, statusdPOST /config/api-keys, or any write to~/.discover/api-keys(or legacy.envkey files) with dummy/test values. - Do not “verify” save paths against the operator’s real key file. Use a temp file, dry logic, or read-only checks.
- Do not clear, overwrite, or restore keys unless the operator explicitly asks to save or change a specific key.
- Tests may read presence only (configured / empty); never paste or rewrite real key material for convenience.
- Do not run
Report Export (Audit only)
- No Domain menu item for export. UI is an Export button at the top of Report → Audit only when the page is Discover-hosted (
http://127.0.0.1:17322/…). Not shown on Passive or Active. Manualfile://never shows the button. - Modal: Client / Defender / Operator radios + Export + Cancel; success shows the output path (
$HOME/databy default). - Defender CSV headers: Time UTC, Operator, Operator IP, Target, Action.
- Backend: statusd
POST /export→recon/export-report.sh --kind … --report … --out-dir … --quiet(JSON path on stdout). - Client
pages/audit.htm: opens on All (the Audit default) and omits Scans per day and By operator. Operator export and the live report keep both panes. - Client Subdomains: staged package shows the host-scan tool menu without Run and without the ⓘ button. TXT, HTM, and WEB are ordinary links. WEB opens
web.htm. Operator export and the live report keep Run, the ⓘ button, and chevrons only on statusd. - Client omits
tools/gowitness/gowitness.jsonl. Yes links already point at the screenshot JPEGs. Operator export keeps the JSONL so an operator import can rebuild those links. - Client omits
assets/report-mode.json. The HTML report does not read it. Operator export keeps the operator stamp. Import → Operator scans refuses a client package whenexport-meta.jsonkind isclient,assets/report-mode.jsonmode isclient, orpages/subdomains.htmcontainswindow.DISCOVER_CLIENT_VIEW=true. - Client omits
export-meta.json. The export is still recorded on the live engagement intools/exports/log.jsonland the audit log. Operator export keeps the file. - Client omits
tools/exports/(log.jsonl). The Exports table is already inpages/audit.htm. Operator export keeps the ledger. The live engagement still appends each export totools/exports/log.jsonl. - Client omits raw Passive dumps at the top of
tools/whose names start withz(zsubfinder,zcrtsh,zarin-emails,zarin-names, and the other theHarvesterz*files). Passive already merged them into emails, names, subdomains, hosts, and the document lists. The HTML report does not read them. Operator export keeps them. - Client omits source files the HTML pages already contain:
whatweb.json,httpx.jsonl,subdomains,emails,names,names-phones.tsv,names-manual.tsv,hosts,public-ips,private-ips,private-subs,dns-private.tsv,squatting,records,whois-domain,whois-ip,active-alive.tsv,active.txt,active-targets.txt,import-batch-hosts.txt,subdomains-import.tsv,passive-scan-date, and.DS_Store. Operator export keeps them. - Client omits Shodan
summary.json,summary.tsv, andindex.json. The panel usesindex.js,kev-ids.js, andhosts/*.json. - Client host-scans keep
output.txt,robots.txt,nikto.htm,transom.htm,web.htm, andstatus.js. Other run files (ffuf.json,ferox.json,nikto.conf,meta.json,latest.json,status.json,nmap.raw,nuclei.txt,nuclei-pass2.txt, and the raw logs) are omitted afterweb.htmis written. Operator export keeps them. - Client keeps operator IPs in the Audit page table. Import events that already store a dash stay a dash. The package omits
tools/audit/log.txtandlog.txt.bak-*. The live engagement still appends to that log. Operator export keeps it. - Assets:
inc-report-export.js,modern.css(export classes); import-report syncs JS. Bustinc-report-export.js?v=…after changes.
Import subdomains (Audit Import hub / CLI)
- Two modes: existing (Firefox/Pentest-Tools/TSV) or team-csv (
subdomain,ip,category). UI: Audit → Import → Subdomains. CLI:import-subdomains.sh --report … --mode … --import … [--run-active] [--json]. - CSV list: one IPv4 per host (empty IP → dig). Skip hosts already in
tools/subdomains(no overwrite). Category = Discover rules first, else CSV. Never writerecon/subdomain-categories.tsv. - A host whose address is
1.1.1.1, or whose missing address resolves to1.1.1.1, is left out. A listed1.1.1.1is not replaced by another lookup. - After import: refresh
pages/subdomains.htmandpages/hosts.htm(unique public IPs). CSV list also writestools/import-batch-hosts.txt(new public hosts only) and may offer Active on that batch only (DISCOVER_ACTIVE_SCOPE=import-batch). - After import + Active (full or import-batch): rebuild the entire Active page from merged
tools/artifacts — Scope (public/private/responding), status codes, alive-by-category, CMS, web servers, technologies, software versions + CVE enrichment, Login pages, and scan date. Batch Active must merge httpx/whatweb/gowitness into the engagement files first, then call the same fullpages/active.htmrebuild (not a batch-only summary). Scan date = latest httpx timestamp, not the first line. - Active public-DNS check: before httpx,
dig +timeout=2 +tries=1 +short A <host> @1.1.1.1(parallel). RFC1918,127.0.0.0/8,169.254.0.0/16, or0.0.0.0drops that host from httpx and recordshost<TAB>ipintools/dns-private.tsv.tools/private-subsis stored-private rows plus those leaks (dig IP wins). Do not rewrite the public IP intools/subdomains. Do not use the operator resolver (VPN split-horizon is not a finding).
Active Login pages (by category)
- Login pages table on Active (under CMS when any category exists). The Source / Type column icon (same look as sort) switches By source (default, ▲) · By type (▼). It does not sort that column. Unicode ⓘ next to the heading explains overlapping By source counts vs By type. Asset:
inc-active-login-view.js. - By source column Source: Path, Title, Tech, Status with host counts; each links to Subdomains
?login=path|title|tech|status. - By type column Type: Basic (HTTP challenge: Basic / Digest / NTLM / Negotiate, including 401 with empty title) · Form (Path / Title / Tech, or WhatWeb PasswordField). Generic
401 Authorization Requiredtitles with HTTP-challenge do not count as Form. Host may be both. Links:?login=basic|form. PasswordField, PoweredBy, Index Of, Object (HTML tag), header/protocol noise (HSTS,HTTP/3,X-UA-Compatible), andWindows Serverstay out of Technologies / Software versions (NOISE_PLUGINS). - Source categories (host may match more than one; counts are unique hosts per category, alive public hosts):
- Path — newest
tools/host-scans/<host>/ffuf/*/ffuf.jsonFUZZ path matches high-confidence login paths (login,wp-login.php,oauth,sso, …), or httpxfinal_url/urlpath (/login.jsp, …). Avoid bareadmin. SPA filter: when a run has many hits sharing one body length (≥50 results, mode count ≥20, mode ≥50% of results), login-named paths with that same length are ignored (soft-200 app shell). - Title — httpx/page title matches login / sign-in / SSO / unauthorized / password phrases, plus common non-English titles (
Zaloguj,Anmelden,Connexion, …). - Tech — fingerprint includes products that typically expose a login UI (CMS, Grafana, Kibana, GitLab/Gitea, Citrix, Keycloak, Jira, Confluence, Argo CD, Harbor, MinIO, Rancher, UiPath, pgAdmin, Control-M, …). Match the product as a word so
Atlassian Jiracounts as Jira. httpx tech tokens, page title, and hostname all count (SPA consoles often only have HSTS in tech). - Status — HTTP 401 from httpx and an auth-related page title, or 401 with HTTP-challenge tech (Basic / Digest / NTLM / Negotiate) even if the title is empty. Bare 403 and bare 401 with empty title and no challenge are noise.
- Skip Microsoft SSO: if httpx
final_url/urlcontainslogin.microsoftonline.com(or related Microsoft IdP hosts), the host gets no Login pages signals (all four). Citrix: short live probePOST /p/u/doAuthentication.do→ followdoSamlwhen present; if the SAML hop is Microsoft, skip (covers NetScaler AAA that only show LogonPoint in httpx). RNAS: titleUnified Access RNASor hostnamernas-*/.rnas.— remote network access gateways, skip (not app logins).
- Path — newest
- Subdomains public rows get
data-login-path|title|tech|status="1"when rebuilt (Active /write_subdomains_active_page/ software-cve refresh). Filter:inc-subdomains-filter.js(?login=). Bust filter?v=after changes.
Threat intel (Active Software Versions)
- Alerts is a full-size header button on Active, immediately left of Enrich, statusd only. The label shows the unreviewed count (
Alerts 3). It opens the Threat intel list for software in this report. Opening the report, opening Active, and opening this list do not start a check. The list shows Last check asmm/dd/yyyy - hh:mmin the view timezone (Zwhen that zone is UTC). The stored stamp stays UTC. No check yet says No check yet. Check now is the only way a check starts. While a check runs, the status lists one line per source as that source starts:[*] Checking NVD.then KEV, advisories, GitHub, and Metasploit. The X line includes the configured account count, for example[*] Checking 4 X accounts.One account uses the singular. Check now stays disabled. Close stays available. When the check finishes, a blank line and then Check finished are added under those lines, with the new-alert count or the note from a first check. The source lines stay. An empty list says No alerts yet. A row opens that alert. Back (or the header close, or Escape) marks that alert reviewed and returns to the list.file://and Client export do not show the button. Client and Defender exports omittools/threat-feed/. Asset:inc-threat-feed.js. Bust?v=andmodern.csson Active after changes. - The check watches Software versions in
tools/software-cves-cache.json. Sources: NVD (new CVEs for those CPEs since the last check), CISA KEV, Exploit-DB, CISA advisories, WordPress and Drupal security feeds when that product is present, GitHub repositories for CVEs already on that software and for CVEs or KEV hits the check just found, local Metasploit exploit modules for those CVEs, and X accounts from Config. The check reads the installed framework catalog. The first check only records what is already public. The first read of the module list on an engagement that already has a baseline records the current modules and adds no Metasploit alerts. Later checks add an alert when a new exploit module matches a CVE on the report. Queries use product and CVE identifiers. Nothing is written to the audit log. - There is no daily clock and no check when the report opens.
POST /threat-feed/checkruns only from Check now.POST /threat-feed/reviewedmarks one alert reviewed.GET /threat-feedreturns the list and does not start a check. OptionalGITHUB_TOKENin~/.discover/api-keysraises the GitHub search limit. X uses the Config bearer token and account list. Restart statusd after endpoint changes.
Active page Enrich (Shodan + Software CVEs)
- Enrich button on Active (statusd only). Modal title Enrich Engagement Data. Checkboxes, default all on, top to bottom: KEVs, Shodan, Software CVEs. When more than one option runs and the Active page was rebuilt, the finished modal replaces Cancel and Enrich with Reload Active page. One option leaves Cancel and Enrich, and shows Reload Active page in the results when the page was rebuilt. With results showing, the dialog grows to the viewport and the summary pane grows with it, so less of the list sits in a scrollbar.
- KEVs →
POST /kev-refresh→active-tech.py <report> --refresh-kev --json. Downloads the CISA catalog toresource/kevs.json(same feed as Update), rewritestools/shodan/kev-ids.js, and rebuilds Active so Top CVE badges use the new catalog. No NVD queries. No API key. - Shodan →
POST /shodan-refresh-all→shodan-enrich.py <report> --force --json-summary - Software CVEs →
POST /software-cve-refresh→active-tech.py <report> --refresh-cves --json(re-queries NVD for missing/empty cache entries by default;--force-alloptional; rebuildspages/active.htmSoftware versions table +cve-software-index.js)
- KEVs →
- Software versions CVE data is NVD CPE, not Shodan host vulns. Permanent skips: Microsoft HTTPAPI, Java Servlet, JavaServer Pages (
SKIP_PRODUCTSinsoftware-cve.py). IIS usesmicrosoft:internet_information_services.IIS:10stays out of this table. jQuery UI usesjqueryui:jquery_ui. WordPress, Slider Revolution, Yoast SEO, and WPML are mapped. SharePoint build numbers stay unmapped. The lookup asks NVD for a version range and drops a CVE whose version shape does not match the label (a year against a dotted build). Enrich lists each product that was not looked up. - Software versions also read the newest
transom.htmfor each host.X-AspNet-Version 4.0.30319and the olderX-AspNet-Version discloses 4.0.30319wording becomeMicrosoft ASP.NET:4.0.30319.X-AspNetMvc-VersionbecomesASP.NET MVC. An outdated Apache, PHP, nginx, or Microsoft-IIS banner, and a versionedX-Powered-Byvalue, use the same Product:version labels. A host already counted for that label is not counted again. An unversioned product token on that host is replaced by the versioned label. The Subdomains Technologies column shows that label, and?software=matches it. Every Software Versions label links to that filter, including a version with no CVEs. Missing headers, cookies, and other Transom findings stay out of this table. - Top CVE on Active: on the Discover host (statusd, browser not Windows) the CVE id opens Firefox tabs for NVD, Rapid7, Tenable, Exploit-DB, Sploitus, CVEbase, and GitHub via
discover-cve:→misc/open-cve-tabs.sh. In Edge on Windows that control opensassets/cve-links.htm, a page of those same links. The KEV badge stays a direct CISA catalog link. Bustinc-active-cve-tabs.js?v=after the click script changes. A package exported beforecve-links.htmexists needs a new export. - Assets:
inc-active-refresh.js; bust?v=andmodern.cssafter UI changes. Restart statusd after endpoint changes.
Trending
Quiet since April.thin dataabout the whole repository
Who's talking about leebaird/discover
- baohuiking/Sec_search“[WIP] Add LLM jailbreak classification with default exclusions”GitHub · Apr 29, 2026
- gwen001/offsectools_www“[addtool] discover”GitHub · Jun 26, 2024
- tracelabs/tlosint-live“Add more tools”GitHub · Oct 7, 2020
- lanmaster53/recon-ng“/bin/sh: 1: db: not found”GitHub · Oct 13, 2019
- laramies/theHarvester“Move from getopt to argparse, plus other changes”GitHub · Jan 20, 2019
The biggest 5 of 9 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 9
Talked about on GitHub (9 times).
On GitHub · 9
- Apr 29, 2026[WIP] Add LLM jailbreak classification with default exclusions — baohuiking/Sec_search0 reactions
- Jun 26, 2024[addtool] discover — gwen001/offsectools_www0 reactions · 2 comments
- Oct 7, 2020Add more tools — tracelabs/tlosint-live0 reactions · 1 comment
- Oct 13, 2019/bin/sh: 1: db: not found — lanmaster53/recon-ng0 reactions · 4 comments
- Jan 20, 2019Move from getopt to argparse, plus other changes — laramies/theHarvester0 reactions · 4 comments
4 more on GitHub
- Nov 5, 2017进击的安全 — mylamour/blog0 reactions · 3 comments
- Nov 9, 2015Improving Ping Discovery thoughts — ivre/ivre0 reactions · 3 comments
- Jul 27, 2015add ssh key prior to updating — weaveleftnright/tribal-chicken0 reactions
- Sep 23, 2014msfconsole should be explicit if a given exploit is TCP or UDP (or other) — rapid7/metasploit-framework0 reactions · 4 comments
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 28,693 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
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.

