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:
- 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.
- 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.
- 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.
npm install -g aquaman-proxy # install the proxy CLI
aquaman setup # stores keys, installs OpenClaw plugin
openclaw # proxy starts automatically via plugin
aquaman setupauto-detects your credential backend. macOS defaults to Keychain, Linux defaults to encrypted file. Override with--backend:aquaman setup --backend keepassxcOptions: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 commandsSingle-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:runAgent / 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 ...
- Store β Credentials live in a vault backend (Keychain, 1Password, Vault, Bitwarden, encrypted file, KeePassXC, systemd-creds)
- Policy β Proxy checks method + path rules before touching credentials. Denied requests get a 403, never real auth headers.
- 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).
- 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.
| 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 |
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 setupapplies safe defaults (blocks admin/billing endpoints for stored services)aquaman policy listshows all configured rules;aquaman policy test <svc> <method> <path>dry-runs a requestaquaman doctorvalidates your policy config and warns about typos
| 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.
openclaw security audit --deep reports two expected findings:
dangerous-execonproxy-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 (likeaquaman_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" }inopenclaw.jsonto restrict which tools agents can call.
aquaman setup adds the plugin to plugins.allow automatically so OpenClaw knows you trust it.