dsh-cookie-janitor: Clean up expired dsh-auth-* cookies to avoid DSH request header overflow (431)

Preface

DSH’s authentication relies on browser cookies. Every time DSH starts, it issues a new cookie based on the listening address, containing the port in the name; the port is random, but the scope of the cookie is only the host, excluding the port. Thus, every request from the browser brings along all historical dsh-auth-* cookies. After accumulating about 70, the Cookie header approaches Node.js’s default 16 KiB limit. The server returns 431 Request Header Fields Too Large before the application code executes, manifesting as a white screen, stuck loading, or authentication failure.

Below is an introduction to the dsh-cookie-janitor plugin maintained by yan3536 (Category admin-security, GitHub 1 star, MIT). It hooks into the Host’s HTTP service, truncating old cookies belonging to disappeared ports before the request enters the application, and provides a 302 fallback for already overflowing requests. The offline self-test in the README covers 24 use cases.

What problem does it solve

DSH’s browser authentication cookie name is derived from the address:

cookie name = "dsh-auth-" + base64url(sha256("host:port"))

The name includes the port, but the port is not fixed:

  • The desktop version hardcodes --port 0 at startup, letting the OS choose an available port;
  • The command line dsh --profile web --port 0 is similar.

Thus, starting N times within 30 days piles up N useless cookies, and their validity does not renew with use. A single cookie is about 221 bytes. The README test shows that with 73 cookies, the Cookie header is 16277 B and still passes; with 74 cookies, it gets 431 at 16500 B. Since headers like Host and User-Agent also consume quota, the actual limit is slightly earlier, estimated around 70 cookies.

The existing method is to manually clear site data for 127.0.0.1 in the browser, which solves it temporarily, but the next startup starts piling up again. This plugin puts cleaning into the request chain, eliminating the need for manual intervention.

Three-layer behavior

The plugin performs three things in the order of request occurrence:

  1. Request Entry: Strip dsh-auth-* cookies belonging to other ports from the Cookie header; the application does not see these cookies;
  2. Response Exit: Issue Max-Age=0 for the stripped cookies, causing the browser to delete them from the cookie jar;
  3. Overflow Fallback: If the request header is too large for Node to parse, replace the 431 with a 302 redirect to the original address with clear instructions attached; the user sees a refresh rather than a crash.

The currently used cookie is never touched; deleting it would log the user out of the currently used instance. After cleanup, the Cookie header of the second request contains only one item, and it will not grow afterwards.

Installation

Install from Git repository:

dsh plugin --profile web add github:yan3536/dsh-cookie-janitor

When debugging source code offline, clone first then install using absolute path:

git clone https://github.com/yan3536/dsh-cookie-janitor
dsh plugin --profile web add /absolute/path/dsh-cookie-janitor

After installation, DSH must be fully quit before restarting. The plugin is attached to the Host’s HTTP service and can only be installed during startup; refreshing the page has no effect.

Desktop users should change --profile web to --profile desktop. The desktop profile is exclusive to Electron; DSH must be fully quit before executing the command, otherwise it will report: Open DeepSeek Harness Desktop once to initialize its profile, then fully quit it before running dsh plugin --profile desktop.

Uninstallation:

dsh plugin --profile web remove dsh-cookie-janitor

Configuration

All optional, defaults are recommended values. When changes are needed, write them into the profile’s cordis.patch.yml:

- id: cookie-janitor
  name: dsh-cookie-janitor
  config:
    keepForeign: 0        # Allow keeping N cookies not from the current port; 0 = clear all
    pruneRequests: true   # Turning this off leaves only the overflow fallback
    rescueOverflow: true  # Turning this off returns 431 as-is
    maxHeaderBytes: 0     # When >0, raises Node's limit to this byte count
    attachTimeoutMs: 15000

maxHeaderBytes only pushes the symptom back; the real fix is keepForeign: 0. When the same browser needs to connect to multiple DSH instances simultaneously, set keepForeign to the actual number of instances in use; the plugin keeps the latest few in the order the browser sends them.

Will it mistakenly delete

No. The decision is entirely based on DSH’s own algorithm:

  1. Only touches cookies starting with dsh-auth-; themes, language, and third-party cookies remain untouched;
  2. The cookie corresponding to the current Host is always retained;
  3. The listening ports corresponding to the deleted ones do not exist in the current process, so keeping them is useless.

If DSH ever changes its cookie naming rule and the plugin cannot recognize any dsh-auth-*, it will do nothing, resulting in the worst case of reverting to the original state.

Offline Verification

node test/smoke.mjs

24 use cases, independent of DSH and offline: 16 pure functions (cookie name derivation, authority normalization, Cookie header parsing, six scenarios of cleanup strategy, expiration instruction assembly, raw packet and target capture); 6 end-to-end (real node:http server plus raw socket, covering normal pass-through, clean request byte-for-byte unchanged, 20 KiB header rescued to 302, restoring native 431 after disabling fallback, raising limit taking effect, pass-through unchanged after disabling cleanup); 2 robustness (silent when no web service, no exception on malformed config).

Requirements and Boundaries

Plugin version 0.1.0, tested and passed on DSH 0.2.0-rc.2, requires Node ≥ 20 (uses Buffer.toString('base64url') and replaceAll). The plugin does not declare engines.dsh: DSH’s compatibility check treats the presence of this key as exclusive, and since the pre-release version is lower than 0.2.0, writing it would actually block the currently usable version.

The plugin only uses two public members of the webServer service: server and protocol; it does not reuse undeprecated internal symbols. The cookie name is recomputed by the plugin itself using sha256(authority) + base64url, because BrowserAuth, COOKIE_PREFIX, and cookieName are not exported from @deepseek-ai/dsh-client-connection.

Boundaries to note:

  1. Only covers HTTP listening on the Host itself. The desktop main window uses the custom protocol dsh-app://, and the authentication cookie for that path is held by a main process memory variable, not written to the browser cookie jar, so it won’t accumulate in the first place.
  2. Cleanup happens on the next request, not the instant of installation. After installing, the first time a page is opened, the plugin sees and clears the old cookies; if the request header is already over the limit at this point, the overflow fallback is triggered.
  3. It does not change DSH’s port strategy. --port 0 is a legitimate capability for remote access, and the plugin only performs subtraction on the cookie side.

Applicable Scenarios and Notes

Suitable for local developers using the DSH web profile who restart frequently and have experienced white screens or 431s; also suitable for maintainers troubleshooting request header issues locally. The plugin runs with the permissions of the current dsh process and installs the cordis.patch.yml from the repository; before enabling, you should read the source code yourself to confirm the license is MIT.

Manual cleanup can solve an immediate problem: open http://127.0.0.1:<port>, delete Cookies and site data from the site info on the left side of the address bar, or delete dsh-auth-* one by one in Developer Tools Application → Cookies. The cost is that the next startup starts piling up again.

Summary

The position of dsh-cookie-janitor is narrow: it solves the specific problem of “historical authentication cookies accumulating infinitely due to port changes, eventually hitting the request header limit”. The solution is to trim old cookies before the request enters the application and let the browser delete them, while providing a 302 fallback for already overflowing requests. It does not change DSH’s port strategy and does not touch cookies unrelated to dsh-auth-.

Directory Page: https://www.skillhub.cn/plugins/yan3536/dsh-cookie-janitor
Source Code: https://github.com/yan3536/dsh-cookie-janitor

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye