Install
openclaw skills install dashpassEncrypted credential vault on Dash Platform for AI agents. Store and retrieve API keys, tokens, and passwords — encrypted on-chain, decryptable only by you. Triggers on: credential management, password vault, API key storage, secret store, Dash Platform credentials.
openclaw skills install dashpassDashPass lets you store API keys, passwords, and other secrets encrypted on the Dash blockchain. Only someone with your private key can decrypt them — not the blockchain nodes, not your AI agent, not anyone else.
Your AI agent calls a CLI tool to store and retrieve credentials. Encryption happens locally before anything touches the network. The blockchain only ever sees ciphertext. Think of it as a password manager where the "cloud" is a decentralized blockchain.
.env File.env file | DashPass | |
|---|---|---|
| Where secrets live | Plain-text file on one machine | Encrypted on decentralized blockchain |
| Disk failure | Secrets gone (unless backed up) | Recoverable with your key |
| Encryption | None | AES-256-GCM per credential |
| Rotation tracking | Manual | Built-in version history |
| Expiry alerts | None | check --expiring-within 7d |
| Multi-machine | Copy file around (risky) | Any machine with your key |
CLI=skills/dashpass/scripts/dashpass-cli.mjs
# Store a credential
echo "sk-xxx" | node $CLI put --service anthropic-api --type api-key --level sensitive --label "Anthropic key" --value-stdin
# Retrieve a credential
node $CLI get --service anthropic-api --pipe
# Retrieve via mutual confirmation (2-of-2 Shamir shares)
node $CLI get --service anthropic-api --mutual
# List all credentials
node $CLI list
# Rotate to new value
echo "sk-NEW" | node $CLI rotate --service anthropic-api --value-stdin
# Check expiring credentials
node $CLI check --expiring-within 7d
# Vault status + credit balance
node $CLI status
# Delete a credential
node $CLI delete --service my-service
# Export as env vars (for eval)
eval $(node $CLI env --services anthropic-api,brave-search-api)
# Initialize Shamir 2-of-2 shares from CRITICAL_WIF
node $CLI init-shares
# Check share health
node $CLI share-status
DashPass supports a 2-of-2 mutual confirmation mode using Shamir Secret Sharing over GF(2^8). This upgrades the single-key Scheme C to require both Evo (main agent) and CC (execution agent) to agree before any credential can be decrypted.
init-shares: Splits the 32-byte private key derived from CRITICAL_WIF into two Shamir shares using a random degree-1 polynomial evaluated at x=1 (Share A) and x=2 (Share B).~/.dashpass/evo.share, Share B to ~/.dashpass/cc.share (both 0600 permissions).get --mutual: Reads both shares, combines via Lagrange interpolation to reconstruct the private key, derives the per-credential AES key (same ECDH+HKDF as Scheme C), decrypts, then zeroes all sensitive buffers.~/.dashpass/audit.log in JSONL format. No key or share material is ever logged.get still works via Scheme C. With shares, get --mutual uses the new protocol.Buffer.fill(0).# One-time: generate shares from CRITICAL_WIF
node $CLI init-shares
# Verify health
node $CLI share-status
CRITICAL_WIF
│
▼
wifToPrivateKey() ← Base58Check decode, extract 32-byte private key
│
▼
ECDH self-sign (secp256k1) ← computeSecret(getPublicKey()) → sharedSecret
│
▼
HKDF-SHA256 ← hkdfSync('sha256', sharedSecret, salt, 'dashpass-v1', 32)
│
▼
AES-256-GCM ← per-credential encrypt/decrypt
│
▼
Dash Platform ← encryptedBlob + salt + nonce stored on-chain
Each credential gets a unique salt (32 bytes) and nonce (12 bytes), so even identical plaintext values produce different ciphertext.
INIT (one-time):
┌─────────────────────────────────────────┐
│ CRITICAL_WIF → 32-byte private key │
│ │ │
│ ▼ │
│ For each byte i: │
│ a0 = key[i], a1 = random │
│ f(x) = a0 ⊕ (a1 · x) [GF(2^8)] │
│ │ │
│ ┌────┴────┐ │
│ ▼ ▼ │
│ f(1) f(2) │
│ Share A Share B │
│ evo.share cc.share │
│ (0600) (0600) │
└─────────────────────────────────────────┘
DECRYPT (each request):
┌─────────────────────────────────────────┐
│ 1. CC: requestDecrypt(service, reason) │
│ 2. Evo: approveDecrypt(request) │
│ 3. combineShares(A, B) │
│ │ │
│ ▼ │
│ Lagrange interpolation at x=0: │
│ key[i] = sA[i]·L1 ⊕ sB[i]·L2 │
│ L1 = 2·inv(3), L2 = inv(3) │
│ │ │
│ ▼ │
│ Reconstructed private key │
│ │ │
│ ▼ │
│ ECDH + HKDF → AES key → decrypt │
│ │ │
│ ▼ │
│ Zero all buffers (privKey, aesKey, │
│ sharedSecret) │
└─────────────────────────────────────────┘
Key design choices:
| Threat | Protection |
|---|---|
| Single share compromise | Neither share alone reveals any information about the key (information-theoretic security in GF(2^8)) |
| Unauthorized decryption | Both shares must be present — a rogue process with access to only one share file cannot decrypt |
| Key material in memory | All sensitive buffers (privKeyBytes, aesKey, sharedSecret) are zeroed with Buffer.fill(0) after use |
| Audit evasion | Every request/approve/deny/execute is logged to ~/.dashpass/audit.log in JSONL format; no key material is ever logged |
| File permission escalation | Share files are stored with 0600 permissions; directory is 0700 |
| Corrupted shares | init-shares performs a round-trip verification before declaring success |
| Limitation | Explanation |
|---|---|
| Same-machine attacker with root | Both shares live on the same filesystem. A root-level attacker can read both. This is a same-machine deployment limitation. |
| JavaScript string immutability | Hex-encoded share strings are JS immutable strings — they cannot be zeroed from memory. They persist until garbage collected. |
| Process memory dump | If the process is memory-dumped during executeDecrypt, the reconstructed key is briefly in a Buffer. The window is minimized but not zero. |
| Share file backup/sync | If ~/.dashpass/ is included in backups or cloud sync, shares may be replicated to less-secure locations. |
The current deployment is same-machine 2-of-2: both Evo (main agent) and CC (execution agent) run on the same host. This means:
cc.share to a separate host and replace readShareB() with a network request.# Check share health
node $CLI share-status
# If shares are missing or unhealthy, re-initialize:
rm -f ~/.dashpass/evo.share ~/.dashpass/cc.share
node $CLI init-shares
Note: Re-initializing creates new shares from CRITICAL_WIF. Existing encrypted credentials are unaffected — they are decrypted using the same private key derived from the same WIF.
# Shares must be 0600, directory must be 0700
chmod 700 ~/.dashpass
chmod 600 ~/.dashpass/evo.share ~/.dashpass/cc.share
If init-shares reports success but share-status shows wrong permissions, check if a umask override is active.
get --mutual fails with decryption errornode $CLI share-status — both must show Healthy: yesCRITICAL_WIF was rotated after init-shares, the shares are stale. Re-initialize.node $CLI list — confirm the service name matches exactly.The audit log at ~/.dashpass/audit.log is append-only JSONL. To rotate:
mv ~/.dashpass/audit.log ~/.dashpass/audit.log.$(date +%Y%m%d)
# New entries will create a fresh audit.log automatically
Yes — this is by design. Without shares, get (without --mutual) decrypts directly using CRITICAL_WIF. Shares are optional and additive. You can set up mutual confirmation at any time without re-encrypting existing credentials.
Activate this skill when the user or agent needs to:
--pipe for programmatic access.--value-stdin (pipe) for put and rotate. Never use --value with literal secrets — it leaks to shell history.status first if any operation fails with credit or balance errors.CRITICAL_WIF as radioactive — if it appears in conversation, immediately warn the user about exposure risk.If the user has not used DashPass before, read the setup guide:
Read {baseDir}/setup.md
For full CLI command documentation (all parameters, examples, output formats):
Read {baseDir}/references/cli-commands.md
For encryption details, architecture diagrams, trust model, and security analysis:
Read {baseDir}/references/security-model.md
For troubleshooting common errors and known limitations:
Read {baseDir}/references/faq.md
For the prior security audit summary:
Read {baseDir}/references/security-analysis-summary.md
| Intent | CLI Command | Reference |
|---|---|---|
| Store a secret | put | {baseDir}/references/cli-commands.md |
| Retrieve a secret | get | {baseDir}/references/cli-commands.md |
| List credentials | list | {baseDir}/references/cli-commands.md |
| Rotate a credential | rotate | {baseDir}/references/cli-commands.md |
| Check expiring | check | {baseDir}/references/cli-commands.md |
| Vault status | status | {baseDir}/references/cli-commands.md |
| Delete credential | delete | {baseDir}/references/cli-commands.md |
| Export as env vars | env | {baseDir}/references/cli-commands.md |
| Init Shamir shares | init-shares | {baseDir}/scripts/mutual-confirm.mjs |
| Check share health | share-status | {baseDir}/scripts/mutual-confirm.mjs |
| Mutual decrypt | get --mutual | {baseDir}/scripts/mutual-confirm.mjs |
| How encryption works | — | {baseDir}/references/security-model.md |
| Error troubleshooting | — | {baseDir}/references/faq.md |
| First-time setup | — | {baseDir}/setup.md |