Back to home

AndyYJF

dsh-lan-web-auth

DeepSeek Harness (dsh) host plugin: crypto.randomUUID polyfill + password auth for running the web GUI over LAN / ZeroTier

Stars
0
Language
JavaScript
Created
Aug 14, 2026
Updated
Aug 14, 2026

Introduction

dsh-lan-web-auth

English | 简体中文

Host plugin for DeepSeek Harness (dsh --profile web) that makes the browser GUI usable over the LAN and protects it with a password:

  1. crypto.randomUUID polyfill — the GUI's RPC client mints request ids with crypto.randomUUID(), which browsers only expose in secure contexts (HTTPS or loopback). Plain-HTTP LAN origins (192.168.x.x, hostnames, ZeroTier IPs) are not secure contexts, so every /api call throws client-side (crypto.randomUUID is not a function), the session list never loads, and the GUI falls into the workspace-picker state. The polyfill is based on crypto.getRandomValues, which IS available on insecure origins.

  2. Password authentication — wraps the page fallback, the /api prefix route, and the two WebSocket downlink upgrades (/api/events.mux, /api/events.host) with a cookie check. Unauthenticated visitors get a built-in login page; POST /api/auth/login with the correct password sets an HttpOnly cookie (30 days). Loopback hosts (127.0.0.1 / localhost / ::1) are exempt by default (config.loopbackExempt).

Security & Risks

Read this before exposing the GUI beyond your own machine. dsh web is a remote-control surface: the harness can execute shell commands, read/write files, and manage credentials and settings, so successful (or bypassed) authentication is effectively remote code execution as your user.

  • Plaintext HTTP, no TLS. The password, the session cookie, and all conversation content travel unencrypted. Anyone who can sniff the network segment (e.g. open Wi-Fi, a compromised AP/router) can capture the password or hijack a session. On untrusted networks, put dsh behind a TLS-terminating reverse proxy, or reach it only over an encrypted tunnel (ZeroTier / Tailscale / WireGuard).
  • No brute-force protection. The login endpoint has no rate limiting or lockout; a weak password can be guessed. Use a long, random, unique password.
  • Password stored in plaintext. config.password lives in ~/.dsh/profiles/web/cordis.patch.yml; the DSH_WEB_PASSWORD alternative is visible in the process environment. Anyone with local read access can recover it. Never commit a real password (the example patch uses a placeholder).
  • Loopback exemption is a real hole. With loopbackExempt: true (the default), any local process that can reach 127.0.0.1:3080 — not just your browser — bypasses the password entirely, because it can send a loopback Host header and the DNS-rebinding fence does not constrain non-browser clients. Set loopbackExempt: false to enforce the password on loopback too.
  • Stateless token, no revocation. The session token is a SHA-256 of the password; changing the password is the only way to invalidate outstanding cookies. Cookies are valid for 30 days.
  • 0.0.0.0 bind widens exposure. The example patch binds all interfaces, so the GUI is reachable on every network the machine is attached to (Wi-Fi, ZeroTier, TUN adapters, ...). On networks you do not fully trust, bind a specific interface instead (e.g. host: '192.168.1.13').
  • Auth is additive, not a security boundary. This plugin's password gate sits on top of the built-in browser-trust fence (Host/Origin checks). It is a convenience layer for home/LAN use, not a substitute for HTTPS plus real authentication. If your threat model matters, front dsh with a proper reverse proxy.
  • Workaround, may conflict with upstream. This plugin works around upstream limitations (missing crypto.randomUUID on non-secure contexts; no built-in auth). If a future dsh release fixes either, review whether this plugin is still needed before upgrading.

Install

  1. Copy the package into your web profile's node_modules:

    ~/.dsh/profiles/web/node_modules/dsh-lan-web-auth/
    

    (Or install it as a plugin: add "dsh-lan-web-auth": "file:<path>" to ~/.dsh/profiles/web/package.json dependencies and run dsh plugin --profile web install.)

  2. Add the row to your user patch layer ~/.dsh/profiles/web/cordis.patch.yml — see patch.example.yml for the full LAN setup (bind 0.0.0.0, trusted hostname, plugin row). The patch layer is a user-owned extension point: it survives npm i -g @deepseek-ai/dsh upgrades.

  3. Restart dsh --profile web (or let the user-patch watcher hot-apply it).

Config

FieldMeaning
passwordLogin password. Falls back to the DSH_WEB_PASSWORD environment variable. If neither is set, auth stays disabled (polyfill only) and a warning is logged.
loopbackExemptWhen true (default), loopback origins skip the password.

Changing config.password in the patch hot-applies via HMR; LAN clients must log in again.

Notes

  • The token is a SHA-256 of the password — stateless, survives restarts.
  • Auth is in addition to the built-in DNS-rebinding / browser-trust fence, which still applies.
  • Plugin code changes need a dsh restart (the loader caches modules per process); config changes hot-apply.
  • The webserver row in patch.example.yml binds all interfaces (0.0.0.0) so LAN/ZeroTier devices can reach the GUI; the connection row adds a hostname to the trust fence.