Files
deepseek-harness/packages/client/connection/README.md
T
creatixchu 01d68dee4e fix(connection): fence every /api request behind one browser-trust check
The only browser-trust guard covered host.pickDirectory, while the
consequential methods (session.prompt drives bash) accepted any Host —
open to DNS rebinding, where a rebound page reads and writes the API as
if same-origin and only the Host header betrays the attacker's domain.

The pickDirectory-specific loopback guard becomes a prefix-wide fence:
Host must be loopback or an exact host[:port] from the new trustedHosts
config, an attached Origin must equal that authority, and explicit
cross-site markers are refused; requests without browser markers (curl,
tests, native clients) pass, because without a browser there is no
confused deputy. The loopback-socket check is dropped — binding policy
expresses reachability, and the fence is not an auth layer. The Agent
Note records the full threat model and the alternatives.
2026-07-28 14:56:45 +08:00

27 lines
2.9 KiB
Markdown

# @deepseek-ai/dsh-client-connection
English | [中文](README.zh.md)
Wire consumer layer: the client plugin's apply mounts `ctx.connection` (shared api client + single-consumer stream-loop starter); the export face carries the wire contract types, the `AbstractApiClient` seam, and the loop's sink/config types. The platform subclasses (WebApiClient/FixtureApiClient), the ConnectionController loop, and the fixture data source are package-internal — apply selects and drives them; tests reach them via src. Contract: api-contracts v3 §3.
## /api browser-trust fence
The node half guards every request under `/api` before bridging (`src/api-request-trust.ts`): the `Host` header must be a loopback authority or an exact `host[:port]` entry from the plugin's `trustedHosts` config (DNS-rebinding defense), an attached `Origin` must equal that authority, and an explicit `sec-fetch-site: cross-site` marker is refused. Requests without browser markers (curl, tests, native clients) pass — without a browser there is no confused deputy. Failures answer plain 403 before any RPC dispatch. A non-loopback (`--host 0.0.0.0`) deployment must therefore list the authorities it is reached by in `trustedHosts`; the fence is deliberately not an authentication layer — reachability policy stays with the webserver binding, and auth remains deferred work. Decision record: [the api browser-trust boundary Agent Note](../../../.agents/notes/implemented/architecture/2026-07-28-api-browser-trust-boundary.md).
## Keyless fixture
Any `fixture` query parameter selects the in-memory carrier. `fixture=empty` starts with no Workspace or Session; `fixturePrompt=reject` rejects prompts before acceptance; `fixtureAttach=fail` publishes a Session but rejects its Workspace attachment; `fixtureSessionCreate=drop-response` publishes and frames a Session before dropping the create response; and `fixtureFrames=workspace-first` reverses the default session-first create-frame order. Workspace creation by name/path and caller-preallocated SessionIds remain deterministic enough for assembled Web tests to reconcile list and frame arrival.
## Model Experience
None, as the wire consumer layer moves already-composed messages between browser and host; nothing here reaches a model request.
#### KV Cache effect
None; this package neither assembles nor sends a provider request.
## Known Limitations and Deferred Work
- **history's implicit resume is arguable** — opening history on an unattached session pulls an agent up host-side; the pure-persistence-read alternative is recorded in the rt-core reconciliation ledger, unchanged in P-I. This package's consumers see it as latency on first open.
- **`ToolEventView`/`ToolCallView`/`ToolResultView` re-exports are scheduled for removal** — they fall when the toolview migration deletes the host `viewFor` line (presentation belongs to the client); the fixture keeps a local `viewFor` mirror until then.