Skip to content

tech4242/aquaman

Repository files navigation

πŸ”±πŸ¦ž Aquaman

CI codecov npm version npm downloads Security: process isolation TypeScript License: MIT

Credential isolation for OpenClaw β€” secrets stay submerged, agents stay dry.

You bought a brand new Mac Mini, set up OpenClaw, and now you're staring at your ~/.openclaw/openclaw.json wondering why your Anthropic API key is sitting there in plaintext. You read the articles. You know what happens when an agent gets prompt-injected. We get it.

Aquaman fixes this with three layers of defense:

  1. Process isolation β€” API keys live in a separate proxy process. The agent never sees them. Even RCE in the agent can't reach credentials β€” they're in a different address space.
  2. Request policies β€” Per-service rules control which endpoints an agent can call. Block admin APIs, prevent deletions, allow drafts but deny sends. Denied requests never get real credentials.
  3. Tamper-evident audit β€” Every credential use is logged with SHA-256 hash chains. You can prove what was accessed and detect tampering after the fact.

No SDK changes required. The proxy is transparent β€” your agent talks to aquaman.local, the proxy injects auth and forwards to the real API.

Quick Start

Local (macOS / Linux)

npm install -g aquaman-proxy              # install the proxy CLI
aquaman setup                             # stores keys, installs OpenClaw plugin
openclaw                                  # proxy starts automatically via plugin

aquaman setup auto-detects your credential backend. macOS defaults to Keychain, Linux defaults to encrypted file. Override with --backend: aquaman setup --backend keepassxc Options: keychain, encrypted-file, keepassxc, 1password, vault, systemd-creds, bitwarden

Existing plaintext credentials are migrated automatically during setup. The migration detects credentials from channels (Telegram, Slack, etc.) and third-party plugins/skills (any *token*, *key*, *secret*, *password* fields in openclaw.json plugin configs). Upstream URLs are auto-detected from plugin config fields like endpoint or baseUrl. Run again anytime to migrate new credentials: aquaman migrate openclaw --auto

The plugin starts the proxy for you β€” no extra steps. To check everything is wired up correctly:

aquaman doctor                 # diagnose issues with actionable fixes
aquaman help                   # list all commands

Docker Setup

Single-image deployment β€” same UDS architecture as local, containerized.

git clone https://github.com/tech4242/aquaman.git && cd aquaman
cp docker/.env.example docker/.env
# Edit docker/.env β€” pick a backend and set its credentials
# needless to say instead of .env you should handle your env properly but this is a starting point you can test.
npm run docker:build
npm run docker:run

How It Works

Agent / OpenClaw Gateway              Aquaman Proxy
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      β”‚              β”‚                      β”‚
β”‚  ANTHROPIC_BASE_URL  │══ Unix ════> β”‚  Keychain / 1Pass /  β”‚
β”‚  = aquaman.local     β”‚   Domain     β”‚  Vault / Encrypted   β”‚
β”‚                      β”‚<═ Socket ═══ β”‚                      β”‚
β”‚  fetch() interceptor │══ (UDS) ══=> β”‚  + Policy enforced   β”‚
β”‚  redirects channel   β”‚              β”‚  + Auth injected:    β”‚
β”‚  API traffic         β”‚              β”‚    header / url-path β”‚
β”‚                      β”‚              β”‚    basic / oauth     β”‚
β”‚                      β”‚              β”‚                      β”‚
β”‚  No credentials.     β”‚  ~/.aquaman/ β”‚                      β”‚
β”‚  No open ports.      β”‚  proxy.sock  β”‚                      β”‚
β”‚  Nothing to steal.   β”‚  (chmod 600) β”‚                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β””β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                         β”‚          β”‚
                                         β”‚          β–Ό
                                         β”‚  ~/.aquaman/audit/
                                         β”‚  (hash-chained log)
                                         β–Ό
                               api.anthropic.com
                               api.telegram.org
                               slack.com/api  ...
  1. Store β€” Credentials live in a vault backend (Keychain, 1Password, Vault, Bitwarden, encrypted file, KeePassXC, systemd-creds)
  2. Policy β€” Proxy checks method + path rules before touching credentials. Denied requests get a 403, never real auth headers.
  3. Inject β€” Proxy looks up the credential and adds the auth header before forwarding. 25 builtin services, 4 auth modes (header, URL-path, HTTP Basic, OAuth).
  4. Audit β€” Every credential use is logged with SHA-256 hash chains.

The agent only sees a sentinel hostname (aquaman.local). It never sees a key, and no port is open for other processes to probe.

Security Model

Layer What it does What it stops
Process isolation Credentials in separate process, connected via Unix domain socket (chmod 600) Compromised agent can't read keys β€” different address space, no TCP port to probe
Service allowlisting proxiedServices controls which APIs the agent can reach Agent can't talk to services you didn't authorize
Request policies Method + path rules per service, enforced before credential injection Agent can reach Anthropic but not its admin API; can draft emails but not send them
Audit trail SHA-256 hash-chained logs of every credential use Post-incident forensics, tamper detection, compliance evidence

Request Policies

OAuth scopes can't distinguish between "draft an email" and "send an email" β€” they're both gmail.send. Request policies fill that gap: allow the service, then restrict what happens inside it.

# ~/.aquaman/config.yaml
policy:
  anthropic:
    defaultAction: allow
    rules:
      - method: "*"
        path: "/v1/organizations/**"
        action: deny          # block admin/billing API
  openai:
    defaultAction: allow
    rules:
      - method: "*"
        path: "/v1/organization/**"
        action: deny          # block admin API
      - method: DELETE
        path: "/v1/**"
        action: deny          # no deletions
  slack:
    defaultAction: allow
    rules:
      - method: "*"
        path: "/admin.*"
        action: deny          # block Slack admin methods
  gmail:
    defaultAction: allow
    rules:
      - method: POST
        path: "/v1/users/*/messages/send"
        action: deny          # drafts ok, sending blocked
  • No policy = allow all (backward compatible)
  • First match wins β€” rules evaluated top-to-bottom, unmatched requests fall through to defaultAction
  • Denied before auth β€” blocked requests never get real credentials
  • Path globs: * matches within a segment, ** matches zero or more segments
  • aquaman setup applies safe defaults (blocks admin/billing endpoints for stored services)
  • aquaman policy list shows all configured rules; aquaman policy test <svc> <method> <path> dry-runs a request
  • aquaman doctor validates your policy config and warns about typos

Credential Backends

Backend Best For Setup
keychain Local dev on macOS (default) Works out of the box
encrypted-file Linux, WSL2, CI/CD AES-256-GCM, password-protected
keepassxc Existing KeePass users Set AQUAMAN_KEEPASS_PASSWORD or key file
1password Team credential sharing brew install 1password-cli && op signin
vault Enterprise secrets management Set VAULT_ADDR + VAULT_TOKEN
systemd-creds Linux with systemd β‰₯ 256 TPM2-backed, no root required
bitwarden Bitwarden users bw login && export BW_SESSION=$(bw unlock --raw)

Important: encrypted-file is a last-resort backend for headless Linux/CI environments without a native keyring. For better security, install libsecret-1-dev (for GNOME Keyring), use systemd-creds (Linux with TPM2), or use 1Password/Vault.

Security Audit

openclaw security audit --deep reports two expected findings:

  • dangerous-exec on proxy-manager.ts β€” the plugin spawns the proxy as a separate process. This is how aquaman keeps credentials out of the agent.
  • tools_reachable_permissive_policy β€” OpenClaw warns that plugin tools (like aquaman_status) are reachable when no restrictive tool profile is set. This is an environment-level advisory about your agent's tool policy, not a vulnerability in aquaman. If your agents handle untrusted input, set "tools": { "profile": "coding" } in openclaw.json to restrict which tools agents can call.

aquaman setup adds the plugin to plugins.allow automatically so OpenClaw knows you trust it.

About

Credential isolation proxy for OpenClaw β€” secrets stay submerged, agents stay dry. πŸ”±πŸ¦ž

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors