{"id":44098136,"url":"https://github.com/tech4242/aquaman","last_synced_at":"2026-04-27T09:02:32.903Z","repository":{"id":336863005,"uuid":"1148355262","full_name":"tech4242/aquaman","owner":"tech4242","description":"Credential isolation proxy for OpenClaw — secrets stay submerged, agents stay dry. 🔱🦞","archived":false,"fork":false,"pushed_at":"2026-02-23T17:02:22.000Z","size":898,"stargazers_count":16,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-24T03:32:40.536Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tech4242.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-02T21:44:22.000Z","updated_at":"2026-02-23T16:44:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tech4242/aquaman","commit_stats":null,"previous_names":["tech4242/aquaman"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/tech4242/aquaman","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tech4242%2Faquaman","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tech4242%2Faquaman/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tech4242%2Faquaman/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tech4242%2Faquaman/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tech4242","download_url":"https://codeload.github.com/tech4242/aquaman/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tech4242%2Faquaman/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30056056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T18:21:05.932Z","status":"ssl_error","status_checked_at":"2026-03-03T18:20:59.341Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-08T13:16:02.004Z","updated_at":"2026-04-27T09:02:32.892Z","avatar_url":"https://github.com/tech4242.png","language":"TypeScript","funding_links":[],"categories":["Security","Security \u0026 Hardening"],"sub_categories":["Security Tools","Security Audit Tools"],"readme":"# 🔱🦞 Aquaman\n\n[![CI](https://github.com/tech4242/aquaman/actions/workflows/ci.yml/badge.svg)](https://github.com/tech4242/aquaman/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/tech4242/aquaman/branch/main/graph/badge.svg)](https://codecov.io/gh/tech4242/aquaman)\n[![npm version](https://img.shields.io/npm/v/aquaman-proxy?label=aquaman-proxy)](https://www.npmjs.com/package/aquaman-proxy)\n[![npm downloads](https://img.shields.io/npm/dt/aquaman-proxy)](https://www.npmjs.com/package/aquaman-proxy)\n[![Security: process isolation](https://img.shields.io/badge/security-process%20isolation-critical)](https://github.com/tech4242/aquaman#security-model)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.3-3178C6?logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\nAPI key protection for OpenClaw — credentials stay in your vault, never in the agent's memory. 🔱🦞\n\nYou 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.\n\nAquaman fixes this with three layers of defense:\n\n1. **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.\n2. **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.\n3. **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.\n\nNo SDK changes required. The proxy is transparent — your agent talks to `aquaman.local`, the proxy injects auth and forwards to the real API.\n\n## Quick Start\n\n```bash\nopenclaw plugins install aquaman-plugin   # 1. install plugin + proxy\nopenclaw aquaman setup                    # 2. store your API keys\nopenclaw                                  # 3. done — proxy starts automatically\n```\n\nTroubleshooting: `openclaw aquaman doctor`\n\n\u003e **Using npm?** `npm install -g aquaman-proxy \u0026\u0026 aquaman setup` does\n\u003e the same thing — installs the proxy CLI, stores your keys, and installs\n\u003e the plugin. Use this if you prefer managing packages with npm.\n\n### Docker\n\nSingle-image deployment — same UDS architecture, containerized.\n\n```bash\ngit clone https://github.com/tech4242/aquaman.git \u0026\u0026 cd aquaman\ncp docker/.env.example docker/.env\n# Edit docker/.env — pick a backend and set credentials\nnpm run docker:build \u0026\u0026 npm run docker:run\n```\n\n## How It Works\n\n```\nAgent / OpenClaw Gateway              Aquaman Proxy\n┌──────────────────────┐              ┌──────────────────────┐\n│                      │              │                      │\n│  ANTHROPIC_BASE_URL  │══ Unix ════\u003e │  Keychain / 1Pass /  │\n│  = aquaman.local     │   Domain     │  Vault / Encrypted   │\n│                      │\u003c═ Socket ═══ │                      │\n│  fetch() interceptor │══ (UDS) ══=\u003e │  + Policy enforced   │\n│  redirects channel   │              │  + Auth injected:    │\n│  API traffic         │              │    header / url-path │\n│                      │              │    basic / oauth     │\n│                      │              │                      │\n│  No credentials.     │  ~/.aquaman/ │                      │\n│  No open ports.      │  proxy.sock  │                      │\n│  Nothing to steal.   │  (chmod 600) │                      │\n└──────────────────────┘              └──┬──────────┬────────┘\n                                         │          │\n                                         │          ▼\n                                         │  ~/.aquaman/audit/\n                                         │  (hash-chained log)\n                                         ▼\n                               api.anthropic.com\n                               api.telegram.org\n                               slack.com/api  ...\n```\n\n1. **Store** — Credentials live in a vault backend (Keychain, 1Password, Vault, Bitwarden, encrypted file, KeePassXC, systemd-creds)\n2. **Policy** — Proxy checks method + path rules *before* touching credentials. Denied requests get a 403, never real auth headers.\n3. **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).\n4. **Audit** — Every credential use is logged with SHA-256 hash chains.\n\nThe agent only sees a sentinel hostname (`aquaman.local`). It never sees a key, and no port is open for other processes to probe.\n\n## Security Model\n\n| Layer | What it does | What it stops |\n|-------|-------------|---------------|\n| **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 |\n| **Service allowlisting** | `proxiedServices` controls which APIs the agent can reach | Agent can't talk to services you didn't authorize |\n| **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 |\n| **Audit trail** | SHA-256 hash-chained logs of every credential use | Post-incident forensics, tamper detection, compliance evidence |\n\n## Request Policies\n\nOAuth 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.\n\n```yaml\n# ~/.aquaman/config.yaml\npolicy:\n  anthropic:\n    defaultAction: allow\n    rules:\n      - method: \"*\"\n        path: \"/v1/organizations/**\"\n        action: deny          # block admin/billing API\n  openai:\n    defaultAction: allow\n    rules:\n      - method: \"*\"\n        path: \"/v1/organization/**\"\n        action: deny          # block admin API\n      - method: DELETE\n        path: \"/v1/**\"\n        action: deny          # no deletions\n  slack:\n    defaultAction: allow\n    rules:\n      - method: \"*\"\n        path: \"/admin.*\"\n        action: deny          # block Slack admin methods\n  gmail:\n    defaultAction: allow\n    rules:\n      - method: POST\n        path: \"/v1/users/*/messages/send\"\n        action: deny          # drafts ok, sending blocked\n```\n\n- **No policy = allow all** (backward compatible)\n- **First match wins** — rules evaluated top-to-bottom, unmatched requests fall through to `defaultAction`\n- **Denied before auth** — blocked requests never get real credentials\n- **Path globs:** `*` matches within a segment, `**` matches zero or more segments\n- **`aquaman setup`** applies safe defaults (blocks admin/billing endpoints for stored services)\n- **`aquaman policy list`** shows all configured rules; **`aquaman policy test \u003csvc\u003e \u003cmethod\u003e \u003cpath\u003e`** dry-runs a request\n- **`aquaman doctor`** validates your policy config and warns about typos\n\n## Credential Backends\n\n| Backend | Best For | Setup |\n|---------|----------|-------|\n| `keychain` | Local dev on macOS (default) | Works out of the box |\n| `encrypted-file` | Linux, WSL2, CI/CD | AES-256-GCM, password-protected |\n| `keepassxc` | Existing KeePass users | Set `AQUAMAN_KEEPASS_PASSWORD` or key file |\n| `1password` | Team credential sharing | `brew install 1password-cli \u0026\u0026 op signin` |\n| `vault` | Enterprise secrets management | Set `VAULT_ADDR` + `VAULT_TOKEN` |\n| `systemd-creds` | Linux with systemd ≥ 256 | TPM2-backed, no root required |\n| `bitwarden` | Bitwarden users | `bw login \u0026\u0026 export BW_SESSION=$(bw unlock --raw)` |\n\n**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.\n\n## Security Audit\n\n`openclaw security audit --deep` reports two expected findings:\n\n- **`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.\n- **`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.\n\n`aquaman setup` adds the plugin to `plugins.allow` automatically so OpenClaw knows you trust it.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftech4242%2Faquaman","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftech4242%2Faquaman","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftech4242%2Faquaman/lists"}