DeepSeek Harness plugin

dsh-vault

Encrypted credential vault for DeepSeek Harness: AES-256-GCM plus TOTP, model tools, and a Settings UI.

Jump to install

Source facts

Repository
Ox0400/dsh-vault
Latest update
Aug 18, 2026
Category
Security & Permissions
GitHub stars
3
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/Ox0400/dsh-vault
Plugin: dsh-vault
Author: Ox0400

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer4 files
README.mdSource · read only
README language

dsh-vault — Encrypted Credential Vault for DeepSeek Harness

![License: MIT](LICENSE) ![npm version](https://www.npmjs.com/package/dsh-vault) ![GitHub Release](https://github.com/Ox0400/dsh-vault/releases) ![npm downloads](https://www.npmjs.com/package/dsh-vault) ![GitHub issues](https://github.com/Ox0400/dsh-vault/issues)

English | 中文

dsh-vault is a security-focused plugin for DeepSeek Harness that stores sensitive credentials — usernames, emails, phone numbers, passwords, TOTP secrets, and developer credentials like SSH connections, API keys, secrets, and OAuth access/refresh tokens — encrypted at rest, and exposes them to the model through CRUD, search, password generation, and TOTP tools, plus a Settings UI page.

Security & Implementation

  • Zero external crypto dependencies: everything is built on Node's built-in node:crypto (AES-256-GCM authenticated encryption, scrypt key derivation, RFC 6238 TOTP).
  • Master password: every entry is encrypted with a 256-bit key derived via scrypt(master password, salt) and AES-256-GCM. The key never touches disk; after unlock it is cached in-process and re-derived on restart.
  • Tamper-evident: GCM auth tags plus a fixed-plaintext verification envelope — a wrong master password or modified ciphertext fails immediately, never returning garbage.
  • No plaintext at rest: the on-disk document contains no plaintext credentials; each entry uses an independent random nonce.
  • Atomic writes: reuses the harness writeFileAtomic + file lock; in-process writes are serialized, cross-process writers take the lock.
  • Search never leaks: vault_search returns summaries only (id/title/kind/username/email/phone/host/port/url/tags) — never passwords, keys, tokens, or TOTP secrets. Full credentials are readable only via explicit vault_get by id.

Entry Model

Each record has a title, an optional kind, and any combination of fields:

FieldDescription
kindlogin (default) / ssh / api-key / secret / oauth / custom
username / email / phoneAccount identity
passwordThe password
host / portSSH host and port (e.g. db.internal / 2222)
privateKeySSH private key (PEM)
apiKeyAPI key
secretGeneric secret (client secret, shared secret, …)
accessToken / refreshToken / expiresAtOAuth token pair and expiry (epoch millis)
otpSecretTOTP secret (bare Base32 or otpauth:// URI)
url / notes / tagsMetadata
fieldsArbitrary key/value pairs (e.g. {"region": "us-east-1"}), searchable

Tools

| Tool | Purpose | |---|---| | vault_add | Add an entry (any combination of fields; empty strings/arrays are ignored) | | vault_get | Read a full entry by id (including all secrets) | | vault_search | Search titles/categories/usernames/emails/phones/hosts/ports/URLs/notes/tags/custom fields (incl. numeric/boolean/nested values; whitespace-separated terms OR-match); optional createdAfter/createdBefore epoch-millis filters; returns secret-free summaries; limit must be an integer 1–100 | | vault_update | Update fields by id (unprovided fields kept; empty string clears a field; title is renamable; rotationDays: 0 clears rotation = never rotate) | | vault_compare | Compare two entries field by field (onlyA/onlyB/differ/equal) — field names only, never secret values | | vault_rename | Rename an entry in one call (shortcut for vault_update) | | vault_delete | Soft-delete an entry (moves it to the trash, still encrypted on disk) | | vault_restore / vault_purge / vault_restore_recent | Bring a trashed entry back / purge it / undo the last delete | | vault_lock / vault_unlock | Explicitly lock the vault (wipe the in-memory key) / re-unlock it | | vault_totp | Generate the current 6-digit code for a stored otpSecret (or a bare Base32 / otpauth URI) | | vault_generate_password | Generate a strong random password (length/classes/grouping) or a memorable passphrase (passphrase: true, EFF-style word list, words/separator/wordDigits) | | vault_strength | Zero-dependency password strength estimate (score 0–100, weak/fair/strong/very strong) | | vault_password_history | List an entry's previous passwords (1Password/Bitwarden-style, newest first, capped at 10; current password excluded) | | kind: card | Bank/credit-card entries: cardNumber/cardExpiry (MM/YY)/cardCvv/cardHolder; search summaries expose expiry + holder only (never the number or CVV); Bitwarden JSON export maps to a card item (type 3, brand inferred) | | vault_password_rollback | Restore an entry password to a stored history entry (current password is archived first, so it is reversible) | | vault_recovery_code / vault_verify_recovery / vault_recovery_status | One-time vault recovery code (1Password/Bitwarden-style): 32-char code shown once, only its SHA-256 hash is stored; verify possession of the code; check whether one is set | | vault_rekey | Upgrade the vault to fresh scrypt KDF parameters in place | | vault_backup | Timestamped encrypted backup with retention; optional note | | vault_import_csv | Bulk-import credentials from a CSV file (custom columns become fields; overwrite: true merges fields into existing entries instead of duplicating) | | vault_bulk_delete | Soft-delete entries matching a query/kind/tag or explicit ids; confirm: true required (dry-run by default); trashed entries are restorable | | vault_apply_tags | Bulk add/remove/replace tags on every entry matching a query (dry-run supported, no secrets) | | vault_totp_uri | Build an otpauth:// provisioning URI for a stored or bare TOTP secret | | vault_switch / vault_list | Switch the active vault by name / list available vaults | | vault_rotation | Report expired / due-for-rotation / expiring-soon credentials; soonWindowDays (1-90, default 7) tunes the soon horizon (no secrets) | | vault_health | Vault health scan: weak/reused passwords, missing 2FA, insecure http:// sites, and an overall security score (0–100) | | vault_watchtower | Watchtower-style per-entry risk analysis (1Password/Bitwarden-inspired): flags short/weak passwords, keyboard sequences, embedded years, common passwords, reuse, http:// sites, missing 2FA, expiry — with a 0–100 score and good/warn/poor verdict (no secrets); entry rows show ⚠ badges | | vault_breach_check | Watchtower-style breach scan against Have I Been Pwned (k-anonymity: only the SHA-1 prefix leaves the machine), with an offline common-password fallback | | vault_integrity | Verify the on-disk vault file decrypts correctly and matches the in-memory store | | vault_merge | Merge one entry into another; keepSource: true keeps the source after merging | | vault_attach / vault_attachments / vault_attachment / vault_detach | Attach files to entries (private keys, certs, configs, recovery codes) — stored base64 inside the encrypted entry, encrypted at rest; list names/sizes, read content, remove | | vault_quick_add | Fast capture (title + one secret) with optional tags/notes | | vault_expiry | Set/clear expiry (expiresAt: 0 removes it) | | vault_stats | Overview counts incl. trashCount (no secrets) | | vault_verify | Verify one entry or audit every entry (all: true) for per-kind completeness, port/expiry sanity (no secrets) | | vault_duplicates | Find duplicate groups: mode = both (default) / title / content (no secrets) | | vault_report | Printable inventory with expiry/rotation columns and a stats footer (no secrets) | | vault_export / vault_import | Portable encrypted backup/migration of the whole vault (separate export password) | | vault_backup / vault_backup_now | Timestamped encrypted backup named <vault>-backups-YYYY-MM-DD_HH-MM-SS-<hex>.json (owning vault + date visible); retention pruning keeps the newest N | | vault_restore_backup | Restore from a backup: mode: "merge" (default) copies the backup entries INTO the current vault so they appear in the entries list; mode: "replace" overwrites the whole vault with a safety snapshot first | | vault_vault_rename / vault_vault_delete | Rename a named vault (file moves, active session follows) or permanently delete one (default vault protected) | | vault_match_url | Find login entries matching a URL (Bitwarden/1Password-style: exact host, subdomain, parent domain, path-prefix; www./port normalization) with a 0–100 score — never returns the password | | vault_fill | Find the entry matching a host/URL/username/title and return its credentials | | vault_env | Render env-flagged entries (tags contain env) as KEY=VALUE lines | | vault_export_bitwarden / vault_import_bitwarden | Bitwarden/Vaultwarden JSON interop (full field mapping, overwrite support) | | vault_import_bitwarden_encrypted | Decrypt a Bitwarden password-protected JSON export (PBKDF2/Argon2id + HKDF → AES-256-CBC + HMAC) and import it; pass the export passphrase | | vault_import_manager_csv | Password-manager CSV auto-detected by header: Bitwarden (login_uri/login_username/…), 1Password 8, Dashlane, NordPass, Keeper, LastPass (fav/grouping/extra); dryRun preview | | vault_import_kdbx | KeePass KDBX: 3.1 and 4.x, AES-KDF or Argon2 (RFC 9106), AES-256-CBC or ChaCha20 payload, keyfile support | | vault_export_1password | Export entries as a 1Password 1PUX archive (ZIP + export.data) for import into 1Password or re-import here; item categories map to login / credit card / API credential / server | | vault_import_1password / vault_import_1pif | 1Password 1PUX (ZIP) and legacy 1PIF text exports | | vault_import_enpass | Enpass JSON export (folders → tags, typed fields, TOTP) | | vault_import_keepass_xml | KeePass 2.x XML export (plaintext or ******** masked values) | | vault_import_chrome / vault_import_keychain | Import passwords from Chrome's Login Data (macOS keychain / Linux keyring or peanuts / Windows DPAPI) or the macOS Keychain (internet passwords inet by default — the ones that actually back website logins — or generic genp via classes; session cache + preview, no prompt spam); every file import supports dryRun preview | | vault_import_firefox | Firefox profile import (logins.json + key4.db, NSS 3DES / PBES2-AES, primary-password aware) | | vault_search_system | Search Chrome / Keychain for sites & usernames — never exposes passwords | | vault_session_open | Open a real headed browser window at a URL so the user can log in manually (password, 2FA, captcha) — the portable way to capture login state for sites that block embedding | | vault_session_collect | Collect every cookie of an open browser session (incl. HttpOnly) and save it as a cookie entry | | vault_session_import | Save session cookies from pasted JSON (devtools export shape) or a raw Cookie header string — the no-browser alternative | | vault_session_import_file | Import a Netscape cookie-jar file (curl -b / wget / browser-extension export; the same format vault_session_export writes) | | vault_session_list | List saved login sessions with cookie counts, expired and expiring-in-7d counts (no values) | | vault_session_export | Export a saved session as a Cookie header value, a Netscape cookie-jar file (curl -b), raw JSON (Playwright addCookies shape), or a ready-to-run Playwright snippet | | vault_session_close | Close an open browser login session (collected cookies stay in the vault) | | vault_session_prune | Remove expired cookies from a saved session (session cookies are kept); preview: true reports without writing | | vault_copy | Copy an entry (secrets included) into another named vault | | vault_templates | Built-in + user-defined templates (save/list/remove), KeePassXC-style; built-ins now include Wi-Fi, Server, Database, Identity, Bank account, Card (1Password-inspired) | Built-in + user-defined templates (save/list/remove), KeePassXC-style |

Typical workflows: store an SSH credential (kind: ssh + host/port/username/password or privateKey) and have the model vault_search for the host then vault_get the connection details; keep api-key/oauth entries for API-gateway access/refresh token rotation.

Installation

dsh-vault is a bundle (a package declaring dsh.bundle): once installed into a profile, its cordis.patch.yml automatically inserts the vault plugin row (referenced by package name dsh-vault; the master password is injected via the DSH_VAULT_PASSWORD environment variable). The package ships a self-contained build script — git installs compile lib/ automatically.

All four install paths below are verified end-to-end (install → bundle layer recognized → plugin activates with all 7 vault_* tools registered → real vault_add/vault_get round trip → uninstall removes the layer):

PathCommandBuild neededallowBuilds
npmadd dsh-vaultno (prebuilt lib/)no
GitHubadd github:Ox0400/dsh-vault#v0.1.1yes (prepare)yes (first run)
local pathadd /abs/path/to/dsh-vaultno (link to built source)no
tarballadd ./dsh-vault-0.1.1.tgzno (prebuilt lib/)no

Option 1: Install from npm (easiest)

dsh plugin --profile web add dsh-vault

npm packages ship prebuilt lib/ artifacts — no allowBuilds, no local compilation, install and go. Set the master password before launching:

export DSH_VAULT_PASSWORD='your strong master password'

Option 2: Install from GitHub (pin a tag or commit)

dsh plugin --profile web add github:Ox0400/dsh-vault#v0.1.1

A git install fetches sources, not built artifacts, so the prepare script builds lib/ at install time. pnpm ≥10 blocks git dependencies from running build scripts by default. The verified flow:

1. Run the add command — it fails with an allowBuilds error and prints the exact key to allow (the line containing the repo URL, including the resolved commit hash):

``text allowBuilds: dsh-vault@https://codeload.github.com/Ox0400/dsh-vault/tar.gz/<sha>: true ``

2. Append that exact key to the profile's pnpm-workspace.yaml ($DSH_HOME/profiles/<name>/pnpm-workspace.yaml):

``yaml packages: - . allowBuilds: dsh-vault@https://codeload.github.com/Ox0400/dsh-vault/tar.gz/<sha>: true ``

3. Re-run the add — pnpm now runs the prepare script, builds lib/, and installs.

Pin a tag/commit so a later upstream push cannot silently change what runs on install. Treat the allowance for what it is: permission to execute that package's code on your machine at install time — only grant it to sources you trust.

Option 3: Install from a local path

dsh plugin --profile web add /absolute/path/to/dsh-vault

pnpm links the checkout into the profile; the bundle is recognized as long as lib/ exists (run pnpm build in the checkout first if needed).

Option 4: Install from a tarball

npm pack && dsh plugin --profile web add ./dsh-vault-0.1.1.tgz

The tarball ships prebuilt lib/ artifacts, so no build step or allowBuilds is required.

dsh plugin --profile web remove dsh-vault uninstalls (removes both the dependency and the layer).

Configuration

OptionDescription
masterPasswordThe master password inline (appears in cordis.yml; not recommended)
masterPasswordEnvEnvironment variable name holding the master password (recommended)
pathVault file path; defaults to $DSH_HOME/vault/default.json
nameVault name for the default path (e.g. name: work$DSH_HOME/vault/work.json)
accessModeAccess policy for the model tools. Three states: readonly (mutations rejected on tools + UI), ask (default — reads free, every add/update/delete goes through the harness approval channel so the user confirms each write), or auto (automatic read-write, no per-call prompt). The Settings UI offers this exact three-way choice and persists it to <vault dir>/access.json.
autoCapturefalse (default). When true, the system prompt instructs the model to detect credentials shared in conversation and — per user preference — offer to save them with vault_add.
lockTimeoutSecondsAuto-lock: after this many seconds of inactivity the vault re-locks (key wiped) and every read/write requires vault_unlock. 0/absent disables.
exportPasswordEnvEnvironment variable holding the export/import password for vault_export/vault_import (never pass it as a model argument).
backupRetentionHow many encrypted backups to keep (default 10); vault_backup prunes older copies.

Example:

- id: vault
  name: dsh-vault
  config:
    masterPasswordEnv: DSH_VAULT_PASSWORD
    accessMode: ask
    autoCapture: true

With autoCapture: true, when you share a credential in chat (e.g. "my npm token is npm_…"), the assistant offers to store it; on your consent it calls vault_add immediately. With autoCapture off, credentials are only saved when you explicitly ask. The Settings UI shows the current mode (read-only / ask-before-write / automatic read-write) with a dropdown to switch it, an auto-capture toggle (detect credentials shared in chat → offer to save), a kind filter, a health & rotation summary, a trash view, and masked secret fields with a Show/Hide toggle.

The vault is created automatically on first tool use; every launch re-unlocks with the master password. Forgetting the master password = permanent data loss (no backdoor — by design).

Development

Clone and develop locally:

git clone git@github.com:Ox0400/dsh-vault.git
cd dsh-vault
pnpm install    # installs devDependencies (typescript/tsdown/vitest, …)
pnpm build      # builds host lib/*.js and the browser bundle lib/client.js
pnpm test       # runs the 41 vitest tests

> Tests need harness peer packages such as dsh-llm/dsh-system-prompt; inside the harness monorepo these resolve via workspace links.

Common commands:

pnpm test          # unit + integration tests (vitest, 41)
pnpm typecheck     # tsc -p tsconfig.json --noEmit
pnpm build         # = build:host (tsc) + build:client (tsdown)
npm pack           # optional: tarball for `dsh plugin add ./dsh-vault-0.1.1.tgz`

All 41 tests pass (crypto / TOTP / password generation / store CRUD / gateway / integration).

Packaging & Publishing

This package is a standard npm bundle:

  • dsh.bundle.patchcordis.patch.yml (the layer applied automatically when a profile lists this bundle)
  • dsh.client → browser-side declaration (exports["./client"] points at lib/client.js)
  • prepare script → self-contained build on git install (tsc host + tsdown client)
  • Runtime dependencies are all peerDependencies (provided by the host harness — no duplicate instances)

Distribution options:

npm pack                  # tarball → dsh plugin add ./dsh-vault-0.1.1.tgz
npm publish --access public   # registry → dsh plugin add dsh-vault

Security Boundaries & Known Limitations

  • Vault strength is bounded by master-password strength; use ≥ 16 characters of high entropy.
  • scrypt cost parameters (N=32768, r=8, p=1) are persisted in the document and can be raised in future versions; old documents remain decryptable.
  • Plaintext credentials exist only in process memory and during explicit vault_get reads; vault_search/vault_update outputs never contain passwords, keys, or tokens. Secrets returned by vault_get enter that tool call's result (model