# 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: ```json { "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](https://github.com/RuoJi6/CyberStrikeAI/blob/54d56774b8bd285817d16d48b70a4a5e6e0963f7/internal/app/vulnerability_tools.go), 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: `; 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 plus `version`; pass `binding_id`, `side=request|response`, `offset`, `length` for segmented reads, at most 8192 bytes per segment. - `update_finding_report`'s `finding_id` **continues to use the exploration node ID**. The new `evidence_version` must 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 `/evidence/blobs//.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: ```text evidence/// 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: ```sh # Set ARTEX_PG_DSN to the corresponding standalone test database before each package run; explicit configuration failures must error. go test ./ -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.