npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

zerocreds

v0.3.0

Published

ZeroCreds — MCP server for credential isolation in LLM agents. Bots use passwords without seeing them.

Downloads

89

Readme

ZeroCreds

MCP server for credential isolation in LLM agents. Your bot uses passwords and API keys — but never sees them.

Medium

  Without ZeroCreds                       With ZeroCreds

  User → "password: MyP@ss!" → LLM        User → ●●●●●● → ZeroCreds → encrypted disk
                                           LLM → vault_login("jira") → ZeroCreds → Chrome
  LLM now has your password                LLM sees only { status: "ok" }
  in context, logs, history                Password never enters LLM context

Why

AI agents are getting real access to real systems. They log into websites, call APIs, manage infrastructure. The standard pattern is dangerous:

  "Here's my Stripe key: sk-live-abc123, please check my charges"

That API key is now in the LLM's context window, conversation logs, provider's training pipeline (maybe), and any tool that reads the conversation. One leaked prompt — and your credentials are exposed.

ZeroCreds solves this with a simple principle: the agent operates credentials, but never sees them.

  ┌─────────────────────────────────────────────────────────────┐
  │                                                             │
  │   Credential lifecycle                                      │
  │                                                             │
  │   User types password                                       │
  │         │                                                   │
  │         ▼                                                   │
  │   ┌───────────┐     AES-256-GCM      ┌───────────────┐     │
  │   │ Browser   │ ──────────────────► │ Encrypted     │     │
  │   │ form      │                      │ store (.json) │     │
  │   └───────────┘                      └───────┬───────┘     │
  │                                              │              │
  │              LLM calls vault_login()         │              │
  │                        │                     │              │
  │                        ▼                     ▼              │
  │                  ┌───────────┐         ┌───────────┐        │
  │                  │ ZeroCreds │ ◄────── │ Decrypt   │        │
  │                  │ server    │         │ in memory │        │
  │                  └─────┬─────┘         └───────────┘        │
  │                        │                                    │
  │                        ▼                                    │
  │                  ┌───────────┐                              │
  │                  │ Chrome    │  Fill form via CDP            │
  │                  │ DevTools  │  Password in browser only     │
  │                  └─────┬─────┘                              │
  │                        │                                    │
  │                        ▼                                    │
  │                  { status: "ok" }  ◄── only this goes       │
  │                                        back to LLM          │
  │                                                             │
  └─────────────────────────────────────────────────────────────┘

How It Works

5 MCP tools. The agent calls them like any tool. The difference — credential data never appears in the response.

| Tool | Agent calls | Agent sees | What actually happens | |------|------------|------------|----------------------| | vault_add | vault_add("jira") | { status, site_id } | Browser form opens, user enters password, encrypted to disk | | vault_login | vault_login("jira") | { status, page_title } | Decrypt, fill login form via Chrome CDP, clear password field | | vault_api_request | vault_api_request("stripe", url) | { status, body } | Decrypt API key, inject into headers, sanitize response | | vault_list | vault_list() | [{ siteId, type }] | List credential metadata — no secrets | | vault_status | vault_status("jira") | { active, lastUsed } | Metadata + audit count — no secrets |


Scenarios

1. First-time Login

The agent needs credentials it doesn't have. It asks the user to add them via a secure form — then logs in via Chrome.

  User              AI Agent              ZeroCreds            Chrome
   │                    │                     │                   │
   │ "Log me into       │                     │                   │
   │  Jira"             │                     │                   │
   ├───────────────────►│                     │                   │
   │                    │── vault_list() ────►│                   │
   │                    │◄── []  (empty) ─────┤                   │
   │                    │                     │                   │
   │                    │── vault_add ───────►│                   │
   │                    │   ("jira")          │                   │
   │                    │                     │                   │
   │   ┌────────────────────────────┐         │                   │
   │   │  Browser form opens       │         │                   │
   │   │  localhost:9900/add       │         │                   │
   │   │                           │         │                   │
   │   │  Email:    [[email protected]]  │         │                   │
   │   │  Password: [●●●●●●●●●●]  │         │                   │
   │   │  URL:      [jira.com]     │         │                   │
   │   │                           │         │                   │
   │   │  [Add to Vault]           │         │                   │
   │   └────────────┬───────────────┘         │                   │
   │                │                         │                   │
   │                └── POST ────────────────►│── encrypt         │
   │                                          │── save to disk    │
   │                    │◄─ { status: ok } ───┤                   │
   │                    │                     │                   │
   │                    │   Password is NOT   │                   │
   │                    │   in this response  │                   │
   │                    │                     │                   │
   │                    │── vault_login ─────►│── decrypt ──┐     │
   │                    │   ("jira")          │◄────────────┘     │
   │                    │                     │── fill email ────►│
   │                    │                     │── fill pass  ────►│
   │                    │                     │── click submit ──►│
   │                    │                     │── clear pass  ───►│
   │                    │                     │◄─ page loaded ───┤
   │                    │◄─ { status: ok,  ───┤                   │
   │                    │    title: "Jira" }  │                   │
   │                    │                     │                   │
   │◄── "You're logged  │                     │                   │
   │     into Jira!"    │                     │                   │

2. API Key Proxy

The agent makes API calls. ZeroCreds injects the key into headers and scrubs it from the response.

  AI Agent              ZeroCreds                  Stripe API
   │                      │                            │
   │── vault_api_request ►│                            │
   │   service: "stripe"  │── decrypt API key          │
   │   url: "/v1/charges" │                            │
   │                      │── GET /v1/charges ────────►│
   │                      │   Authorization:           │
   │                      │   Bearer sk-live-****      │
   │                      │◄── { data: [...] } ───────┤
   │                      │                            │
   │                      │── scan response for        │
   │                      │   leaked key               │
   │                      │   (replace with ***)       │
   │                      │                            │
   │◄── { status: ok,  ───┤                            │
   │     body: "..." }    │                            │
   │                      │                            │
   │   API key NOT in     │                            │
   │   this response      │                            │

3. Returning User

Credentials already stored — the agent goes straight to login:

  User              AI Agent              ZeroCreds            Chrome
   │                    │                     │                   │
   │ "Open GitHub"      │                     │                   │
   ├───────────────────►│                     │                   │
   │                    │── vault_list() ────►│                   │
   │                    │◄─ [{ siteId:       ─┤                   │
   │                    │     "github",       │                   │
   │                    │     active: true }] │                   │
   │                    │                     │                   │
   │                    │── vault_login ─────►│── decrypt ───┐    │
   │                    │   ("github")        │◄─────────────┘    │
   │                    │                     │── CDP login ─────►│
   │                    │                     │◄─ success ───────┤
   │                    │◄─ { status: ok } ───┤                   │
   │                    │                     │                   │
   │◄── "Done!"         │                     │                   │

4. Instant Revocation

Remove access — the agent can no longer use the credential:

  Admin (CLI)           ZeroCreds            AI Agent
   │                      │                      │
   │── zerocreds remove   │                      │
   │   "jira"             │── delete + audit log  │
   │◄── "Removed"         │                      │
   │                      │                      │
   │                      │    ... later ...      │
   │                      │                      │
   │                      │◄── vault_login ──────┤
   │                      │    ("jira")           │
   │                      │── { FAIL:          ──►│
   │                      │   "not found" }       │

5. Tamper-Proof Audit Trail

Every credential use is logged with a SHA-256 hash chain:

  ~/.zerocreds/audit.jsonl

  ┌─────────────────────────────────────────────────────────────┐
  │ evt_001 │ credential.created │ jira    │ success │ hash_1  │
  │         │                    │         │         │    │    │
  │ evt_002 │ credential.used    │ jira    │ success │    ▼    │
  │         │ bot: claude        │         │ prevHash: hash_1  │
  │         │                    │         │         │ hash_2  │
  │         │                    │         │         │    │    │
  │ evt_003 │ credential.used    │ jira    │ success │    ▼    │
  │         │ bot: claude        │         │ prevHash: hash_2  │
  │         │                    │         │         │ hash_3  │
  └─────────────────────────────────────────────────────────────┘

  Tamper with any entry → chain breaks → detected

  $ zerocreds audit
  Chain integrity: VALID (3 entries)

6. Web Chat Integration

For browser-based AI chats, the credential form appears inline — no new tab:

  Web Chat (browser)                    ZeroCreds (server)
  ┌──────────────────────┐             ┌──────────────────┐
  │  import { VaultUI }  │◄══ WS ═════►│  WebSocket :9901 │
  │  from 'zerocreds/web'│             │                  │
  │                      │             │  AI agent calls   │
  │  ┌────────────────┐  │◄── event ───│  vault_add()     │
  │  │ Vault          │  │             │                  │
  │  │ Password: ●●●● │  │             │                  │
  │  │ [Grant Access] │  │── POST ────►│  encrypt + save  │
  │  └────────────────┘  │             │                  │
  └──────────────────────┘             └──────────────────┘

  Password goes via HTTP POST (not WebSocket).
  WebSocket is only for signaling "credential needed" / "credential saved".

Quickstart

# Clone and build
git clone https://github.com/Chill-AI-Space/vault-mcp.git
cd vault-mcp && npm install && npm run build

# Register with Claude Code
claude mcp add -s user zerocreds -- node ~/vault-mcp/dist/index.js

# Use: "Log me into GitHub"
# → vault_add("github") → browser form → you enter password
# → vault_login("github") → Chrome logs in
# → Agent sees { status: "ok" } — never the password

Or add credentials via CLI:

zerocreds add --site github --email [email protected] --url https://github.com/login
# Password is prompted interactively (masked with *)

Web SDK (for browser-based AI chats)

import { VaultUI } from 'zerocreds/web';

const vault = new VaultUI({
  vaultUrl: 'http://localhost:9900',  // default
  wsUrl: 'ws://localhost:9901',       // default
  onRequest: (siteId) => console.log(`Credential needed: ${siteId}`),
  onSaved: (siteId) => console.log(`Saved: ${siteId}`),
});

vault.connect();
// When AI agent calls vault_add() → modal appears in your page
// No new browser tab. Password submitted via HTTP POST to vault.

Also works as a script tag:

<script type="module">
  import { VaultUI } from './node_modules/zerocreds/dist/web/vault-ui.js';
  new VaultUI().connect();
</script>

Bundle size: ~6KB, zero runtime dependencies, Shadow DOM (no CSS conflicts).

CLI

zerocreds add                        # Interactive credential entry
zerocreds list                       # List credentials (no secrets)
zerocreds remove <site_id>           # Remove credential
zerocreds audit [site_id]            # Audit log + chain integrity
zerocreds dashboard                  # Web dashboard on localhost:9900

Architecture

zerocreds/
├── src/
│   ├── index.ts              ── CLI or MCP mode (auto-detect)
│   ├── server.ts             ── MCP server with 5 tools
│   ├── cli.ts                ── CLI commands
│   ├── tools/
│   │   ├── vault-add.ts      ── Browser form OR WebSocket modal
│   │   ├── vault-login.ts    ── Decrypt → Chrome CDP → fill form
│   │   ├── vault-api.ts      ── Decrypt → inject headers → sanitize
│   │   ├── vault-list.ts     ── Metadata only
│   │   └── vault-status.ts   ── Metadata + audit stats
│   ├── ws/
│   │   └── server.ts         ── WebSocket server (127.0.0.1:9901)
│   ├── web/
│   │   ├── vault-ui.ts       ── Web SDK (WS client + modal)
│   │   └── modal.ts          ── Shadow DOM modal (dark theme)
│   ├── store/
│   │   ├── encrypted-store.ts ── AES-256-GCM, unique IV per credential
│   │   └── keychain.ts        ── Master key management
│   ├── browser/
│   │   └── cdp-bridge.ts     ── Playwright CDP bridge
│   ├── audit/
│   │   └── logger.ts         ── JSONL + SHA-256 hash chain
│   └── dashboard/
│       ├── server.ts         ── HTTP + WS bootstrap
│       ├── index.html        ── Dashboard UI
│       └── add.html          ── Credential entry form
├── dist/web/
│   └── vault-ui.js           ── Bundled Web SDK (~6KB)
└── test/                     ── 36 tests

Configuration

| Variable | Default | Description | |----------|---------|-------------| | ZEROCREDS_MASTER_KEY | auto-generated | Encryption key (scrypt → 32 bytes). VAULT_MASTER_KEY also accepted for backward compatibility. | | ZEROCREDS_CDP_URL | http://localhost:9222 | Chrome DevTools endpoint. VAULT_CDP_URL also accepted. |

Storage

~/.zerocreds/
├── credentials.json    ── AES-256-GCM encrypted (unique IV per entry)
├── audit.jsonl         ── Append-only, SHA-256 hash chain
└── .master-key         ── Master key (mode 0600, auto-generated)

On first run, if ~/.vault-mcp/ exists and ~/.zerocreds/ does not, the data directory is automatically migrated.

Security

  Protects against                 Does NOT protect against
  ─────────────────                ────────────────────────
  ✓ LLM context leakage           ✗ Compromised host (root access)
  ✓ Plaintext credential storage   ✗ Malicious MCP client
  ✓ Audit log tampering            ✗ Browser-level memory attacks
  ✓ Accidental exposure in logs    ✗ Network MITM to target sites

See SECURITY.md for full threat model.

Testing

npm test           # 36 tests
npm run test:watch

License

MIT