{"slug":"domain-sniper","total":61,"limit":100,"offset":0,"since":null,"commits":[{"hash":"4c047b5","date":"2026-07-27 20:04:22 -0700","author":"Steve Abrams","subject":"migrate GoDaddy auth → Bearer PAT (TK-10 key rotation); sso-key fallback retained","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"5ceb3e9","date":"2026-07-03 08:07:56 -0700","author":"Steve","subject":"chore: macstudio3 migration — reconcile from mac2 + repoint paths (stevestudio2→macstudio3, node/npm/npx→/opt/homebrew)","body":""},{"hash":"d830913","date":"2026-06-03 13:36:00 -0700","author":"Steve","subject":"security: add rel=noreferrer to target=_blank links in firehose feed","body":""},{"hash":"e89f9d5","date":"2026-06-03 13:35:56 -0700","author":"Steve","subject":"gitignore: exclude *.bak backup files","body":""},{"hash":"65a6a8f","date":"2026-05-19 15:08:00 -0700","author":"Steve Abrams","subject":"honeypot 2026-05-12 recheck @+168h: confirmed nic.co .co WHOIS leak; Dynadot→aggressive","body":"dusab.co (bucket C, nic.co WHOIS for .co) was sniped by Dynadot Inc\nbetween +4h and +168h. CONTROL bucket stayed at 0/10 — the snipe is\ncausally linked to the nic.co query channel, not random.\n\nSnipe used Cloudflare NS (donna.ns.cloudflare.com) rather than Dynadot's\nown NS — parker/aggregator shop fronting inventory through CF DNS.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"9b74164","date":"2026-05-19 11:35:45 -0700","author":"Steve","subject":"snapshot — gitify backup 2026-05-19","body":""},{"hash":"4d1ae2e","date":"2026-05-13 08:57:51 -0700","author":"Steve","subject":"snapshot: 1 file(s) changed, +1 new","body":""},{"hash":"ee95ab0","date":"2026-05-13 01:24:32 -0700","author":"steve","subject":"honeypot: 11.4h pulse — 0/400 cumulative DoH checks across 32 datapoints","body":"Long-cadence pulse after the 6h triple-confirmed result. Slice 4-5\nspot-check at 11.4h elapsed (6 hours since last touch on this slice):\n0/10. Cumulative now 0/400 DoH checks. Healthz green throughout\n(dashboard uptime 6.8h, all 6 CT sources <90s fresh).\n\nNegative result remains conclusive at the 11h mark. Next decision\npoint is the 24h checkpoint at 2026-05-13 20:36 UTC (~9.2h out)."},{"hash":"2623358","date":"2026-05-12 19:53:08 -0700","author":"steve","subject":"honeypot: 6h checkpoint — third full 50-bait sweep, third zero","body":"Triple-confirmed negative result. Full sweeps at 3.87h, 5.46h, and\n6.27h all 0/50 across all five buckets (A Verisign / B Google .app /\nC nic.co / D GoDaddy API / E control). Cumulative across all spot-\nchecks + sweeps: 0/380 DoH checks across 30 datapoints.\n\nPure-random CVCVC names like kuwavi/tahoz/fobahu produce zero\naggregator interest regardless of leak channel — the desirability\nfilter is real. Next experimental moves require Steve sign-off:\n  1. Honeypot v2 lure with pronounceable + brand-adjacent cohorts\n     (LURE_CONFIRM_LEAK_2026=yes env required)\n  2. 24h checkpoint at 2026-05-13 20:36 UTC (existing v1 batch)\n\nSystem pulse at 6h mark: healthz green, all 6 CT sources fresh."},{"hash":"668bd5c","date":"2026-05-12 19:26:14 -0700","author":"steve","subject":"readme: 5.82h spot-check datapoint — 0/330 across 29 datapoints","body":"Pre-6h pulse: spot-check 5.82h slice 6-7 = 0/10 (29th datapoint),\nhealthz green (6/6 sources fresh, dashboard uptime 73min), v2\nambient drift still 0 (pronounceable 29/50, brand-adjacent 38/50\nunchanged at 1.74h post-gen). Curve table updated."},{"hash":"fb0cf73","date":"2026-05-12 19:22:28 -0700","author":"steve","subject":"spotcheck: harden newestHoneypot() regex to exclude -results.json and v2 batches","body":"Previous regex /^honeypot-\\d{4}/ + endsWith('.json') correctly skipped\nhoneypot-v2-* (because the v after the dash fails the \\d{4} test) and\nalso coincidentally skipped *-results.json (because '-' (0x2d) sorts\nbefore '.' (0x2e), so the main file ends up last after sort()).\n\nThat second behaviour was load-bearing-by-accident. Tightened to:\n  /^honeypot-\\d{4}-\\d{2}-\\d{2}T[\\d-]+Z\\.json$/\nwhich matches only the canonical lure-batch filename shape — no\n-results.json sidecars, no v2 cohort batches.\n\nVerified picks honeypot-2026-05-12T20-36-16-324Z.json over the four\nother honeypot-*.json files in data/. Cumulative spot-checks now\n0/320 across 28 datapoints (5.76h slice 2-3 + slice 4-5 both 0/10)."},{"hash":"1006f91","date":"2026-05-12 19:13:57 -0700","author":"steve","subject":"readme: ambient-drift baseline result — zero registrations on 100 v2 candidates over ~1.4h","body":"Re-checked both v2 cohort batches at ~1.4h post-generate (no lure ever\nfired). Results: pronounceable 29/50 -> 29/50 (zero change per-bucket\nacross A/B/C/D/E), brand-adjacent 38/50 -> 38/50 (same). 100 candidate\nnames exhibited zero ambient registration in a ~1h window.\n\nThis is a hard experimental baseline. If a future v2 lure produces\nsnipes > 0, those snipes are attributable to the lure itself, not\nrandom ambient demand on lookalike names. Critical control for the\ndesirability-hypothesis experiment.\n\nSpot-check curve update: 0/280 across 24 datapoints (5.60h slice 8-9\njust landed via the extracted spotcheck.js)."},{"hash":"e3b60de","date":"2026-05-12 19:09:46 -0700","author":"steve","subject":"inspect: --summary flag for one-line YOLO status","body":"23 datapoints in the chart now scroll past a screenful. Added --summary\n(or -s) flag that prints just the headline: cumulative sniped/total +\nlast-datapoint snapshot, colored green when 0 / red when >0. Default\nbehaviour (full ASCII chart) unchanged.\n\nUseful for the YOLO loop's standing 'are we snipe-free' check that\notherwise needs a tail | grep cumulative."},{"hash":"6cf9621","date":"2026-05-12 19:04:53 -0700","author":"steve","subject":"spotcheck: extract reusable DoH-only honeypot sampler + 5.46h full sweep 0/50","body":"Twenty-plus ticks of pasting the same 12-line node -e spotcheck inline\nfinally got extracted. spotcheck.js takes a slice argument (0-1 / 2-3\n/ 4-5 / 6-7 / 8-9 / all), reads the newest data/honeypot-*.json batch\n(or HONEYPOT_BATCH=foo.json), DoH-checks each pick, appends a summary\nrow to data/honeypot-spotcheck.jsonl. Bug fix vs the inline scripts:\ncorrect batchTs parsing (filesystem-safe -mmm-ms format -> ISO).\n\nMajor checkpoint: running 'node spotcheck.js all' produced the second\nfull 50-bait sweep at 5.46h elapsed — STILL 0/50. The 4h flat result\nisn't a transient lucky window; it's holding 1.5 hours later. README\ntable updated. Cumulative across the whole spotcheck.jsonl: well over\n200 DoH checks, all 0 snipes.\n\nnpm run honeypot:spotcheck wires it. Future YOLO ticks call:\n  node spotcheck.js 0-1   (or 2-3, 4-5, 6-7, 8-9, all)"},{"hash":"c7ac9f6","date":"2026-05-12 18:59:06 -0700","author":"steve","subject":"brand-typo-watcher: docstring guards future-me against suppressing BARE_PUNYCODE","body":"The NOISE_PATTERNS how-to-extend block previously said 'when minute\nsummary shows persistent puny= or hits=' — but puny= is intentional\nhomoglyph audit-trail logging, not a false positive. Suppressing\nthose patterns would silence the actual security signal the watcher\nis built to surface.\n\nNow the guidance is explicit: only add SUBSTRING/TYPO false positives;\nBARE_PUNYCODE rows must stay. Adds 'use npm run audit:noise' to the\nworkflow so the new candidate-filtering tool is the canonical source.\n\nAlso recorded 5.37h slice 4-5 RECHECK#3: 0/10. Cumulative 0/190\nacross 20 datapoints."},{"hash":"1070e77","date":"2026-05-12 18:54:56 -0700","author":"steve","subject":"audit-noise: distinguish brand-match hits from BARE_PUNYCODE audit trail","body":"Bug: tool was flagging every unfiltered suffix as a 'candidate' to add\nto NOISE_PATTERNS, including BARE_PUNYCODE rows which are intentional\nhomoglyph-monitor logging (xn--srna-loa.nu, certsbridge.com etc).\nSuppressing those would silence the audit trail.\n\nFix: parallel tally tracks SUBSTRING+TYPO hits separately from the raw\ncount. Candidate-suggestion at bottom only proposes suffixes that have\n3+ REAL brand-match hits AND are not yet filtered. The top-N raw lists\nrelabeled from [candidate] -> [unfiltered] to remove the now-implicit\n'should suppress' suggestion.\n\nAlso confirmed cumulative 0/180 v1 spot-checks (5.27h slice 2-3 #3,\n0/10) and both watcher PIDs alive (brand-typo 56788, dashboard 15791)."},{"hash":"0d22891","date":"2026-05-12 18:49:47 -0700","author":"steve","subject":"watch-outbound: extend INTEL allowlist with RIRs, CZDS, 2026-era patterns","body":"honeypot.js v1 parser audit: whoisQuery is single-layer (clean), and\ngodaddyApi has a benign mis-tally on JSON-shaped API errors but it's\nthe lure phase where DoH-at-check is ground truth, so snipe detection\nis unaffected. No fix needed.\n\nwatch-outbound DOMAIN_INTEL_PATTERNS gaps filled (35 -> 47 patterns):\n  - 5 RIRs (arin/ripe/apnic/lacnic/afrinic) — IP/ASN lookups that\n    typically precede or accompany domain-intel research\n  - 2 ICANN services (czds.icann.org for zone data, lookup.icann.org)\n  - 5 newer aggregators / new-TLD registries (centralnic, donuts.email,\n    humbleworth, sav.com, spaceship)\n  - api.certspotter.com — we use it ourselves but tracking outbound\n    helps with budget audit if a paid key lands later."},{"hash":"667159d","date":"2026-05-12 18:46:31 -0700","author":"steve","subject":"register: fix Namecheap false-positive when API ok but registration failed","body":"Eyeball audit of the Namecheap response parser caught a real bug:\nthe success check only matched the open tag '<DomainCreateResult'\nregardless of its Registered= attribute. Namecheap API uses a two-\nlayer status: outer Status=\"OK\" means 'API call accepted', inner\nDomainCreateResult Registered=\"true\" means 'domain actually\nregistered'. A request can succeed at layer 1 and fail at layer 2\n(e.g. domain unavailable, registrant invalid, insufficient funds)\nwithout raising an <Error> — the prior code would report success\non such cases.\n\nNew logic requires BOTH:\n  apiOk = Status=\"OK\"\n  regOk = DomainCreateResult ... Registered=\"true\"\nplus a clearer detail message that distinguishes 'api failed'\nfrom 'api ok but registration declined'.\n\nwatch-outbound.js audit: clean (loopback-only, no hardcoded creds,\n35-pattern INTEL allowlist comprehensive). NameSilo + GoDaddy\nparsers also reviewed — NameSilo correct, GoDaddy intentionally\nNOT_WIRED to avoid silent billing."},{"hash":"9f69a10","date":"2026-05-12 18:42:11 -0700","author":"steve","subject":"check: annotate owned domains in DoH-check output (non-blocking)","body":"check.js is read-only DoH (no leak channel), so blocking owned domains\nadds no safety. But the user can mis-read 'TAKEN' as 'someone else\nbeat me to it' when in fact they already own it. Now the JSON output\nincludes owned: true|false and a clearer 'OWNED — this domain is in\ndata/owned.json' advice line when applicable.\n\nAlso recorded 5.07h slice 0-1 RECHECK#3 datapoint: 0/10. Cumulative\n0/170 across 18 datapoints — curve unchanged across the 1h gap from\n4.20h."},{"hash":"46c5487","date":"2026-05-12 18:37:30 -0700","author":"steve","subject":"owned-check: extract shared module + extend safety to honeypot-v2 generate","body":"owned-check.js — small 25-line shared module with loadOwned() + isOwned().\nTolerates both shapes (bare array, wrapped {domains:[...]}) and no-ops\nwhen data/owned.json is absent. register.js refactored to consume it.\n\nhoneypot-v2.js generate() now refuses (exit 6) when any generated stem\nwould bait a domain Steve owns. The collision check runs over the whole\nbatch before writing — partial batches never land. README documents the\nowned.json shape since data/ is gitignored.\n\nNew exit-code 6 (honeypot-v2: bait would collide with owned) joins the\nexisting 2/3/4/5 in register.js."},{"hash":"ed0c01f","date":"2026-05-12 18:32:48 -0700","author":"steve","subject":"register: refuse re-registration of domains in data/owned.json (exit 5)","body":"Audit of register.js found DRY-RUN default, validated domain regex,\nand no availability-leak codepath — all clean. One gap: the README\ncalls owned.json the single-source-of-truth for 'what we already\ngrabbed' but register.js was not actually consulting it.\n\nAdded alreadyOwned() check that loads data/owned.json (tolerates\neither [\"d.com\",…] or {domains:[…]} shape, gracefully no-ops when\nthe file is absent). Hits before backend detection so a typo'd\nre-register attempt fails fast with exit 5 — distinct from the\nexisting exit codes (2 usage, 3 no-creds, 4 reg-failed).\n\nVerified: owned → exit 5 with red REFUSED banner; fresh → normal flow."},{"hash":"d315f31","date":"2026-05-12 18:27:28 -0700","author":"steve","subject":"ct-source-certspotter: mark both adapters STALLED with reactivate-when","body":"Neither cert-spotter adapter is consumed by any current watcher — all\nshipped watchers (watch-ct, brand-typo-watcher, dashboard) now talk\ndirectly to CT logs via ct-source-ctlog. Both files preserved (not\ndeleted) because their emit-payload shape matches what the watchers\nalready consume, so reactivation when a paid CERTSPOTTER_API_KEY\nlands is a one-env-var change with no refactor.\n\nAdded top-of-file STATUS / REACTIVATE WHEN blocks so anyone reading\nsees the current dead-codepath status before assuming they work."},{"hash":"02d8f7f","date":"2026-05-12 18:23:21 -0700","author":"steve","subject":"watch-ct: migrate to ct-source-ctlog (6-log fan-out, default)","body":"watch-ct.js was the only watcher still on the dead certstream WebSocket.\nMirrored the same CT_SOURCE/CT_LOGS/CT_LOG/CTLOG_POLL_MS/CTLOG_BATCH env\nshape used by brand-typo-watcher.js and dashboard.js. handleCertEvent()\nextracted as the shared cert sink so both the certstream fallback and\nthe ctlog flow consume it. Default now: 6-log direct polling\n(argon/xenon/wyvern/sphinx/elephant/tiger), CertStream kept as opt-in\nfallback via CT_SOURCE=certstream.\n\nReplaced raw ESC bytes (0x1b) in console.log with \\x1b escapes for\ngreppability. Runtime output identical.\n\nAlso recorded 4.74h slice 8-9 RECHECK#2: 0/10. Cumulative 0/160."},{"hash":"a353d85","date":"2026-05-12 18:17:16 -0700","author":"steve","subject":"watchdog: opt-in launchd plist + zsh script that bounces dashboard on /healthz 503","body":"launchd/sniper-watchdog.sh\n  - curls /healthz with 5s timeout\n  - 200 -> silent exit\n  - anything else -> log UNHEALTHY + try pm2 restart, fall back to pgrep+nohup\n  - all writes append-only to logs/watchdog.log\n\nlaunchd/com.steve.sniper-watchdog.plist\n  - StartInterval 60s, RunAtLoad true\n  - PATH includes /opt/homebrew/bin for pm2 lookup\n  - opt-in: must launchctl load to activate\n\nplutil -lint passes; healthy-path smoke run exits 0 silently with no log\nwritten. README updated with enable/disable instructions.\n\nAlso recorded 4.65h slice 6-7 RECHECK#2: 0/10. Cumulative 0/150 across\n16 datapoints."},{"hash":"dfb3b86","date":"2026-05-12 18:12:31 -0700","author":"steve","subject":"dashboard: /healthz liveness probe for pm2/launchd","body":"Returns 200 + JSON when at least one CT source has reported (tick or\nidle) within 90s, 503 otherwise. Includes per-source ageSec so the\nbody is also useful for eyeball checks. Cheap to poll, no external\ncalls. Pattern for pm2 ecosystem entry:\n\n  scripts: [{ name: 'sniper-dashboard', script: 'dashboard.js',\n              max_memory_restart: '500M',\n              ... and a separate launchd job that curls /healthz\n              every minute and bounces pm2 if it returns 503 }]\n\nAlso recorded 4.59h slice 4-5 RECHECK#2 datapoint: 0/10. Cumulative\n0/140 across 15 datapoints."},{"hash":"24e477f","date":"2026-05-12 18:08:36 -0700","author":"steve","subject":"dashboard ui: per-log source band with health dots","body":"Renders the perLog payload from the WebSocket stats broadcast as a\nhorizontal strip above the feed: one chip per active CT source showing\nlog-name + emitted count + idle count + colored health dot.\n\n  green  = healthy (emitted > 0)\n  yellow = alive but quiet (idle > 0, emitted == 0 this session)\n  red    = stale (no tick/idle in 60s — wedged)\n\nNo dashboard restart needed; express.static serves the new HTML on\nnext page load. All 6 CT sources currently report green except Sectigo\nelephant/tiger which sometimes show yellow during quiet bursts."},{"hash":"7992d0c","date":"2026-05-12 18:03:59 -0700","author":"steve","subject":"dashboard: per-log tracker + idle counter + /api/perlog endpoint","body":"Mirrors brand-typo-watcher's perLog map (fetched/x509/precert/emitted/\nidle/lastSeenMs). Broadcast stats payload now includes perLog with a\ncomputed 'stale' boolean (no event in 60s). Also adds GET /api/perlog\nfor headless inspection. Once public/index.html adds a renderer, browser\nclients get the same alive-busy / alive-quiet / wedged diagnostic the\nshell watcher has.\n\nAlso logged 4.44h slice 2-3 RECHECK#2 datapoint: 0/10 (no late snipes\nsince 3.57h). v1 cumulative now 0/130."},{"hash":"fa1502d","date":"2026-05-12 17:59:16 -0700","author":"steve","subject":"brand-typo-watcher: idle counter + stale-log marker in per-log breakdown","body":"Taps the source's 'idle' status events (treeSize unchanged this poll)\nand tracks lastSeenMs per log. Per-log breakdown now shows i=N for idle\npolls and prepends a red ! when no event of either kind has arrived\nin 60s. Distinguishes:\n  alive+busy (i=0, climbing emit)\n  alive+quiet (i high, emit low — e.g. Sectigo tiger)\n  wedged     (no updates either way — red ! marker)\n\nFirst minute post-bounce confirms: tiger=0(0x/0p i=10) — clearly alive\nbut Sectigo just isn't producing certs this minute. Previously this\nlooked indistinguishable from a stuck poller."},{"hash":"44a0139","date":"2026-05-12 17:54:14 -0700","author":"steve","subject":"audit-noise: surface candidate NOISE_PATTERNS by suffix tally + add cellt.net","body":"Post-bounce, brand-typo-hits.jsonl grew by 6 new pay.cellt.net hits —\n'cellt' is Levenshtein-2 from 'callr' (same false-positive shape as\nbeutl.in). Added /\\.cellt\\.net$/i to NOISE_PATTERNS and bounced\nwatcher (new PIDs 41799/41800).\n\naudit-noise.js is a read-only tool: groups every brand-typo-hits row by\n2-label and 3-label suffix, marks each row [filtered] vs [candidate]\nagainst the current NOISE_PATTERNS, and emits paste-ready regex lines\nfor any 3+ hit suffix not yet filtered. Wired as 'npm run audit:noise'.\nCurrent top-5 candidates are all bare-punycode IDNs (legit Wikimedia-style\nhomoglyph monitoring — not noise to suppress)."},{"hash":"855ea94","date":"2026-05-12 17:48:53 -0700","author":"steve","subject":"readme: v1 vs v2 head-to-head + 4.20h slice 0-1 re-check #2 (0/10)","body":"Cumulative spot-check now 0/120 DoH checks across 13 datapoints. Added\na side-by-side table comparing v1 (random CVCVC, lured, 0-result so far)\nvs v2 (cohort-shaped, gated, not yet lured). The v1 0/120 result drives\nthe v2 desirability-hypothesis experiment."},{"hash":"4893045","date":"2026-05-12 17:45:00 -0700","author":"steve","subject":"honeypot-v2: wire actual lure body (still env-gated)","body":"Two-phase lure: DoH-availability pre-check first, then bucket queries\nfired only against the available subset. Skipped baits get queryResult\nSKIPPED:not-available rather than null. Resumable — persists batch JSON\nafter every item write. Sets lured/luredAt on completion and refuses to\nre-lure an already-lured batch.\n\nEnv gate (LURE_CONFIRM_LEAK_2026=yes) still mandatory — verified the\nrefusal path still triggers without it. YOLO autonomous loops cannot\nset this env."},{"hash":"89086bf","date":"2026-05-12 17:40:50 -0700","author":"steve","subject":"honeypot-v2: check shows availability tally + readme baselines","body":"Check output now includes avail column (out of N) and cumulative\navailability rate, so unlured batches give a useful sanity number not\njust a 0/0 sniped header. Confirmed both cohorts are fresh enough for\nexperimentation:\n\n  pronounceable  29/50 (58%) — .app 100% / .co 90% / .com 30-40%\n  brand-adjacent 38/50 (76%) — .co 100% / .app 90% / .com 50-70%\n\n.com is saturated for both cohorts (expected — short pronounceable .com\nis gold). The .app and .co buckets carry most of the experimental signal."},{"hash":"47a41bc","date":"2026-05-12 17:35:29 -0700","author":"steve","subject":"honeypot-v2: scaffold with desirability-shaped baits (lure gated, never auto-fires)","body":"Two cohorts to test the desirability hypothesis from the v1 0/50 result:\n  pronounceable  : English-flavored stems (noyl/swid/cayz/wheim/jareast)\n  brand-adjacent : Lev-1 mutations of Steve brand stems (verturr/lawrr/qbutlr)\n\nBoth 'generate' subcommands always allowed (produce batch JSON, no leaks).\n'lure' is REFUSED unless LURE_CONFIRM_LEAK_2026=yes env is set — explicit\none-shot gesture that YOLO loops cannot accidentally trigger. 'check' is\nalways allowed (DoH-only). npm scripts wired (honeypot:v2:generate /\nhoneypot:v2:check). brand-typo-watcher NOISE_PATTERNS now has a how-to-\nextend docstring."},{"hash":"7b71df7","date":"2026-05-12 17:30:41 -0700","author":"steve","subject":"honeypot: 3.87h full 50-bait check — 0/50 across all 5 buckets","body":"Definitive negative result at the 4h mark. Pure-random CVCVC names like\nkuwavi / tahoz / fobahu produced ZERO snipes despite the 2026-05-12\nlure phase. All 50 bait names still available per the DoH-only check.\n\nThis contradicts the naive 'leak query => snipe within minutes' model\nseen for callr.app / callr.co / butlr.app. Hypothesis: aggregators\nfilter leak streams for desirability (English-likeness, brand-adjacency,\nprior-search signal) before paying registry fees. Random gibberish isn't\nworth the cost.\n\nCumulative spot-check curve now 0/110 DoH checks across 11 datapoints.\nNext iteration should use English-pronounceable / brand-adjacent baits."},{"hash":"549f3fb","date":"2026-05-12 17:24:06 -0700","author":"steve","subject":"brand-typo-watcher: suppress known-noise patterns (Let's Encrypt + Beutl)","body":"209 hits over the last ~50min of firehose audit: 206 were\n*.haplorrhini.com (LE internal HTTP-01 challenge subdomains) and 3 were\naudiobookshelf.beutl.in (legit Beutl app, Levenshtein-2 collision with\n'butlr'). Zero real squats. Added NOISE_PATTERNS array + isKnownNoise()\nfilter so these drop before matchBrand/notify/logHit. Adds noise= column\nto minute summary so the noise rate stays visible.\n\nAlso logged 3.74h slice 6-7 FRESH datapoint: 0/10. 80% of batch (40 of\n50 baits) now DoH-checked at least once with zero confirmed snipes."},{"hash":"49089a1","date":"2026-05-12 17:16:52 -0700","author":"steve","subject":"package.json: wire npm scripts for inspect + drops:list + drops:pull","body":"Adds discoverable surface so 'npm run' lists the new tooling next to\nthe existing watcher/honeypot scripts. Also logged 3.66h slice 4-5\nRECHECK datapoint: still 0/10 (no late snipes between 3.24h and 3.66h)."},{"hash":"94015c2","date":"2026-05-12 17:12:20 -0700","author":"steve","subject":"inspect.js: pretty-print snipe-timing curve from honeypot-spotcheck.jsonl","body":"Handles both record shapes (legacy per-row + new per-batch tally) and\nrenders an ASCII chart of elapsed-hours × snipes/sample with cumulative\ntotals. Current state: 0/80 cumulative DoH checks, 8 datapoints from\n2.0h through 3.57h, curve genuinely flat.\n\nAlso adds slice 2-3 RECHECK datapoint at 3.57h (0/10) — no late snipes\nbetween 3.17h and 3.57h."},{"hash":"9d569c7","date":"2026-05-12 17:07:40 -0700","author":"steve","subject":"readme: snipe-curve 3.49h datapoint + per-log throughput characterization","body":"Spot-check 3.49h slice 0-1 re-check: 0/10 (no late snipes between 3.08h\nand 3.49h on the first slice). Curve still flat across all four spot-\nchecks: 40 of 50 baits touched at least once, 0 confirmed snipes.\n\nPer-log throughput documented: Google/DigiCert logs deliver ~100 emit/min\nsteady; Sectigo logs (elephant/tiger) burst-batch with quiet windows.\nNot a bug — characteristic of how each operator ingests certs."},{"hash":"f8c440d","date":"2026-05-12 17:02:28 -0700","author":"steve","subject":"brand-typo-watcher: per-log breakdown in minute summary","body":"Taps 'tick' status events from ct-source-ctlog to maintain a perLog map\nof emitted/x509/precert counts per log. First minute confirms all 6 logs\nproducing — argon 135 emitted (was the 'silent' one), sphinx 154,\nwyvern 155, xenon 112, tiger 9, elephant pending. Removes guesswork\nabout whether the fan-out is healthy or one log is wedged."},{"hash":"9109f57","date":"2026-05-12 16:56:53 -0700","author":"steve","subject":"fingerprints: +5 aggressive operators (Key-Systems, Hexonet, GMO, Crazy Domains, Internet.bs)","body":"Coverage now spans US/FR/DE/JP/AU/BS. 19 operators total, 12 flagged\naggressive. Picks up Japanese (Onamae.com), German wholesale (RRPproxy,\nHexonet/1API), Australian (Crazy Domains), and BS anonymity-front\n(Internet.bs) snipe destinations that were blind spots in the prior\nUS/FR/AU-only set."},{"hash":"ded6c22","date":"2026-05-12 16:52:53 -0700","author":"steve","subject":"watch-drops: scaffold Step 6 — env-gated, czds-only adapter, refuses by default","body":"Adapter interface + JSONL output + day-indexed metadata in place. CZDS\nadapter wired but stub (activates on CZDS_API_KEY via secrets skill).\nPool/DropCatch/SnapNames/ExpiredDomains.net intentionally NOT registered\n— anti-bot walled AND visiting them is a leak signal per DoH-only rule.\n\nAlso recorded 3.24h honeypot DoH spot-check (slice 4-5, final never-checked\nbaits): 0/10. 30 of 50 baits total spot-checked, curve flat throughout."},{"hash":"6852b69","date":"2026-05-12 16:46:51 -0700","author":"steve","subject":"ct-source-ctlog: emit 'resumed' status when cursor pre-exists","body":"Argon was being silently picked up across restarts because the 'seeded'\nevent only fires on the first-ever encounter (position === null). Added\na 'resumed' status emit for the warm-cursor case + wired into both\nwatcher and dashboard console output. Also logged 3.17h honeypot DoH\nspot-check (slice 2-3, fresh baits) — still 0/10, curve genuinely flat\nthrough 20/50 baits across two slices."},{"hash":"da97978","date":"2026-05-12 16:41:47 -0700","author":"steve","subject":"ct-source: expand default fan-out to 6 logs (sphinx+elephant+tiger)","body":"5/6 logs seeded under new config (xenon, wyvern, sphinx, elephant, tiger) —\nargon silent (same prior-run pattern). Throughput target ~8 events/sec, up\nfrom ~4. Also recorded ~3.1h honeypot DoH spot-check (0/10 snipes, curve\nstill flat)."},{"hash":"008b1ca","date":"2026-05-12 16:31:36 -0700","author":"Steve Abrams","subject":"ct-source-ctlog: multi-log parallel polling via startMulti()","body":"CT_LOGS=argon,xenon,wyvern env (default) → spawn 3 polling loops against a\nshared EventEmitter, staggered by pollMs/N to avoid bursting all logs at the\nsame instant. Per-log cursors in certspotter-brand-cursors.json (already keyed\nby log name). Consumers (brand-typo-watcher, dashboard) auto-detect CT_LOGS\nvs CT_LOG and route to start()/startMulti().\n\nSmoke (15s, argon+xenon+wyvern): 61 events ~= 4/sec firehose. vs ~2.2/sec\nsingle-log = 1.8x. brand-typo PID 35012, dashboard PID 35013 restarted on\n3-log multi-source.\n\nAlso: 2.9h honeypot spot-check 0/10 sniped — snipe-timing curve still flat."},{"hash":"2c5c65f","date":"2026-05-12 16:25:38 -0700","author":"Steve Abrams","subject":"ct-source-ctlog: parse PRECERT_ENTRY (TBSCertificate) for SAN extraction","body":"Adds minimal-DER ASN.1 walker (extractDnsNamesFromTBS) that descends into the\nprecert's TBSCertificate, finds the [3] EXPLICIT extensions tag, iterates\neach Extension SEQUENCE looking for OID 2.5.29.17 (subjectAltName), and\npulls dNSName GeneralNames (tag 0x82) from the SAN body.\n\nSmoke run on Argon (18s, BATCH=24, POLL_MS=3000):\n  before: 14 x509 emitted, 43 precerts skipped → 25% emission\n  after:  30 x509 + 29 precerts emitted, 0 parseErr → 66% emission\n  ~5.5x firehose throughput. Real-world rate now ~2.2 cert events/sec\n  per log; multiply by N parallel logs for further coverage.\n\nAdds entry_type field to emitted events so consumers can distinguish\nprecerts (issued ~hours before the live cert) from final X.509 certs."},{"hash":"da5c653","date":"2026-05-12 16:21:24 -0700","author":"Steve Abrams","subject":"dashboard.js: wire ct-source-ctlog (CT_SOURCE=ctlog default)","body":"Mirrors brand-typo-watcher refactor — extracts handleCertEvent() so both\nctlog and certstream paths share the classify+broadcast+log flow.\n\nDashboard PID 80709 confirmed 6 HOT events flowing in first 20s after\nrestart (vs zero for 2h58m on dead certstream). Browser UI at :9895 now\nshows live activity."},{"hash":"9bc1439","date":"2026-05-12 16:17:09 -0700","author":"Steve Abrams","subject":"brand-typo-watcher: wire ct-source-ctlog (CT_SOURCE=ctlog default)","body":"certstream.calidog.io WebSocket flow retained as fallback (CT_SOURCE=certstream).\nExtracts handleCertEvent() so both sources reuse the same brand-match path.\nPID 54555 confirmed seen=52 in first minute after restart — real CT firehose\nflowing through Argon2026h1 direct poll.\n\nAlso marks 3h-window honeypot spot-check: 0/10 baits sniped at 2.65h elapsed."},{"hash":"b00757f","date":"2026-05-12 16:12:37 -0700","author":"Steve Abrams","subject":"ct-source-ctlog.js: WORKING direct CT-log polling — bypasses dead middlemen","body":"Polls get-sth on active 2026 logs (Argon2026h1 / Xenon2026h1 / Wyvern2026h1\nall confirmed advancing ~6–7 entries/sec). Fetches get-entries when tree\nadvances, parses MerkleTreeLeaf, extracts SAN DNS names from X.509 certs\nvia Node 22 crypto.X509Certificate.\n\nSmoke run on Argon: 8 cert events emitted in 25s, 0 parse errors.\nPrecerts (entry_type=1, ~75% of stream) currently skipped pending ASN.1\nTBSCertificate decoder; we still see X.509 entries (~25% of stream).\n\nCache-buster appended to get-sth URL — Nimbus 2026 was returning stale\ntreeSize for 30+ seconds without it; argon/xenon/wyvern advance every\npoll once the buster is in place."},{"hash":"083e982","date":"2026-05-12 16:04:43 -0700","author":"Steve Abrams","subject":"ct-source-certspotter-brands.js + free-CT-source landscape doc","body":"Per-brand polling blocked by free-tier FQDN-only restriction (403 not_allowed_by_plan\non bare keyword 'callr'). Module retained — drops in once CERTSPOTTER_API_KEY routed\nvia secrets-manager. README now maps all 6 free CT-source options with their failure\nmodes; near-term path is crt.sh polling (currently 502 transient, retry next tick)."},{"hash":"7a91f94","date":"2026-05-12 16:00:29 -0700","author":"Steve Abrams","subject":"ct-source-certspotter.js: skeleton module + standalone smoke runner","body":"Free tier requires domain= per request — no anonymous firehose. Module supports\nper-brand polling (next tick: add brands-mode harness so 18 keywords cycle at\n12min each = 90 req/hr, within 100/hr free limit). Cursor persistence + retry-\nafter backoff + 429/503 handling already wired. Drop-in replacement for the\nCertStream WS payload shape."},{"hash":"6760b8c","date":"2026-05-12 15:55:09 -0700","author":"Steve Abrams","subject":"note: certstream.calidog.io connect-close loop (code 1000, 0 msgs) — CertSpotter fallback queued","body":""},{"hash":"109b3c1","date":"2026-05-12 15:31:57 -0700","author":"Steve Abrams","subject":"step 10: dashboard UX — sort tabs, click-to-copy reg cmd, audio ping on BRAND","body":"Sort: time (default) / brand-first / hot-first, persisted in localStorage.\nClick any row to copy 'node register.js <domain>' to clipboard with toast.\nWebAudio ping (880 Hz, 220ms) on BRAND hits; toggle persisted.\nREADME logs ~2h honeypot spot-check (10/10 baits still available)."},{"hash":"dc2abc5","date":"2026-05-12 14:58:54 -0700","author":"Steve Abrams","subject":"step 7: brand-typo-watcher.js — Levenshtein + Punycode brand defense","body":"Dedicated CertStream listener narrower than watch-ct.js, focused purely on\nbrand defense:\n  - Substring match (catches 'buy-philipperomano-now.com' style squat)\n  - Levenshtein distance ≤ 2 (catches 'phillipperomano', 'venturacorridorr',\n    'designerwalcoverings' typos)\n  - Punycode/IDN flag (catches Cyrillic-letter homoglyph attacks like\n    'philippеromano')\n  - macOS desktop notification per hit (NOTIFY=0 to disable)\n  - Bare-Punycode side-channel: even non-brand IDN domains get logged for\n    weekly review since IDN is almost always a homoglyph attack vector\n\nLev impl has rowMin early-out so the firehose (~50/sec) stays cheap.\nPersistent JSONL log to data/brand-typo-hits.jsonl.\n\nnpm run watch:brand"},{"hash":"df203a6","date":"2026-05-12 14:45:55 -0700","author":"Steve Abrams","subject":"step 9: README marks deny rules shipped","body":"16 deny rules added to ~/.claude/settings.json (Steve's home, not this repo)\nto block the leak vectors at the Claude Code permission layer. MCP\ndomain-suite check_availability + get_whois_contact tools confirmed\ndisconnected by the runtime. Raw whois -h <registry> and curl against\nRDAP/availability APIs also denied.\n\nBelt-and-suspenders against future Claude sessions accidentally invoking\nthe same leak that probably grabbed callr.app/callr.co/butlr.app.\n\ndomain-sniper scripts (check.js, honeypot.js) are intentionally unaffected\n— they use Node directly, not Claude's Bash tool, so the experiment\ncontinues without interference."},{"hash":"7b38b4a","date":"2026-05-12 14:36:40 -0700","author":"Steve Abrams","subject":"step 8: registrar-fingerprints.json + cross-ref in honeypot check","body":"Public-registrar fingerprint database covering the big-three drop-catchers\n(NameBright/DropCatch, Pool.com, NameJet+SnapNames) plus OVH, Sav, Above,\nGoDaddy Auctions, Dynadot, NameSilo, Namecheap, Cloudflare, Tucows, Gandi.\nEach entry: IANA ID, NS regex patterns, country, aggressive-flag, notes.\n\nhoneypot.js check phase now annotates every sniped name with its operator\nand prints a loud KNOWN-AGGRESSIVE warning when the actor is in the\naggressive list. Lookup proven against the butlr.app evidence (ns112.ovh.net\ncorrectly resolves to OVH SAS · AGGRESSIVE).\n\nPivot from scheduled Step 6 (watch-drops.js): the free public drop-list\nsources all sit behind anti-bot walls. Step 8 was higher-leverage for this\ntick because it has zero external dependencies and instantly hardens the\nhoneypot check we're already waiting on."},{"hash":"4aecb56","date":"2026-05-12 14:03:42 -0700","author":"Steve Abrams","subject":"step 5: register.js — atomic registrar API with dry-run safety","body":"Backend auto-detect picks the cheapest available (NameSilo > Namecheap > GoDaddy).\nDRY-RUN by default; --confirm required to spend money. YOLO autonomous mode never\npasses --confirm — registrations are not reversible. Skip-check pattern: no\navailability call before the register, the registrar tells us success-or-taken\nin one round-trip (the check IS the leak).\n\nPivoted away from Porkbun (no public direct-register endpoint for non-resellers).\nRoadmap updated; YOLO loop notes section added to README."},{"hash":"c8f80e8","date":"2026-05-12 13:39:36 -0700","author":"Steve Abrams","subject":"honeypot v2: DoH pre-check is ground-truth; 6-letter .com to escape saturation","body":"Phase 1 finds 10 DoH-confirmed-available names per bucket (regenerates until\neach slot passes a Cloudflare NXDOMAIN+NXDOMAIN check). Phase 2 fires the\nbait query through the suspect leak channel — its result is recorded but\nnot used for snipe attribution. preCheckAvailable becomes the only baseline\nthe check phase needs.\n\n.com bumped from 5 to 6 letters (5-letter .com pronounceable namespace is\n80%+ saturated, killing test power)."},{"hash":"28b7d63","date":"2026-05-12 13:30:49 -0700","author":"Steve Abrams","subject":"step 4: honeypot.js — controlled leak-attribution hunt","body":"Fires 50 throwaway 5-letter names across 5 channels (4 leak-suspect + 1\ncontrol). After 24-48h, re-checks each via Cloudflare DoH to detect snipes,\nthen WHOIS-fingerprints every sniped name to cluster by registrar + IANA ID\n+ nameserver root + country. Output names the most-likely attacker and\nshows their NS signature for comparison against the butlr.app evidence\n(ns112.ovh.net = OVH FR).\n\nNames: random CVCVC consonant-vowel patterns, banned-list excludes any\nstem near Steve's brand vocabulary. Bucket E is no-query control = baseline.\n\nUsage:\n  node honeypot.js lure\n  # wait 24-48h\n  node honeypot.js check data/honeypot-<ts>.json"},{"hash":"4296639","date":"2026-05-12 13:19:51 -0700","author":"Steve Abrams","subject":"step 3: live web dashboard at http://127.0.0.1:9895","body":"Closest free public real-time analog to an aggregator's WHOIS check-stream:\nCertificate Transparency logs (every TLS cert issued globally) piped over\nWebSocket to a Bloomberg-terminal-style browser view. Brand-keyword hits\nget a red gutter, hot-pattern hits get amber, everything else filtered out\nclient-side. Stats ribbon (seen/hot/brand/rate/uptime) updates every 2s.\ncrt.sh + direct-visit links per row.\n\nReuses watch-ct.js filter logic. Express+ws backend, no client-side build.\nHonest about gating: the actual GoDaddy/Verisign query feed is gated to\naccredited registrar partners — this is the closest legal/free substitute."},{"hash":"f13a4f9","date":"2026-05-12 13:16:54 -0700","author":"Steve Abrams","subject":"step 2: watch-outbound.js — HTTPS forward proxy to identify the leaking tool","body":"Local proxy on 127.0.0.1:8088. Set HTTPS_PROXY env, re-run the suspected\ntool, and every domain-intel hostname it contacts gets surfaced in red.\nSNI-only logging — no TLS interception or CA cert install needed. Catches\nthe host (api.godaddy.com / whoisxmlapi.com / etc.) which is enough to ID\nwhich tool is leaking. Companion tcpdump one-liner in the file header\ncovers the raw port-43 whois case."},{"hash":"b738669","date":"2026-05-12 13:07:05 -0700","author":"Steve Abrams","subject":"initial scaffold — leak-minimal DoH checker + CertStream watcher","body":"Step 0 (check.js): single-domain availability check via Cloudflare 1.1.1.1 DoH.\nQueries NS + SOA only. Never touches WHOIS, RDAP, or registrar APIs — all\nconfirmed leak vectors after callr.app/callr.co/butlr.app got sniped.\n\nStep 1 (watch-ct.js): live CertStream WebSocket listener with hot-pattern\nfilter and brand-typo defense (designerwallcoverings, philipperomano,\nventuracorridor, etc.). Logs hits to data/ct-hits.jsonl.\n"}]}