{"id":43661666,"url":"https://github.com/wardgate/wardgate","last_synced_at":"2026-02-10T03:00:51.092Z","repository":{"id":336214509,"uuid":"1148664539","full_name":"wardgate/wardgate","owner":"wardgate","description":"Give AI agents API access without giving them your credentials. Reduce the blast radius!","archived":false,"fork":false,"pushed_at":"2026-02-06T14:12:57.000Z","size":1293,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-07T08:57:35.551Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://wardgate.github.io/wardgate/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wardgate.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"avoutic","ko_fi":"avoutic","buy_me_a_coffee":"avoutic"}},"created_at":"2026-02-03T08:16:34.000Z","updated_at":"2026-02-06T12:57:32.000Z","dependencies_parsed_at":"2026-02-08T01:00:41.566Z","dependency_job_id":null,"html_url":"https://github.com/wardgate/wardgate","commit_stats":null,"previous_names":["wardgate/wardgate"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/wardgate/wardgate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardgate%2Fwardgate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardgate%2Fwardgate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardgate%2Fwardgate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardgate%2Fwardgate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wardgate","download_url":"https://codeload.github.com/wardgate/wardgate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardgate%2Fwardgate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29215849,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T00:10:47.190Z","status":"ssl_error","status_checked_at":"2026-02-08T00:10:43.589Z","response_time":63,"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-04T22:03:06.241Z","updated_at":"2026-02-08T01:00:49.257Z","avatar_url":"https://github.com/wardgate.png","language":"Go","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/wardgate-banner.png\" alt=\"Wardgate Banner\" width=\"800\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/wardgate/wardgate/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/wardgate/wardgate/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://goreportcard.com/report/github.com/wardgate/wardgate\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/wardgate/wardgate\" alt=\"Go Report Card\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/go-1.22-blue\" alt=\"Go Version\"\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-AGPL--3.0-green\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Wardgate - AI Agent Security Gateway\n\n*Wardgate* is a security proxy that sits between AI agents and external services, providing credential isolation, access control, and audit logging.\n\nGive your AI agents API access - without giving them your credentials.\n\n## The Problem\n\nAI agents are powerful. They can manage your calendar, check your email, update your tasks, and automate your life. But to do that, they need access to your accounts.\n\nThey are also like a whizzkid-teenager. They know a lot, but they have a mind of their own. They are gullible (to prompt injections). And just like teens, they don't really think. So thinking about consequences is definitely above their pay-grade!\n\nContainerization is a great way to isolate your agents. But it's not a silver bullet. You still need to be careful about what you put in your containers. They still get your credentials via environment variables or another way. Otherwise they can't help you.\n\nAnd projects like [OpenClaw](https://github.com/openclaw/openclaw) have all these access control features built in. But unless you gutted capabilities beyond being useful, you have to trust the agent, the application or all the thousands of commits / pull requests that it does not change its own permissions or capabilities and actually does what you want it to do.\n\nDo you really want to give your API keys or e-mail access to that? Give an AI agent direct access to your inbox, 2-factor authentication codes, or other sensitive data? Trust that it won't exfiltrate your data or go rogue, after reading some clever prompt injection?\n\n*The risk is real:*\n- Credentials in prompts can leak through model outputs, logs, or attacks\n- Prompt injection can make agents do things you didn't intend\n- A compromised agent has the same access you gave it - to everything\n\n## The Solution\n\nWardgate sits between your agents and the outside world. Agents talk to Wardgate. Wardgate talks to APIs. Your credentials never leave Wardgate.\n\n\n```mermaid\nflowchart LR\n    Agent[AI Agent - no creds] --\u003e|HTTP or HTTPS| Wardgate[Wardgate - has creds]\n    Wardgate --\u003e|API| Service[External Service]\n```\n\n*What Wardgate gives you:*\n\n- *Credential Isolation* - Agents never see your API keys, OAuth tokens, or passwords\n- *Access Control* - Define what each agent can do: read-only calendar, no email deletion, ask before sending\n- *Protocol Adapters* - HTTP/REST passthrough, IMAP and SMTP with REST wrappers\n- *Audit Logging* - Every request logged (metadata only, not content) - know exactly what your agents did\n- *Approval Workflows* - Require human approval for sensitive operations (send email, delete data)\n- *Anomaly Detection* - Alert on unusual patterns (suddenly fetching 100 emails, or a specific folder, or things from the past?)\n\n## Who Is This For?\n\nYou want to use AI agents like [OpenClaw](https://github.com/openclaw/openclaw), [AutoGPT](https://github.com/Significant-Gravitas/AutoGPT), or custom LLM tooling - but you're not comfortable giving them direct access to your life. I'm not sure I'll ever be comfortable with AI agents that have built-in access control.\n\nWardgate lets you get the benefits of AI automation while keeping a security boundary between the agent and your accounts.\n\n*Use cases:*\n- Personal AI assistant with calendar, email, and task access\n- Development agents with limited API access\n- Multi-agent setups where you want isolation between agents\n- Anywhere you'd otherwise paste credentials into an agent's config\n\n## Quick Example\n\nSo if you want your agent to be able to read your Todoist tasks, you can configure Wardgate to allow it to do so.\n\nInstead of giving your agent a Todoist API key:\n\n# Agent config (dangerous)\n```yaml\ntodoist_api_key: \"abc123...\"\n```\n\nYou configure Wardgate using a **[preset](docs/presets.md)** (easiest):\n\n```yaml\n# Wardgate config - using preset (recommended)\nendpoints:\n  todoist:\n    preset: todoist\n    auth:\n      credential_env: WARDGATE_CRED_TODOIST_API_KEY\n    capabilities:\n      read_data: allow       # Read tasks, projects\n      create_tasks: allow    # Create new tasks\n      close_tasks: allow     # Mark tasks complete\n      delete_tasks: deny     # Never delete\n```\n\nOr with full manual configuration:\n\n```yaml\n# Wardgate config - manual (for custom APIs)\nendpoints:\n  todoist-api:\n    upstream: https://api.todoist.com/rest/v2\n    auth:\n      type: bearer\n      credential_env: WARDGATE_CRED_TODOIST_API_KEY\n    rules:\n      - match: { method: GET }\n        action: allow\n      - match: { method: DELETE }\n        action: deny\n      - match: { method: \"*\" }\n        action: ask  # Human approval required\n```\n\nYour agent calls https://wardgate.internal/todoist/tasks - Wardgate injects the real credentials and enforces your rules.\n\n## Quick Start\n\n```bash\n# Copy and edit .env file\ncp .env.example .env\n# Edit .env with your credentials\n\n# Copy and edit config.yaml file\ncp config.yaml.example config.yaml\n# Edit config.yaml with your configuration\n\n# Run (automatically loads .env)\n./wardgate -config config.yaml\n\n# Or specify a different env file\n./wardgate -config config.yaml -env /path/to/.env\n```\n\n## Usage\n\nAgents make requests to the gateway instead of directly to APIs:\n\n```bash\n# Instead of: curl -H \"Authorization: Bearer $TODOIST_KEY\" https://api.todoist.com/rest/v2/tasks\n# Use:\ncurl -H \"Authorization: Bearer $AGENT_KEY\" http://localhost:8080/todoist-api/tasks\n```\n\nThe gateway:\n1. Validates the agent's key\n2. Evaluates policy rules (allow/deny)\n3. Injects the real API credential\n4. Forwards the request to the upstream\n5. Logs the request/response\n6. Returns the response to the agent\n\n## Documentation\n\n- [Security Architecture](docs/architecture.md) - How Wardgate protects your credentials\n- [Policy System](docs/policies.md) - Writing and configuring rules\n- [Presets Reference](docs/presets.md) - Built-in presets and capabilities\n- [Configuration Reference](docs/config.md) - All configuration options\n- [Deployment Guide](docs/deployment.md) - Docker, Caddy, and production setup\n\n## Configuration\n\nSee `config.yaml.example` for a quick example, or [Configuration Reference](docs/config.md) for full documentation.\n\nKey sections:\n\n- `server.listen` - Address to listen on (default `:8080`)\n- `agents` - List of agents and their key env vars\n- `endpoints` - Map of endpoint name to upstream config and rules\n- `notify` - Notification settings for approval workflows\n\n## Presets (Easy Setup)\n\nWardgate includes presets for popular APIs in the `presets/` directory. Just specify the preset name and your credentials:\n\n```yaml\npresets_dir: ./presets\n\nendpoints:\n  github:\n    preset: github\n    auth:\n      credential_env: WARDGATE_CRED_GITHUB_TOKEN\n    capabilities:\n      read_data: allow\n      create_issues: allow\n      create_comments: allow\n      create_pull_requests: ask  # Require approval\n```\n\n### Available Presets\n\n| Preset | Service | Capabilities |\n|--------|---------|--------------|\n| `cloudflare` | Cloudflare | read_data, manage_dns, purge_cache, manage_page_rules |\n| `github` | GitHub | read_data, create_issues, create_comments, manage_labels, create_pull_requests, manage_releases |\n| `google-calendar` | Google Calendar | read_data, create_events, update_events, delete_events |\n| `imap` | IMAP Email | list_folders, read_inbox, read_all_folders, mark_read, move_messages |\n| `pingping` | PingPing.io | read_data, create_monitors, update_monitors, delete_monitors, manage_checks |\n| `plausible` | Plausible | read_data, send_events |\n| `postmark` | Postmark | read_data, send_email, send_batch, send_templates |\n| `sentry` | Sentry | read_data, resolve_issues, manage_projects |\n| `smtp` | SMTP Email | send_email |\n| `todoist` | Todoist | read_data, create_tasks, close_tasks, update_tasks, delete_tasks, manage_projects |\n\nEach capability can be set to `allow`, `deny`, or `ask` (require human approval).\n\n### Custom Presets\n\nThe easiest way to define new presets is to add a new YAML file in the `presets/` directory.\n\nSee [Configuration Reference](docs/config.md#custom-presets-user-defined) for details.\n\n```yaml\n# presets/my-api.yaml\nname: my-api\ndescription: \"My Custom API\"\nupstream: https://api.example.com\nauth_type: bearer\n```\n\nBut you can also define your own presets in the config file:\n\n```yaml\n# In config.yaml\ncustom_presets:\n  my-api:\n    description: \"My Custom API\"\n    upstream: https://api.example.com\n    auth_type: bearer\n    capabilities:\n      - name: read_data\n        description: \"Read resources\"\n        rules:\n          - match: { method: GET }\n      - name: write_data\n        description: \"Write resources\"\n        rules:\n          - match: { method: POST }\n\nendpoints:\n  my-api:\n    preset: my-api\n    auth:\n      credential_env: MY_API_KEY\n    capabilities:\n      read_data: allow\n      write_data: ask\n```\n\n## Policy Rules\n\nRules are evaluated in order. First match wins.\n\n```yaml\nrules:\n  - match: { method: GET }\n    action: allow\n  - match: { method: POST, path: \"/tasks\" }\n    action: allow\n  - match: { method: POST, path: \"/tasks/*/close\" }  # Glob pattern\n    action: allow\n  - match: { method: \"*\" }\n    action: deny\n    message: \"Not permitted\"\n```\n\n### Supported Actions\n\n| Action | Description |\n|--------|-------------|\n| `allow` | Pass through immediately |\n| `deny` | Block with error message |\n| `ask` | Require human approval (blocks until approved/denied/timeout) |\n\n### Path Patterns\n\n- Exact match: `/tasks` matches only `/tasks`\n- Wildcard suffix: `/tasks*` matches `/tasks`, `/tasks/123`, `/tasks/123/comments`\n- Single segment: `/tasks/*/close` matches `/tasks/123/close` but not `/tasks/a/b/close`\n- Multi-segment: `/api/**/status` matches `/api/status`, `/api/v1/status`, `/api/v1/tasks/status`\n\n### Rate Limiting\n\nLimit requests per agent per time window:\n\n```yaml\nrules:\n  - match: { method: GET }\n    action: allow\n    rate_limit:\n      max: 100        # Maximum requests\n      window: \"1m\"    # Per minute (supports: s, m, h)\n```\n\n### Time-Based Rules\n\nRestrict when rules apply:\n\n```yaml\nrules:\n  - match: { method: POST }\n    action: allow\n    time_range:\n      hours: [\"09:00-17:00\"]  # Only during business hours\n      days: [\"mon\", \"tue\", \"wed\", \"thu\", \"fri\"]  # Weekdays only\n```\n\n### Ask Workflow (Human Approval)\n\nFor sensitive operations, require human approval:\n\n```yaml\n# In endpoint rules\nrules:\n  - match: { method: DELETE }\n    action: ask  # Requires human approval\n\n# Configure notifications\nnotify:\n  timeout: \"5m\"  # How long to wait for approval\n  slack:\n    webhook_url: \"https://hooks.slack.com/services/...\"\n  # Or use a generic webhook\n  webhook:\n    url: \"https://your-webhook.example.com/notify\"\n    headers:\n      Authorization: \"Bearer token\"\n```\n\nWhen an `ask` rule matches:\n1. Agent request blocks\n2. Notification sent to Slack/webhook with link to dashboard\n3. Human reviews request in Web UI and approves or denies\n4. Request proceeds or returns 403\n\n## Endpoint Discovery API\n\nAgents can discover available endpoints via `GET /endpoints`:\n\n```bash\ncurl -H \"Authorization: Bearer $AGENT_KEY\" http://localhost:8080/endpoints\n```\n\nResponse:\n```json\n{\n  \"endpoints\": [\n    {\"name\": \"todoist\", \"description\": \"Todoist API (Personal)\"},\n    {\"name\": \"imap-personal\", \"description\": \"IMAP (personal@example.com)\"},\n    {\"name\": \"smtp-personal\", \"description\": \"SMTP (personal@example.com)\"}\n  ]\n}\n```\n\nThe description comes from (in priority order):\n1. `description` field in endpoint config\n2. Preset description (if using a preset)\n3. Adapter name (IMAP, SMTP, HTTP)\n\nThe description is meant for the agent to understand which API it is supposed to assume is behind it.\n\n## Admin UI \u0026 CLI\n\nWardgate includes a web dashboard and CLI for managing approval requests.\n\n### Enabling the Admin UI\n\nAdd an admin key to your configuration:\n\n```yaml\nserver:\n  listen: \":8080\"\n  admin_key_env: WARDGATE_ADMIN_KEY\n```\n\nSet the key in your environment:\n\n```bash\nexport WARDGATE_ADMIN_KEY=your-secret-admin-key\n```\n\nAccess the dashboard at `http://localhost:8080/ui/`. Enter your admin key to login.\n\n### CLI Usage\n\nThe same binary provides CLI commands for managing approvals:\n\n```bash\n# Set environment variables\nexport WARDGATE_URL=http://localhost:8080\nexport WARDGATE_ADMIN_KEY=your-secret-admin-key\n\n# List pending approvals\nwardgate approvals list\n\n# View details of an approval (including email content for SMTP)\nwardgate approvals view \u003cid\u003e\n\n# Approve or deny\nwardgate approvals approve \u003cid\u003e\nwardgate approvals deny \u003cid\u003e\n\n# View history of recent decisions\nwardgate approvals history\n\n# Monitor mode - live updates with interactive approve/deny\nwardgate approvals monitor\n```\n\nThe Web UI and CLI show full request content for email approvals, allowing you to review the recipient, subject, and body before approving.\n\n### Logging Dashboard\n\nThe Web UI includes a **Logs** tab that shows recent request activity. Logs are stored in memory (ring buffer) and can be filtered by:\n\n- Endpoint\n- Agent\n- Decision (allow/deny/rate_limited/error)\n- HTTP method\n\nConfigure logging in your `config.yaml`:\n\n```yaml\nserver:\n  logging:\n    max_entries: 1000      # Max entries to keep (default: 1000)\n    store_bodies: false    # Store request bodies (default: false)\n```\n\n**Note:** Logs are stored in memory only and are lost on restart. For persistent logging, configure your log aggregator to consume stdout.\n\n## IMAP Support\n\nWardgate can proxy IMAP servers via a REST API, letting your agents read email without direct IMAP access:\n\n```yaml\nendpoints:\n  imap-personal:\n    adapter: imap\n    upstream: imaps://imap.gmail.com:993\n    auth:\n      type: plain\n      credential_env: IMAP_CREDS  # format: username:password\n    rules:\n      - match: { path: \"/inbox*\" }\n        action: allow\n      - match: { path: \"/*\" }\n        action: deny\n```\n\nREST endpoints exposed:\n- `GET /folders` - List mailbox folders\n- `GET /folders/{folder}?limit=N\u0026since=DATE` - Fetch messages from folder\n- `GET /folders/{folder}/messages/{uid}` - Get full message by UID\n- `POST /folders/{folder}/messages/{uid}/mark-read` - Mark message as read\n- `POST /folders/{folder}/messages/{uid}/move?to=X` - Move message to folder\n\n## SMTP Support\n\nWardgate can send emails via SMTP through a REST API, with approval workflows and content filtering:\n\n```yaml\nendpoints:\n  smtp-personal:\n    adapter: smtp\n    upstream: smtps://smtp.gmail.com:465  # Or smtp://...587 for STARTTLS\n    auth:\n      type: plain\n      credential_env: SMTP_CREDS  # format: username:password\n    smtp:\n      tls: true\n      from: \"your-email@gmail.com\"\n      known_recipients:\n        - \"@company.com\"  # Known domain (no approval needed)\n      ask_new_recipients: true  # Ask before sending to unknown recipients\n      blocked_keywords:\n        - \"password\"\n        - \"secret\"\n    rules:\n      - match: { path: \"/send\" }\n        action: allow\n```\n\nREST endpoint exposed:\n- `POST /send` - Send an email\n\n**Send request body:**\n```json\n{\n  \"to\": [\"recipient@example.com\"],\n  \"cc\": [\"cc@example.com\"],\n  \"bcc\": [\"bcc@example.com\"],\n  \"reply_to\": \"reply@example.com\",\n  \"subject\": \"Email subject\",\n  \"body\": \"Plain text body\",\n  \"html_body\": \"\u003chtml\u003e...\u003c/html\u003e\"\n}\n```\n\n**SMTP Features:**\n- *Content filtering* - Block emails containing specific keywords\n- *Recipient allowlisting* - Only allow sending to approved recipients\n- *Ask for new recipients* - Require human approval when sending to unknown recipients\n- *HTML and plain text* - Support for multipart emails\n\n## Building\n\n```bash\ngo build -o wardgate ./cmd/wardgate\n```\n\n## Docker Deployment\n\n```bash\n# Create config directory and copy files\nmkdir -p config\ncp config.yaml.example config/config.yaml\ncp .env.example config/.env\n\n# Edit config/config.yaml and config/.env with your settings\n\n# Run with Docker Compose (includes Caddy for HTTPS)\ndocker compose up -d\n\n# Or for production with a custom domain\nDOMAIN=wardgate.example.com docker compose up -d\n```\n\nSee [Deployment Guide](docs/deployment.md) for more options.\n\n## Testing\n\n```bash\ngo test ./...\n```","funding_links":["https://github.com/sponsors/avoutic","https://ko-fi.com/avoutic","https://buymeacoffee.com/avoutic"],"categories":["Secrets Management \u0026 Isolation"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwardgate%2Fwardgate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwardgate%2Fwardgate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwardgate%2Fwardgate/lists"}