# Security notes

## Threat model

The plugin is for a **private LAN** DeepSeek Harness web UI. It assumes:

- The host is not reachable from the public internet.
- Attackers on the LAN should not get a shell-capable agent without the password.
- The operator can always recover from `127.0.0.1`.

## Controls

- Inbound allowlist uses `socket.remoteAddress`, not `Host` / `X-Forwarded-For`.
- Presence of proxy headers is a deny, not a source of identity.
- Password is scrypt (`N=16384,r=8,p=1`) with a random 16-byte salt.
- Login is rate-limited (5 failures / 60s / IP).
- Session cookie is `HttpOnly; SameSite=Strict; Max-Age` (default 7 days). Token hashes persist in `$DSH_HOME/lan-gate-sessions.json` so a process restart does not log everyone out. Changing the password still drops all sessions.
- Login POST requires `Origin` to match `Host` when `Origin` is present.
- `/api` WebSocket upgrades are refused without a valid session (unless loopback bypass).
- `GET /dsh-lan-full/state` never returns `passwordHash`.
- Changing the password drops all sessions.

## Known residual issues

1. **No TLS.** HTTP on a LAN can leak the password and cookie to a passive observer. SameSite cookies do not fix that. If you need confidentiality, put TLS in front *without* adding forwarding headers, or only use loopback + SSH tunnel.
2. **Loopback bypass.** Enabled by default so a locked-out operator can recover. Disable `loopbackBypassAuth` if untrusted local processes share the host. A logged-in session can run bash; API keys are the operator's responsibility.

## Reporting

Open a GitHub issue on this repository. Do not include live passwords or API keys.
