Windows CI uses pacboy re2:p with re2_cgo (dynamic libre2) for
testing. Linux CI keeps re2_cgo + re2_static (bundled static archive).
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
go mod download needs git in PATH; MSYS2 shell doesn't inherit
the Windows system git.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Replace upstream wasilibs/go-re2 with chainreactors/go-re2 fork that
bundles pre-built libre2_cre2.a static archives. Build tag re2_cgo +
re2_static selects the bundled archive and statically links libstdc++
and libgcc, producing binaries with zero C++ runtime dependencies.
Removes libre2-dev/g++ install steps from CI — no longer needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Linux CI installs libre2-dev and uses -tags re2_cgo. Windows CI
uses msys2/setup-msys2 with pacboy re2 for CGO mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Set bl.IsValid=false before putToFuzzy snapshot in BaseCompare, so
the snapshot no longer passes the IsValid check in Output()
- Gate file output on the same condition as console output:
bl.IsValid || (r.Fuzzy && bl.IsFuzzy)
- Bump deps: utils, utils/parsers, fingers (types migrated to parsers)
- Remove local replace directives
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Allow {?...} / {$...} mask patterns to be embedded directly in -u, -H,
--host, --cookie, --path fields. The mask is auto-extracted as the word
source and replaced with {{FUZZ}} placeholder, which gets substituted
with each generated word at request build time.
Also supports explicit -w with {{FUZZ}} placeholders in any field.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
sendProcess now does wg.Add(1) before sending to processCh, and both
BrutePool.Handler and CheckPool.Handler call wg.Done() after processing.
This ensures wg.Wait() in startDrain does not return while the Handler
is still processing baselines that may produce new crawl additions.
Also adds e2e tests for:
- Crawl recursive URL discovery (depth 1 → depth 2)
- Extract (recon/keys) collection on invalid baselines via dump file
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Previously, ProtonExtract only ran inside Collect() which was only called
for valid/fuzzy baselines. Invalid baselines (failed BaseCompare) with
keys, tokens, or other sensitive data in their response body were silently
skipped. Now putToOutput runs extract on invalid baselines that have raw
response data.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
CrawlSource baselines were going through the standard BaseCompare flow,
which compared them against the random baseline and marked most as invalid.
This prevented doCrawl from being called on crawl results, breaking
recursive URL discovery after the initial index page.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Embed proton's found/keys templates (156 rules covering AWS, GCP, Azure,
OpenAI, Slack, GitHub, Stripe, etc.) into the spray binary. The new --keys
flag activates them; -a (advance) also enables keys automatically. When
used with --recon, tags are merged into a single EnableExtractors call.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
RunWithCheck closed OutputCh immediately after context cancellation
without waiting for the CheckPool goroutine to finish. The Handler
goroutine could still be calling putToOutput on the already-closed
channel, causing "panic: send on closed channel".
Add r.poolwg.Wait() before close(OutputCh), matching RunWithBrute
which already had this synchronization.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Mirrors gogo's ResourceLoader pattern. SDK spray engine sets it to
no-op after init, preventing RunWithArgs from reloading ports/fingers/templates.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- parsers.Extracted: add Severity and Items (ExtractItem with ctx/line/offset)
- ProtonExtract: preserve severity from templates, capture N-char context around matches
- Add --extract-context CLI flag (default 0, e.g. --extract-context 50)
- Add word matchers pre-filtering to 14 existing templates for performance
- Add 9 new HaE-inspired rules: lfi-indicator, upload-form, url-as-value,
location-redirect, mac-address, sensitive-field, linkfinder, url-schemes,
authorization-header
- Total proton templates: 45 (was 35)
- Update ColorString/TreeString to render severity and context
- Comprehensive tests for severity, context, new templates, tag mappings
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
gomod (grouped golang.org/x/* and chainreactors/*) plus github-actions where present. No ignore on chainreactors/* so inter-repo deps are auto-updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The replace pinned a pre-v1.0.3 pseudo-version up to the v1.0.3 release.
proxyclient v1.1.0 is now published, so require it directly and remove
the replace. Core schemes (SOCKS/SOCKS5/HTTP/HTTPS) cover spray's proxy
use; the extra protocols (trojan/vmess/ssh/...) are split into separate
modules in v1.1.0 but spray doesn't use them. go build ./... passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
go generate with the updated templates submodule (7d5675c) produces
different embedded data and code. Key changes:
- cmd/cmd.go: logs.Info/Important → logs.InfoLevel/ImportantLevel
- pkg/templates.go: remove proton_rules.bin/neutron.bin embeds (no longer needed)
- core/baseline: use ProtonExtract instead of Extractors.Extract
- core/format: list proton extractor names
- Update embedded binary data files
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The file was referenced by //go:embed but never committed,
causing build failures when consumed as a remote Go module.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Fingers now defaults to RE2 regex engine with AC pre-filtering.
No build tag changes needed — RE2 is the new default.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
When ctx is cancelled (e.g. IsFailed threshold), the Run loop breaks
and stops reading additionCh. But doCheck (now via addAddition) may
have queued items with wg.Add(1) that no one consumes. Close().wg.Wait()
hangs forever.
Fix: spawn a drain goroutine in Close() before wg.Wait() that consumes
and Done()s remaining additionCh items, then close the channel after
Wait returns.
Verified: 16 IPs x 2 ports x 1000 words completes with EXIT 0.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Supports check mode (exploit verification via finger field) and brute mode
(default credential testing via zombie/tags field). POC templates are only
executed against targets whose fingerprints match, avoiding blind scanning.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Root cause: doCheck() called reqPool.Invoke() from the Handler goroutine.
When all reqPool workers blocked on sendProcess waiting for Handler to
drain processCh, and Handler blocked on Invoke waiting for a free worker,
a circular wait formed.
Fix: doCheck now uses addAddition() to submit check requests via
additionCh consumed by the Run loop, breaking the circular dependency.
Before: 16 targets x 500 words = HANG (>130s)
After: 16 targets x 500 words = 1.8s
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Root cause: the atomic.Bool + polling monitor goroutine pattern had a
race between wg.Wait() in the monitor and wg.Add(1) in the main loop.
When the monitor observed done=true and started Wait, the main loop
could still dispatch new work, causing Close().wg.Wait() to hang.
Fix: replace with nil-channel + sync.Once pattern. When the word stream
exhausts or limit is hit, worderCh is set to nil (disabling that select
branch permanently), then a single goroutine waits for wg to reach zero.
Since wg.Add(1) only occurs in the worderCh branch, nil-ing it before
Wait guarantees no new Add after Wait starts — no race possible.
Other fixes:
- Task feeder goroutine now ctx-aware (prevents leak on cancel)
- AddPool checks Invoke error (prevents poolwg counter mismatch)
- Revert resource_provider IIFE (reading a struct field cannot panic)
- Remove E2E -short skip (race is fixed, full coverage in CI)
- Fix Go 1.24+ vet: non-constant format strings in Init()
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Bug fixes:
- Defer scopeLocker.Unlock in doScopeCrawl (deadlock on panic)
- Defer statsMu.Unlock in recordStat (deadlock on panic)
- Defer RUnlock in resource_provider.LoadConfig via inline func
- Fix data race in invoke(): move bl field writes before doRedirect
- Close response body on ReadAll error (connection leak)
- Add defer raw.Close() for raw file parsing (fd leak)
- Safe type assertion in load.go keyword parsing (panic on bad YAML)
- Check ants pool creation errors in NewBrutePool/NewCheckPool
New tests (15 test functions):
- pool_test.go: scopeLocker panic recovery, cancel mid-processing,
single-threaded map access, valid pool creation
- runner_test.go: concurrent recordStat safety, nil stat handling
- load_test.go: malformed YAML tolerance, valid YAML loading
- e2e_test.go: normal brute scan, context cancellation, server errors,
WAF behavior, multi-target check mode, mixed status codes
CI hardening:
- Add -race detector (Linux, -short mode)
- Add -timeout 300s to prevent deadlock hangs
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- go:generate now uses -embed flag to produce //go:embed binary data
- templates.go reduced from 125KB base64 source to 0.9KB + 93KB .bin files
- binary saves ~28KB (removes base64 decode overhead at runtime)
- templates submodule updated with embed-aware generator
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add 19 tests in core/pool/pool_test.go covering:
- addAddition: normal, after cancel, wg balance, full buffer, concurrent
- sendProcess: normal, after cancel, full buffer, concurrent
- putToOutput/putToFuzzy: normal, after cancel, Outwg balance
- Handler lifecycle: processCh close exits handler, drains all items
- Shutdown sequence: no deadlock, cancel mid-flight
- Goroutine leak detection after full shutdown
Add .github/workflows/ci.yml:
- Runs on PR to master and push to master
- Tests on ubuntu-latest and windows-latest
- go build, go test -race, go vet
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Replace close(additionCh) with additionClosed atomic.Bool flag to
prevent panic when async producers (redirect/crawl/retry/append)
write after pool shutdown
- Guard addAddition() with ctx.Err() and additionClosed check before send
- ParseRawResponse failure no longer marks baseline as invalid or
returns early; log at debug level instead
- Read Location header from live response (resp.GetHeader) instead of
re-parsed bl.Response.Header for reliability
- Add ParseRawResponse boundary tests (nil, empty, truncated, binary, etc.)
Co-Authored-By: Claude Opus 4.6 <[email protected]>