New
Apps 367Makers 367This week 367
Promote your app−30%
2views in
the last 30 days

Vultrino

Credential proxy so AI agents never see the keys

Built with Claude Code

by feirai · added Oct 29, 2026
no ratings0 comments
Open app Code

A credential proxy for the AI era — enabling AI agents to use credentials without seeing them.

What is Vultrino?

Vultrino is a credential proxy that keeps raw credential fields out of the agent-facing API and injects authentication inside trusted connectors. Instead of giving an agent an API key, you give it a credential alias and an action surface.

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   AI Agent      │────▶│    Vultrino     │────▶│   External API  │
│   (Claude, etc) │     │   (injects auth)│     │   (GitHub, etc) │
└─────────────────┘     └─────────────────┘     └─────────────────┘
        │                       │
        │ "Use github-api       │ Authorization: Bearer ghp_xxx...
        │  credential"          │
        ▼                       ▼
   Alias-only request     Handles authentication

Features

  • Credential Isolation — agent-facing schemas carry aliases and confined responses, not raw credential fields
  • Role-Based Access Control — Fine-grained permissions with credential scoping
  • Multiple Credential Types — API keys, Basic Auth, OAuth2 (with automatic token refresh), and extensible via plugins
  • OAuth2 Support — Client credentials and refresh token flows with automatic token refresh
  • Scoped API Keys — Restrict which credentials each API key can access using glob patterns
  • Plugin System — Extend with custom credential types and actions via WASM plugins
  • MCP Integration — Native Model Context Protocol support for LLM tools
  • Metered LLM Proxy — Point any OpenAI/Anthropic-compatible client's base_url at Vultrino with a Vultrino key instead of the provider key; the real model key stays in the vault and token spend is metered. Supports incremental SSE streaming (stream: true) with on-the-fly secret scrubbing.
  • Use Tokens — Single-use or time-scoped grants that let an agent perform one specific action
  • Action Approvals — Human-in-the-loop sign-off (admin panel, Telegram, or webhook/email) before an action runs
  • Web UI — Clean admin interface for managing credentials, roles, and API keys
  • Encrypted Storage — AES-256-GCM encryption with Argon2 key derivation
  • Policy Engine — URL patterns, method restrictions, rate limiting
  • Usage Events: credential use and admin changes are recorded as events in the event outbox (replayable with GET /api/v1/events) and in structured logs. A durable audit-log file and a working web Audit Log page are not implemented yet (see LIMITATIONS).

Installation

Requirements

  • Rust 1.96.0 (pinned in rust-toolchain.toml; rustup installs it)
  • No system OpenSSL packages — TLS uses rustls

From Source

git clone https://github.com/FeirAI/vultrino.git
cd vultrino
cargo build --release --locked
cp target/release/vultrino ~/.local/bin/

Release binaries / Docker

Tagged releases (v*) publish platform archives and a container image:

# Binary (example: Apple Silicon)
curl -L https://github.com/FeirAI/vultrino/releases/latest/download/vultrino-aarch64-apple-darwin.tar.gz | tar xz
sudo mv vultrino /usr/local/bin/

# Container
docker pull ghcr.io/feirai/vultrino:latest

See Installation for Linux/macOS variants.

Quick Start

1. Initialize Storage

# Create config.toml and the web UI admin login (interactive; `vultrino web` refuses to start without the login)
vultrino init

# Set your encryption password
export VULTRINO_PASSWORD="your-secure-password"

# Add your first credential
vultrino add --alias github-api --key ghp_your_token_here

2. Make Authenticated Requests

# Make a request using the credential
vultrino request github-api https://api.github.com/user

3. Start the Web UI

# Required by `vultrino web` (it refuses to start without it): a stable secret, kept the same across restarts
export VULTRINO_POLICY_HASH_SECRET="<stable random secret>"

# Start the admin interface
vultrino web

# Open http://127.0.0.1:7879 in your browser

4. Use with AI Agents (MCP)

# Start MCP server for LLM integration
vultrino serve --mcp

Usage

CLI Commands

# Credential Management
vultrino add --alias <name> --key <api-key>    # Add API key credential
vultrino add --alias <name> -t basic_auth      # Add basic auth (interactive)
vultrino add --alias <name> -t oauth2 \        # Add OAuth2 credential
  --client-id <id> --client-secret <secret> \
  --token-url https://oauth.example.com/token \
  --scopes "read,write"
vultrino add --alias <name> -t ssh_password \  # Add SSH (password) credential
  --ssh-host <host> --ssh-user <user>          # for ssh plugin deploy/run
vultrino add --alias <name> -t postgres \      # Add Postgres credential
  --pg-host <host> --pg-database <db> \        # for postgres plugin run_sql/backup
  --pg-user <user> --pg-sslmode require
vultrino list                                   # List all credentials
vultrino remove <alias>                         # Remove a credential

# Per-credential defaults (non-secret configuration)
vultrino meta set <alias> <key> <value>         # e.g. deploy.source_dir, run.commands
vultrino meta list <alias>                      # Show all metadata for a credential
vultrino meta unset <alias> <key>               # Remove a metadata key

# Making Requests
vultrino request <alias> <url>                  # GET request
vultrino request <alias> <url> -X POST -d '{}'  # POST with body

# Plugin Actions
vultrino action <credential> <plugin.action>    # Execute plugin action
vultrino action my-server ssh.deploy            # Rsync via stored SSH credential
vultrino action my-server ssh.run               # Run a configured command sequence
vultrino action my-db postgres.run_sql          # Apply the configured migration script
vultrino action my-db postgres.backup           # pg_dump to the configured output dir

# Plugin Management
vultrino plugin install <path-or-url>           # Install a plugin
vultrino plugin list                            # List installed plugins
vultrino plugin info <name>                     # Show plugin details
vultrino plugin remove <name>                   # Remove a plugin

# Role & API Key Management
vultrino role create <name> --permissions read,execute --scopes "github-*"
vultrino role list
vultrino key create <name> --role <role-name>
vultrino key list

# Use Tokens (single-use / time-scoped agent grants)
vultrino token create deploy-once \              # one-shot, expires in 10 minutes
  --credential "deploy-*" --action ssh.deploy --uses 1 --expires 10m
vultrino token create reporter \                 # time-scoped, unlimited uses for 24h
  --credential github-api --action http.request --expires 24h
vultrino token create risky --credential prod-db --require-approval  # gate every use
vultrino token list
vultrino token revoke <id|prefix|name>

# Action Approvals (human-in-the-loop)
vultrino approval list                           # see pending/decided requests
vultrino approval status <id>                    # show status; runs it if approved
vultrino approval status <id> --wait             # block until decided, then return result
vultrino approval approve <id>
vultrino approval deny <id>

# Server Modes
vultrino web                                    # Start web UI
vultrino serve --mcp                            # Start MCP server

Web UI

The web interface provides:

  • Dashboard — Overview of credentials and recent activity
  • Credentials: add and remove credentials (no in-place edit; to change one, delete and re-create it)
  • API Keys — Manage access keys for external applications
  • Roles — Configure role-based access control
  • Audit Log: placeholder page; it does not show usage history yet (use the event outbox, GET /api/v1/events, for usage and admin-change records)

OAuth2 Credentials

Vultrino supports OAuth2 with automatic token refresh for machine-to-machine authentication:

# Add OAuth2 credential via CLI
vultrino add --alias my-oauth2 -t oauth2 \
  --client-id your-client-id \
  --client-secret your-client-secret \
  --token-url https://oauth.example.com/token \
  --scopes "api,read,write"

# With optional refresh token (for providers that issue them upfront)
vultrino add --alias my-oauth2 -t oauth2 \
  --client-id your-client-id \
  --client-secret your-client-secret \
  --token-url https://auth.provider.com/token \
  --refresh-token your-refresh-token

Supported Grant Types:

  • client_credentials — Machine-to-machine API access (default)
  • refresh_token — Use refresh token to obtain new access token

Automatic Token Refresh:

  • Vultrino automatically fetches tokens before the first request
  • Tokens are refreshed 5 minutes before expiration
  • Updated tokens are persisted to storage automatically
  • If refresh token flow fails, falls back to client credentials

Security:

  • Token URLs must use HTTPS
  • SSRF protection prevents token endpoints pointing to internal IPs
  • Client secrets are encrypted at rest

Scoped API Keys

API keys can be scoped to only access specific credentials using glob patterns:

# Create a role with credential scoping
vultrino role create github-only \
  --permissions read,execute \
  --scopes "github-*" \
  --description "Can only access GitHub credentials"

# Create an API key with this role
vultrino key create github-agent --role github-only
# Output: vk_abc123...

# This key can only access credentials matching "github-*"

Scope Patterns:

  • github-* — Matches github-api, github-org, etc.
  • *-prod — Matches aws-prod, stripe-prod, etc.
  • oauth2-* — Matches all OAuth2 credentials
  • Empty scopes (default) — Access all credentials

Using Scoped Keys:

# CLI: Pass the API key with -k flag
vultrino -k vk_abc123... request github-api https://api.github.com/user

# MCP: Include api_key in tool arguments
{"name": "http_request", "arguments": {
  "api_key": "vk_abc123...",
  "credential": "github-api",
  "method": "GET",
  "url": "https://api.github.com/user"
}}

MCP Integration

Vultrino provides native MCP (Model Context Protocol) support for AI agent integration:

# Start MCP server
vultrino serve --mcp

# Or use the dedicated mcp command
vultrino mcp

Available MCP tools:

  • http_request — Make authenticated HTTP requests
  • list_credentials — List available credentials
  • get_credential_info — Get credential metadata
  • check_approval — Poll a pending action approval and retrieve its result once approved
  • ABI-v2 plugin tools whose actions need only public parameters and a non-secret credential handle

Example MCP Request:

{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {
  "name": "http_request",
  "arguments": {
    "api_key": "vk_your_api_key",
    "credential": "github-api",
    "method": "GET",
    "url": "https://api.github.com/user"
  }
}}

Use Tokens

A use token is a narrow, ephemeral grant — the opposite of a durable API key. It authorizes one kind of action against one credential (or glob), optionally capped to a number of uses and/or a time window. Hand it to an agent in the same place as an API key (the api_key field, or Authorization: Bearer); it is recognized by its vut_ prefix.

# "POST to the deploy webhook once, in the next 10 minutes"
vultrino token create deploy-once \
  --credential deploy-hook --action http.request --uses 1 --expires 10m
# Output: vut_xxxxxxxx... (shown once)
  • Single-use (--uses 1) or limited-use (--uses N); omit for unlimited.
  • Time-scoped with --expires (30m, 24h, 7d; omit for never).
  • Scoped to a credential glob (--credential) and optionally a single action or plugin.* glob (--action).
  • Uses are counted fail-closed: the use is spent the moment the action runs, even if the downstream call errors, so a single-use token can never run twice.
  • Add --require-approval to gate every use behind a human decision (below).

Manage tokens in the Use Tokens page of the web UI or with vultrino token list / vultrino token revoke.

Action Approvals

Some actions are too consequential to let an agent run unsupervised. Mark them and Vultrino will pause for a human before the action executes — no action result is returned until someone signs off.

What triggers approval (any of):

  • A credential flagged with vultrino meta set <alias> require_approval true
  • A use token created with --require-approval
  • A matching policy rule with action = "prompt"
  • A stored capability whose trusted reversibility is partially-reversible or irreversible. This signal is independent of policy/token flags.

On the production vultrino web surface, a directly executed action must have an exact stored declaration for the credential it actually injects. A presented business label cannot borrow a canonical sibling's classification, a request cannot borrow a declaration for another credential, and a shared bare canonical verb cannot run directly (it may proceed only through authoritative approval). A missing exact label declaration or unavailable catalog is refused before dispatch. Consequently the only catalog classification that can reach the direct path is an exact trusted reversible declaration for that credential and action. An approval freezes both its catalog class and its authoritative Govder recipe (including risk/irreversibility facts). Resume re-fetches both before minting an execution permit; catalog reclassification/deletion or recipe replacement/removal requires a new approval. Production strict posture also refuses an inconclusive recipe lookup for reversible actions instead of inferring the weaker one-person numeric fallback. New vultrino init configurations enable the same posture for stdio; older stdio/embedded configurations can opt in with [enforcement] require_declared_capabilities = true.

If approvals are disabled, a triggered action is refused; disabling the approval subsystem never converts a human-floor action into a direct action.

How it works (and what the agent sees):

  1. The agent calls a tool. Instead of a result it gets a clear "APPROVAL REQUIRED" message with an approval_id — the action has not run.
  2. The agent polls the check_approval MCP tool (or GET /api/v1/approvals/{id}, or vultrino approval status <id> --wait) with that id.
  3. A human approves or denies it — in the Approvals page of the admin panel, via a Telegram button, or via a link delivered by webhook/email.
  4. Once approved, the next poll runs the action and returns the real result. If denied or expired, the agent is told to stop.

Configure out-of-band notifications under [approvals] in config.toml:

[approvals]
enabled = true
ttl_secs = 3600                                   # auto-expire undecided requests
public_base_url = "https://vultrino.example.com"  # used in approve/deny links

[approvals.telegram]                              # inline Approve/Deny buttons
bot_token = "123456:ABC-DEF..."
chat_id = "987654321"

[approvals.webhook]                               # POST to any URL (email/Slack/...)
url = "https://hooks.example.com/vultrino-approvals"
auth_header = "Bearer your-webhook-secret"

Out-of-band links carry a single-use capability token and open a confirmation page (a link prefetch can't auto-decide), so the admin panel session is never required to approve from Telegram/email.

Notes & guarantees:

  • Single-use/limited-use tokens are enforced fail-closed with a cross-process file lock, so a token can never drive more than max_uses executions even when the web and MCP servers run as separate processes sharing one vault.
  • Approved actions are designed to execute at most once: execution is claimed atomically (an executed flag, an epoch compare-and-swap, and a stale-claim retake that finalizes rather than re-runs), a crashed mid-execution claim is auto-recovered after a timeout, and a transient pre-execution failure (e.g. a plugin not yet loaded) is retried rather than marked done. This is covered by integration tests; it is not proved. The Lean model proves one-shot only for its own abstract (approval, epoch) model.
  • An agent may only poll approvals it owns. Ownership means the same API key or use token principal, or a caller with the same non-blank agent_label and equal normalized tenants (a blank tenant counts as no tenant, so two untenanted callers match, but an untenanted caller never matches a tenanted one). This lets an agent keep polling after its use token is re-minted.
  • Set public_base_url to an HTTPS address so Telegram/email approve-deny links are confidential. The request log records only the method and the path, never the query string, so a link's capability token is not written to the logs at any level (a reverse proxy in front of vultrino keeps its own access log: keep the token out of that one too).
  • A use token's pending approvals are bounded at open time: a new approval opens only while uses plus the token's approvals still in the pending state is below max_uses, checked-and-inserted atomically under the vault lock. Approvals that have escalated, or were approved but have not run yet, are not counted, so a token can hold more open approvals than it has uses left (a surplus one is refused when it tries to spend a use). This slows, but does not fully prevent, a single-use token flooding the approval queue (or the Telegram/webhook notifier).
  • Policy is re-evaluated when the action finally runs, so an explicit deny rule (URL / method / time-window) still blocks even a human-approved action. The exact Govder recipe and risk facts are also re-fetched; an unavailable or changed authority invalidates the old approval and nothing executes. The exact credential record revision and tenant are revalidated first, so an alias replacement or metadata move cannot inherit the old human decision. Rate limits are charged once, at request time — a human approval is never re-charged against, nor re-denied by, the rate limiter at execution time. When a deny does fire on resume, the use token is left unconsumed.

Plugin System

Vultrino ships with built-in plugins and also supports WASM plugins for extending functionality with custom credential types and actions.

Built-in Plugins

Plugin Credential Types Actions
http api_key, basic_auth, oauth2 request
hmac hmac_api_key request, sign
ecdsa ecdsa_key sign, sign_l1_action
ssh ssh_password deploy (rsync), run (remote exec)
postgres postgres run_sql (migrations/maintenance), backup (pg_dump)

The ssh plugin requires sshpass, ssh, and rsync on the host's PATH. See the SSH plugin docs for the full credential schema, metadata keys, override-lock model, and a worked deploy + restart example.

The postgres plugin requires psql and pg_dump (from postgresql-client or Homebrew's libpq). See the Postgres plugin docs for the credential schema, metadata keys, SQL-override lock mo

Description taken from the repository README.

Ratings

–
0 ratings
5 0
4 0
3 0
2 0
1 0

Rate this app

Sign in to rate

Comments 0

Sign in to comment

No comments yet.

Related apps

#security · #credentials · #proxy