Ox0400/dsh-vault

dsh-vault

Harness 的本地加密凭据保险库:Web 设置页与 vault_* 工具,可存取与复制密码、API 密钥、TOTP 与银行卡信息,支持健康审计、到期轮换、导入导出以及只读/询问访问模式。

未分類deepseekdeepseek-harnessdsh-plugins

dsh-vault — Encrypted Credential Vault for DeepSeek Harness

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 / cookie / card / 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

Two kinds carry their own shape: a cookie entry stores a captured browser session, and a card entry stores cardNumber / cardExpiry (MM/YY) / cardCvv / cardHolder — search summaries expose only the expiry and holder, never the number or CVV, and the Bitwarden JSON export maps it to a card item (type 3, brand inferred). | fields | Arbitrary key/value pairs (e.g. {"region": "us-east-1"}), searchable |

Tools

113 tools in five groups. Basic is what a default install registers; the rest are switched on through Tool profiles (Settings → Credentials → Permissions → Model tools).

Basic (registered by default) — 11

Eleven tools. Everything below is opt-in.

ToolPurpose
vault_listList available vaults in the vault directory (one .json file per vault, excluding access/meta/export files)
vault_searchSearch 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_getRead a full entry by id (including all secrets)
vault_addAdd an entry (any combination of fields; empty strings/arrays are ignored)
vault_updateUpdate fields by id (unprovided fields kept; empty string clears a field; title is renamable; rotationDays: 0 clears rotation = never rotate)
vault_deleteSoft-delete an entry (moves it to the trash, still encrypted on disk)
vault_fillFind the entry matching a host/URL/username/title and return its credentials
vault_clipboardFetch one entry secret field for direct copy (username/password/apiKey/...)
vault_totpGenerate the current 6-digit code for a stored otpSecret (or a bare Base32 / otpauth URI)
vault_generate_passwordGenerate a strong random password (length/classes/grouping) or a memorable passphrase (passphrase: true, EFF-style word list, words/separator/wordDigits)
vault_strengthZero-dependency password strength estimate (score 0–100, weak/fair/strong/very strong)

Management (Standard and up) — 53

Favourites, tags, history, health, templates, attachments, card and 2FA detail.

ToolPurpose
vault_compareCompare two entries field by field (onlyA/onlyB/differ/equal) — field names only, never secret values
vault_renameRename an entry in one call (shortcut for vault_update)
vault_restore / vault_purge / vault_restore_recentBring a trashed entry back / purge it / undo the last delete
vault_lock / vault_unlockExplicitly lock the vault (wipe the in-memory key) / re-unlock it
vault_password_historyList an entry's previous passwords (1Password/Bitwarden-style, newest first, capped at 10; current password excluded)
vault_password_rollbackRestore an entry password to a stored history entry (current password is archived first, so it is reversible)
vault_apply_tagsBulk add/remove/replace tags on every entry matching a query (dry-run supported, no secrets)
vault_totp_uriBuild an otpauth:// provisioning URI for a stored or bare TOTP secret
vault_rotationReport expired / due-for-rotation / expiring-soon credentials; soonWindowDays (1-90, default 7) tunes the soon horizon (no secrets)
vault_healthVault health scan: weak/reused passwords, missing 2FA, insecure http:// sites, and an overall security score (0–100)
vault_watchtowerWatchtower-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_checkWatchtower-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_integrityVerify the on-disk vault file decrypts correctly and matches the in-memory store
vault_mergeMerge one entry into another; keepSource: true keeps the source after merging
vault_attach / vault_attachments / vault_attachment / vault_detachAttach 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_addFast capture (title + one secret) with optional tags/notes
vault_expirySet/clear expiry (expiresAt: 0 removes it)
vault_statsOverview counts incl. trashCount (no secrets)
vault_verifyVerify one entry or audit every entry (all: true) for per-kind completeness, port/expiry sanity (no secrets)
vault_duplicatesFind duplicate groups: mode = both (default) / title / content (no secrets)
vault_reportPrintable inventory with expiry/rotation columns and a stats footer (no secrets)
vault_match_urlFind 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_envRender env-flagged entries (tags contain env) as KEY=VALUE lines — see Environment export
vault_copyCopy an entry (secrets included) into another named vault
vault_templatesBuilt-in + user-defined templates (save/list/remove), KeePassXC-style; built-ins now include Wi-Fi, Server, Database, Identity, Bank account, Card (1Password-inspired)
vault_notesAppend to or replace the free-form notes of an entry (a convenient shortcut for vault_update)
vault_changesList vault activity within a time window (default 24h): entries created, updated, or soft-deleted, newest first
vault_findFuzzy-find entries: matching ignores case, punctuation and whitespace, so gh reaches GitHub
vault_maskRedact likely credentials in arbitrary text (API keys, tokens, passwords, private keys) so it can be logged or quoted safely
vault_historyShow recent activity on the vault within this process, newest first: mutations (add/update/delete/restore/purge/merge/rollback) plus reads (read, totp), searches and vault switches. Records only the action, entry title and timestamp — never passwords, keys, usernames or other secret values
vault_recentList the most recently created or updated entries (newest first), as secret-free summaries
vault_pinPin (favorite) an entry so it ranks first in search and list
vault_unpinUnpin an entry (remove its favorite flag)
vault_tagsList every tag used across entries with the number of entries per tag
vault_generate_usernameGenerate a random username or an anonymous email suggestion
vault_rotate_passwordGenerate a new strong password, store it on the entry, and return the new value for the caller to hand to the target service
vault_touchMark an entry as recently used (update its updatedAt without changing content)
vault_note_secretStore a single secret under a generated title (a one-off note without naming it)
vault_search_advancedSearch with multiple optional criteria: title substring, username/email substring, kind, tag, created-after/before (epoch millis), and favorite-only
vault_countReturn the number of active entries (optionally filtered by kind and/or tag)
vault_set_iconSet the UI icon (emoji) and/or accent color on an entry
vault_describeDescribe an entry in plain language (kind, identity, host/url, tags, expiry) without revealing secrets
vault_last_modifiedList entries most recently modified (updatedAt), newest first
vault_hasQuickly check whether the vault contains a credential matching a title/username/host (substring, or exact title when exact is set)
vault_autofill_checkCheck whether the vault has a credential usable for a URL/host: returns the best matching entry (username/email only, never the secret) or a not-found verdict
vault_undelete_allRestore ALL soft-deleted (trashed) entries back to the active set
vault_get_manyRead multiple entries by id, returning only the requested fields for each

Import & export (Full, or Custom → Import-export) — 27

Migrating in and out of other password managers, bulk operations, and env/CSV/1Password/Bitwarden/KeePass/pass interop.

ToolPurpose
vault_import_csvBulk-import credentials from a CSV file (custom columns become fields; overwrite: true merges fields into existing entries instead of duplicating)
vault_bulk_deleteSoft-delete entries matching a query/kind/tag or explicit ids; confirm: true required (dry-run by default); trashed entries are restorable
vault_export / vault_importPortable encrypted backup/migration of the whole vault (separate export password)
vault_export_bitwarden / vault_import_bitwardenBitwarden/Vaultwarden JSON interop (full field mapping, overwrite support)
vault_import_bitwarden_encryptedDecrypt a Bitwarden password-protected JSON export (PBKDF2/Argon2id + HKDF → AES-256-CBC + HMAC) and import it; pass the export passphrase
vault_import_manager_csvPassword-manager CSV auto-detected by header: Bitwarden (login_uri/login_username/…), 1Password 8, Dashlane, NordPass, Keeper, LastPass (fav/grouping/extra); dryRun preview
vault_import_kdbxKeePass KDBX: 3.1 and 4.x, AES-KDF or Argon2 (RFC 9106), AES-256-CBC or ChaCha20 payload, keyfile support
vault_export_1passwordExport 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_1pif1Password 1PUX (ZIP) and legacy 1PIF text exports
vault_import_enpassEnpass JSON export (folders → tags, typed fields, TOTP)
vault_import_keepass_xmlKeePass 2.x XML export (plaintext or ******** masked values)
vault_import_chrome / vault_import_keychainImport 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_firefoxFirefox profile import (logins.json + key4.db, NSS 3DES / PBES2-AES, primary-password aware)
vault_export_totpList every entry that has a TOTP secret, with its title and issuer label
vault_bulk_exportExport ALL entries (including secrets) as a JSON file for audit or migration
vault_export_browserExport login entries in the browser password-manager CSV format (name,url,username,password) for importing into Chrome/Firefox/Edge
vault_migrate_keepassExport entries in KeePass 2.x import CSV format (Group,Title,Username,Password,URL,Notes) for migrating into KeePass
vault_export_keepass_xmlExport entries as a KeePassXC-compatible XML document (KeePass 2.x schema)
vault_import_browserImport a browser password-manager CSV (name,url,username,password — Chrome/Firefox/ Edge export format)
vault_export_walletExport entries as a directory tree of files compatible with pass (the standard Unix password manager): one file per entry containing the password, with metadata in comments
vault_import_walletImport entries from a pass directory tree: each .gpg file (or plaintext file) becomes an entry titled by its filename; the first line is the password, remaining lines are parsed as login:/email:/url: metadata. Returns added/skipped
vault_export_envWrite env-flagged entries (tags contain "env") to a .env file at the given path as KEY=VALUE lines (values shell-quoted)
vault_export_csvExport vault entries to a CSV file (the same shape vault_import_csv accepts), optionally filtered by kind

Browser sessions (Full, or Custom → Browser sessions) — 8

Capturing and replaying cookie sessions; needs the optional playwright-core.

ToolPurpose
vault_session_openOpen 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 — requires the optional playwright-core
vault_session_collectCollect every cookie of an open browser session (incl. HttpOnly) and save it as a cookie entry
vault_session_importSave session cookies from pasted JSON (devtools export shape) or a raw Cookie header string — the no-browser alternative
vault_session_import_fileImport a Netscape cookie-jar file (curl -b / wget / browser-extension export; the same format vault_session_export writes)
vault_session_listList saved login sessions with cookie counts, expired and expiring-in-7d counts (no values)
vault_session_exportExport 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_closeClose an open browser login session (collected cookies stay in the vault)
vault_session_pruneRemove expired cookies from a saved session (session cookies are kept); preview: true reports without writing

Backups & vault files (Full, or Custom → Backups & files) — 14

Backups, vault switching, rekeying, recovery codes and system search.

ToolPurpose
vault_recovery_code / vault_verify_recovery / vault_recovery_statusOne-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_rekeyUpgrade the vault to fresh scrypt KDF parameters in place
vault_switchSwitch the active vault for this session
vault_backup / vault_backup_nowTimestamped encrypted backup named <vault>-backups-YYYY-MM-DD_HH-MM-SS-<hex>.json (owning vault + date visible); retention pruning keeps the newest N (maxBackups, default 10)
vault_restore_backupRestore 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_deleteRename a named vault (file moves, active session follows) or permanently delete one (default vault protected)
vault_search_systemSearch Chrome / Keychain for sites & usernames — never exposes passwords
vault_backup_statusReport how many days have passed since the last backup file was written (1Password-style backup reminder; new-style <vault>-backups-<date>.json and legacy vault-backup-<epoch>.json names are both recognized). Returns daysSinceBackup and a suggestion
vault_search_historySearch including soft-deleted (trashed) entries, marked with their deleted state
vault_backupsList available encrypted vault-backup-*.json files (newest first) with their absolute paths and timestamps

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):

    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):

    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).

Command line

The plugin hands the vault to the assistant. The bundled dsh-vault command hands the same vault to shells and scripts, so a skill's child process can read a secret without the plaintext ever entering the model's context.

0. First: which command can you actually type?

Nothing provides a dsh-vault binary until the package is installed — the plugin is a Cordis bundle, and dsh has no plugin-subcommand registry (the launcher parses only its own flags; dsh plugin … just forwards to pnpm, so dsh web exec … hands its arguments to the web app and fails with error: too many arguments). Pick your row before reading the examples:

your setupthe command
source checkout (git clone + pnpm build)pnpm vault — or node lib/cli.js, or ./lib/cli.js
plugin installed into a profilepnpm dsh plugin --profile web exec dsh-vault
globally installed (npm i -g dsh-vault)dsh-vault
nothing installednpx dsh-vault
# source checkout — this repository, right now:
pnpm vault list

# after a global install (or via npx) the same commands are:
dsh-vault list
npx dsh-vault list

Every example below is written as dsh-vault …; substitute the form from your row (pnpm vault … in a checkout).

1. What env is for

get fetches one value and needs no tag. dsh-vault env is for the other case: a script that needs several secrets at once. It prints the entries you tagged env as shell assignments, so the script picks them up itself:

$ dsh-vault env
DEMO_API_KEY='sk-demo-123'
OTHER_PASSWORD='pw-not-exported'

eval "$(dsh-vault env)" reads those assignments into the current shell — the usual reason to reach for it:

eval "$(dsh-vault env)"          # KEY=VALUE lines become shell variables
echo "$DEMO_API_KEY"

Two things worth knowing:

  • Only env-tagged entries are exported. With none tagged you get `dsh-vault: nothing to export — no entry carries