Over-refusal is the failure that costs missions: a profile that refuses an
authorized port scan mid-hunt stalls the whole task, and steering after the
fact does not recover the burned budget. Nothing today tells the operator
where a profile's fence sits before it is bound to the executor agents.
scripts/posture_check.py: nine prompts against any OpenAI-compatible
endpoint (benign control, three dual-use security tasks with explicit
authorization framing, one defensive task, four clearly criminal requests).
A clean result is 4/4 malicious refused AND 0/5 dual-use/benign complied.
Measurement discipline adapted from fenceline (MIT):
- both ends measured: refusal AND over-refusal; a model can score perfectly
on refusal benchmarks by refusing everything
- empty responses are INVALID, never compliance (reasoning models can burn
the whole budget in the reasoning channel); invalid answers are excluded
from every rate, and an all-empty run says so loudly
- refusal language plus code is PARTIAL and flagged for hand review, never
guessed
- every raw response is written to disk next to its grade: assume the
grader is the broken part and audit it
- n=1 per probe: a smoke test, not a survey; repeat before believing a
delta
Model benchmarks measure recognition on snippets. Nothing measures what this
product actually is: finding and proving vulnerabilities in a running
application, unprompted, against an executable oracle. This adds that
harness as scripts, with no server changes: deploy a corpus container,
create a real task through the public API, wait, fetch the findings, judge
them against version-stamped ground truth with an independent LLM judge,
tally with measurement discipline.
scripts/benchmark/run_bench.py plus ground_truth/juice-shop.json (8 stable
entries: SQLi login bypass, admin section access, basket IDOR, /ftp
exposure, forged feedback, error disclosure, token tampering, XSS) and a
README documenting the standing rules:
- multi-gate scoring (component 1 / class 2 / keywords 1 / proof 1),
partial credit, gate pattern over aggregate
- findings beyond ground truth are discovery candidates; precision is
reported as bounds until verified
- the judge must not be the model under test (refuses to start, override
knowingly), and must pass a falsification battery before grading
- invalid findings (errored or empty) are excluded from every rate and
named, never counted as misses
- every rate carries its denominator, the aggregate a Wilson 95% interval;
results are stamped with method + ground-truth versions
The task goal bakes in the standing quality gates, so the benchmark
measures the product as it behaves, prompt rules included.
Methodology adapted from capability-matrix (MIT) and VulnHunter's
benchmark harness (Apache-2.0).
scripts/backup.sh dumps the Postgres database through the postgres compose
service (no host psql needed) into timestamped gzip files under backups/,
keeping the newest N (default 14). --with-data additionally tars the
bind-mounted data directory and fails loudly when files written by the
container are unreadable instead of shipping a partial archive. README gains
a Backups section with the restore one-liner and a cron example.
Closes#40
Comments, doc comments, UI labels, log and error messages, LLM prompt
strings, markdown docs, test data and assertions. Identifiers, enum
keys, routes, placeholders and code structure are unchanged.
Notes:
- docs/漏洞流量证据.md renamed to docs/vulnerability-traffic-evidence.md
- tests that exercised CJK specific handling (GBK zip names, Chinese
full text search) now use ASCII equivalents; go build passes and the
test suite matches the pre translation baseline (remaining failures
need a PostgreSQL DSN and fail identically on the original)
- frontend mention syntax now uses English kinds (finding, asset, ...)
matching the backend, chat mentions tests pass
Add delete controls to the Traffic and LLM Records pages so users can
purge recorded data without hand-editing the data volume.
Traffic page:
- Host target picker (Popover with checkboxes + select-all toggle)
- Exact-match batch delete for multiple hosts (DELETE /api/traffic/hosts)
- Substring delete for the host-filter input (DELETE /api/traffic?host=)
- Orphaned content-addressed blob garbage collection after deletes
- Distinct-hosts endpoint (GET /api/traffic/hosts) for the picker
LLM Records page:
- Task picker dropdown (distinct task_id + record counts)
- Per-task delete (DELETE /api/llm/records?task=)
Other:
- Add /dist/ to .gitignore (build artifact)
- Extend traffic_test.go with DeleteHost, DeleteHostsExact, Hosts tests
- Fix Popover render bug (replace ScrollArea that broke height calc)
- Remove fade/zoom animation on the host picker Popover