DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Permission Gate — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins

dsh-permission-gate

Permission Gate

UI-level access gate + process-wide agent tool brake for DeepSeek Harness: shared session, strict 60-minute idle lock, native settings module. NOT server-side authentication.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add dsh-permission-gate@1.2.0
READMECompatibilityVersions

Compatibility and provenance

Permission Gate is published as dsh-permission-gate and currently resolves to version 1.2.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
npm
Registry updated
9/23/2026

Versions

1.2.0stable
9/23/2026

Related plugins

Loading related plugins…

Latest
1.2.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
80 kB
Files
9
Surface
web
License
MIT
Source
npm
GitHub
★ 1
Weekly downloads
0
Last push
9/23/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in security-access.

Doctor@linxin666/dsh-doctorTransactional rescue mode for DSH profiles with a supervised launcher, isolated recovery capsule, deterministic repairs, health monitoring, and a local Web recovery consolePocketdsh-pocketPut DeepSeek Harness in your pocket: one package, one settings page, and scan a QR code on your phone to access DSH on your computer in sync (LAN + public network, real-time screen mirroring).DSCODE@toddzheng024/dscode-bundleA complete DeepSeek coding agent with persistent shell, Ultra collaboration and automatic permission review.Plugin Subscriptionsdsh-plugin-subscriptionsUse ChatGPT (Codex), Claude, Grok (X Premium), GitHub Copilot, and Google Antigravity subscriptions as DeepSeek Harness LLM providers, with OAuth login from the web Settings page

README

dsh-permission-gate

A UI-level access gate and process-wide agent tool brake for DeepSeek Harness (dsh).

Log in once → every open DSH page unlocks. Nobody logged in → the agent itself can't run a single tool.


⚠️ Read this first: this is NOT authentication

DSH's /api surface has no authentication of its own — that is a deliberate property of the harness, not a bug this plugin fixes. The harness's own source describes its request fence like this:

trustedHosts is a DNS-rebinding fence, explicitly not authentication

Any client that can reach the DSH port can bypass this plugin entirely by calling the HTTP API directly. This plugin gates:

  • ✅ the browser page (a full-screen lock page injected into every page load)
  • ✅ the agent's tool calls (a process-wide tools.guard brake)

It does not gate the HTTP surface. It is not a reverse proxy, not a session layer, and not an authorization system.

Always pair it with a real boundary:

Real boundaryWhat it gives you
Bind DSH to loopback (dsh web, the default)Nothing on the network can reach it at all
A VPN / overlay (WireGuard, Tailscale, ZeroTier)Only your own devices can route to the port
A TLS reverse proxy that performs real authenticationThe only place a real auth layer can live

If you deploy this on a public port and believe you are protected, you are worse off than having nothing, because you will stop looking for the real problem.


What it does

  • Full-screen lock page. Injected into every DSH page load via the documented webserver/index-inject channel — no client bundle, no module loader, nothing to keep in sync with the SPA.
  • Global shared session. One session per process, one idle clock. Log in on your phone → your desktop page unlocks on its next poll. The clock expires → every page falls back to the login page.
  • Strict 60-minute idle lock. No grace period, not even for a running task. This is intentional: the gate is a dead-man switch.
  • Process-wide tool brake. While nobody is logged in, ctx.tools.guard denies every agent tool call. The agent cannot read files, run commands, open the network, or spawn subagents.
  • Real credentials. scrypt + random salt, stored at ~/.dsh/permission-gate.json (mode 0600). The session lives in memory only, so a restart always requires a fresh login — but your password is never reset.
  • Server-rendered escape hatch. /gate is plain HTML served by the host half. It works even if the injected script fails or is cached out.
  • Native settings module. A 权限闸门 page inside DSH's own Settings, where the gate can be disabled — and disabling requires the password.
  • Collapsible status chip. A countdown chip in the corner; collapse it to a slim tab on the right edge and click the tab to bring it back. The preference persists in localStorage.

Install

This package declares dsh.bundle, so it is a profile layer: installing it is one command, and DSH reconciles the composition for you. There is no patch file to edit.

dsh plugin --profile web add dsh-permission-gate

# restart DSH once — the client roster is scanned at startup

The bundle inserts this row on its own (see cordis.patch.yml):

- insert:
    - id: permission-gate
      name: dsh-permission-gate

Migrating from a manual install? Delete that same row from your own ~/.dsh/profiles/web/cordis.patch.yml first. The bundle now inserts it, and two entries sharing one id will collide.

On the next page load you get the lock page. The first visit asks you to set a password; every visit after that asks you to enter it.

Endpoints

All of them are served by the host half and sit behind the same origin as DSH.

MethodPathPurpose
GET/gateServer-rendered login page. Always available.
GET/gate/ui.jsThe injected browser script (cache-control: no-store).
GET/gate/status{ state, expires, remainingMs, idleMs, hasCredential, authenticated }
POST/gate/login{ password, mode } — mode: "setup" on first run. Sets the session cookie.
POST/gate/touch"A human is present" — extends the idle clock.
POST/gate/lockDrop the session and clear the cookie.
POST/gate/mode{ password, enable } — disable/enable the gate. Requires the password.

state is one of setup · locked · unlocked · disabled.

Threat model

ScenarioCovered?
Someone picks up your unlocked phone/laptop and opens the browser✅ full-screen lock page
You walk away and an autonomous agent keeps working✅ strict idle lock + tool brake
A page is left open on a second device✅ shared session logic; all pages mirror the server state
Someone in your tailnet calls /api directly❌ not covered — that is what the real boundary is for
Someone can edit cordis.patch.yml or the package directory❌ not covered — a plugin cannot defend the composition that loads it
Someone restarts the DSH process❌ not covered — the gate lives in the process; a restart also clears the session

Deliberate exemption

Three tools stay callable while the gate is locked, because they touch no files, commands, session content, or credentials:

get_goal · update_goal · todo_write

They exist so a locked agent can still report state and close out its own bookkeeping. Remove the BOOKKEEPING_TOOLS line in lib/index.js if you want a zero-exemption gate.

Recovery

SituationWhat to do
Forgot the passwordDelete ~/.dsh/permission-gate.json → next visit asks you to set a new one
The injected UI is broken / cachedVisit /gate directly — it is server-rendered
Locked out completelySet disabled: true on the row in cordis.patch.yml, or remove the row. cordis.patch.yml is watched live, so no restart is usually needed
Want to inspect statecurl http://127.0.0.1:3080/gate/status

Design notes

Built while running DSH remotely from a phone. Three bugs are baked into the comments and the test suite, because each one is a trap anyone building injected UI for DSH will hit:

  1. A silent render crash is worse than a visible error. The lock page used to throw on every render in the common path (appendChild(null) when the "confirm password" field is absent) — the host-side guard kept working while the UI showed nothing, i.e. "no permissions, but you can still chat." Fix: never append null, and wrap the whole render in a fallback that puts the error on screen.
  2. Never re-render a form on a timer. A 5-second status poll rebuilt the login form and wiped whatever the password field contained. Fix: re-render only when the state actually changes, and carry typed values across renders.
  3. A global session must not require a per-browser cookie. /gate/touch originally demanded a cookie matching the session token. After a restart only the browser that logged in held a valid cookie, so every other page's activity was rejected with 401 — the countdown only ever went down. Fix: touch grants nothing; it only requires that the shared session is unlocked.

Development

The smoke test runs the real lib/ui.js against a minimal DOM stub whose appendChild throws on null, exactly like a real DOM. No browser needed.

npm test

Compatibility

Developed against DSH 0.1.1-rc.2 / cordis 4.x, and depends on these harness capabilities:

  • host: webServer.register · webserver/index-inject · tools.guard
  • client: the settings.section slot · slots and timer services

These are internal-ish APIs; a DSH upgrade may require a matching update here.

License

MIT