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
11 KiB
Vulnerability Multi-Traffic Evidence
The "Related Traffic" section of vulnerability details supports cross-page multi-select, role and note, ordering, and unbinding. The traffic page also supports multi-selecting records and linking them to an existing vulnerability in one action. Vulnerability evidence inherited by a task is read-only; to modify it, go into the source task.
"Agent Auto Traffic Binding" in System Settings is off by default; the read/write interface is agent_traffic_binding on /api/settings. Enabling it increases Token consumption from reviewing requests/responses, tool calls, and prompts; the next Agent run uses the new setting. When disabled, the auto-binding parameters and the re-binding tool are hidden, no auto-binding guidance is injected, and newly submitted auto-bindings from already-running sessions are rejected. Manual binding, traffic capture, reading saved evidence, and export are unaffected.
Once enabled, the default flow is "finding recorded → automatically trigger the report Agent → verify and bind traffic → write the report against the latest evidence version". The reporter keeps the verification command, key output, existing real traffic IDs, and their roles in evidence; the report Agent combines the vulnerability details and execution records, verifies with traffic_search / traffic_get, then calls bind_finding_traffic, and finally reads the latest version to save the report. When the switch is off, the report Agent does not get the raw traffic search/read tools and does not bind automatically; it can still read manually bound snapshots and generate reports.
Backward compatible with existing callers: report_finding's traffic_refs / evidence_hint_id can still bind explicitly and immediately. Binding is optional: for non-HTTP vulnerabilities such as TCP, or when nothing was captured or no exact record can be found, omitting the refs still allows normal reporting and report writing; keep other verifiable evidence such as command output and logs, and it is recommended to note why nothing was bound — no new required fields are added. All submitted IDs must be valid with complete bodies. Any single failure rolls back the whole binding operation; when an explicit bind-along-with-report fails, the entire report is rolled back. Appending the same snapshot again does not add a binding and does not overwrite the note.
Agent Numbering and Report Versions
report_finding gains optional parameters; array order is the initial evidence order:
{
"traffic_refs": [
{"traffic_id": "real traffic ID", "role": "baseline", "note": "normal account request"},
{"traffic_id": "another real traffic ID", "role": "proof", "note": "reproduction request"}
]
}
Roles are baseline (normal control), proof (vulnerability proof), verification (additional verification), and supporting (auxiliary evidence, default). Verify real records with traffic_search / traffic_get first; domain and time are only used to filter candidates, not to infer task ownership.
For prompt reference see CyberStrikeAI's vulnerability reporting tool guidance, adapted to this project's optional-binding convention, without introducing mandatory reason validation for missing captures. Never guess IDs, and do not re-probe just to obtain a capture.
The first line of the response is still finding recorded: <exploration node ID>; the following JSON provides the standalone vulnerability record finding_id, the exploration node finding_node_id, and a binding summary.
get_finding_traffic(finding_id)uses the standalone vulnerability record ID and returns the ordered list plusversion; passbinding_id,side=request|response,offset,lengthfor segmented reads, at most 8192 bytes per segment.update_finding_report'sfinding_idcontinues to use the exploration node ID. The newevidence_versionmust be set to the version actually read; if the evidence changes while generating, writes of the old version are rejected and you must re-read and regenerate.- When an old report call passes no version, it does not claim to cover existing traffic evidence. After bindings, notes, roles, or ordering change, existing reports are flagged as needing an update.
With auto-binding enabled, add_hint / add_task_hint support saving traffic_refs in a single hint or in each element of a batch hints. A Planner reporting on behalf can pass evidence_hint_id, explicitly selecting the refs from this task's own hints; refs from inherited hints cannot be used. The system never guesses bindings from domain, time, or browsing history. A failed submission produces neither partial vulnerabilities nor early report triggers.
If an existing vulnerability is missing bindings, use bind_finding_traffic(finding_id, traffic_refs) to bind afterwards without re-registering. list_findings / list_task_findings / node_detail / get_task_node_detail return the explicit finding_id and finding_node_id; the legacy id keeps exploration-node semantics.
At startup, only optional properties are added to old tool schemas, and the original default traffic-tool bindings are extended to the report Agent; the re-binding tool goes to the report Agent by default. Custom binding lists, prompts, descriptions, and enabled states are preserved. Guidance is added uniformly after final tool assembly: the reporting role hands over existing evidence; the report Agent verifies, binds, and writes the report. When a platform conversation lacks task context, it should hand off to the task Agent via a structured hint instead of reporting directly. Before judging a task complete, existing evidence should be handed over first; missing captures do not force a wait. A failed report_finding does not trigger the report Agent.
API
Base path: /api/exploration/findings/{finding_id}/traffic, using the standalone vulnerability ID. Auth is unchanged; context_task validates task visibility and inherited read-only.
| Method / relative path | Request / response |
|---|---|
GET |
Ordered summary, evidence version, version used by the report |
POST |
{"traffic_refs":[...]} append as a batch |
PATCH /{binding_id} |
{"version":1,"role":"proof","note":"note"} |
DELETE /{binding_id} |
{"version":1} |
PUT /order |
{"version":1,"binding_ids":["2","1"]}, must be the complete list |
GET /{binding_id} |
Snapshot metadata and bounded body preview |
GET /{binding_id}/body |
side, offset, length; download=1 downloads the full original bytes |
Version/order-set conflicts and writes during archiving return 409; inherited writes return 403; bindings that do not exist or do not belong to the vulnerability return 404; traffic/attachment read and validation failures return explicit errors.
Storage and Migration
An idempotent startup migration on PostgreSQL adds traffic_evidence_snapshots, finding_traffic_bindings, and findings.evidence_version / report_evidence_version (default 0). It does not guess backfill bindings from historical text.
Snapshots store the original traffic ID, capture time, URL, method, status, request/response headers, body length, and SHA-256. Bodies are stored by hash at <data>/evidence/blobs/<first two chars>/<hash>.bin, independent of the cleanable data/traffic; multiple vulnerabilities can share snapshots/bodies. Snapshots have no content-update API; reads and exports fail when the hash does not match.
The full body is read under the original traffic write lock, including large-body blobs and legacy-directory records. Files are persisted and verified first, then a single PostgreSQL transaction writes the exploration node, intent relations, vulnerability, snapshot, and bindings; the planner is notified only after commit. Failures may leave unreferenced files but never partial business records.
PostgreSQL advisory lock 7337741004 coordinates evidence files and SQL references; the task row lock forbids evidence modification once archiving is queued. Recovery holds the evidence lock from body installation through metadata commit. Deleting a vulnerability cascades to its bindings.
The cleaner runs hourly and only reclaims unreferenced content with no in-flight operation, delayed by at least 24 hours. Regular traffic cleanup never touches the evidence directory. When backing up hot data, back up both PostgreSQL and data/evidence.
Export and Archiving
Markdown includes the ordered evidence list and version; JSON includes metadata; CSV adds counts and binding IDs. md-zip keeps the vulnerability Markdown and additionally provides:
evidence/<finding_id>/<binding_id>/
manifest.json
request.http
response.http
request.bin
response.bin
Markdown references messages via relative links. Before the download is sent: attachments are copied, hashes verified, compressed, disk-synced, and every ZIP entry's CRC is read-checked; anything missing/corrupt fails the whole download. Complete attachments preserve the original binary bytes.
Archive v3 collects snapshots and bodies by vulnerability binding, independent of the original traffic or domain. Hot data is cleaned only after package verification completes; shared evidence is kept. Recovery verifies installed bodies first, then restores metadata and bindings in a transaction, with retry on failure. v1/v2 remain restorable, with missing new fields explicitly zero-filled.
Verification and Boundaries
Each test package gets its own freshly created PostgreSQL test database, specified via ARTEX_PG_DSN, so leftover task/model fixtures cannot trigger background runs. Run the full tests of the affected packages and confirm nothing is skipped due to missing configuration:
# Set ARTEX_PG_DSN to the corresponding standalone test database before each package run; explicit configuration failures must error.
go test ./<package> -count=1
go test -race -p 1 ./evidence ./db ./agent ./server -run 'TestEvidence|TestFindingTraffic|TestFindingEvidence|TestReportFindingAtomicContract|TestTaskArchive'
Frontend verification covers npx tsc --noEmit, Biome checks on affected files, the Webpack build, and NEXT_EXPORT=1 static export. Use a separate cache directory to avoid clobbering a running dev server.
Local end-to-end acceptance uses separate ports, controlled HTTP / domain HTTPS targets, and a temporary data directory, covering both binding entries, cross-page selection, ordering/notes, error messages, inherited read-only, download, and — after deleting the original traffic — export, archiving, hot-body reclamation, restore, and hash verification.
The first version uses a global evidence coordination lock; during large batch binding/export or slow attachment downloads, other evidence operations may wait. Evidence cannot be fabricated when recordings or complete bodies are missing. This feature does not change the capture switch, nor does it address certificate issues for HTTPS direct-to-IP access.