Security
Security is layered. Bypassing one layer trips another. Seven independent controls:
- Permission profiles — which tools the agent can even reach for
- Access control — which users can talk to the agent at all
- Credential proxy — API keys never touch the SDK directly
- SSRF + DNS-rebinding guards — outbound HTTP is IP-checked and pinned
- Prompt-injection sanitizer — LLM input goes through NFKC + pattern redaction
- Input validation — every tool argument is validated before dispatch
- Sandboxed code execution — user- and model-authored code runs only in the QuickJS WASM sandbox, read-and-transform only
Permission profiles
Section titled “Permission profiles”Set via codebuddy.permissionScope.defaultProfile. Profiles filter the tool list at construction:
| Profile | Behavior |
|---|---|
restricted | Read-only. No terminal, no writes, no browser. Read tools + search + think. |
standard | Read/write. Terminal requires modal approval outside a small safe-command list. Default. |
trusted | Same tools; auto-approves the safe-command list. Catastrophic patterns still deny. |
Catastrophic commands are denied in every profile, including trusted — destructive filesystem wipes, disk formatting/overwrite, fork bombs, pipe-to-shell remote execution, and privilege-escalation patterns. This denial cannot be re-enabled by configuration.
Custom per-workspace additions in .codebuddy/permissions.json:
{ "profile": "standard", "commandDenyPatterns": ["docker rm", "kubectl delete namespace"], "toolAllowlist": [], "toolBlocklist": ["browser"]}Patterns are bounds-checked and compiled at load time.
Access control (team mode)
Section titled “Access control (team mode)”AccessControlService gates who can invoke the agent. Modes (codebuddy.accessControl.defaultMode): open (default — no restrictions) / allow (only listed users) / deny (block listed users). Overridden by .codebuddy/access.json if present.
Identity resolution: GitHub auth first, git config user.email fallback, cached briefly. Every access decision is written to an audit log.
Credential proxy
Section titled “Credential proxy”Enable via codebuddy.credentialProxy.enabled. When on:
- Keys stay in the OS keychain; a localhost-only HTTP proxy injects them into upstream requests. Keys never appear in logs, memory, or agent context.
- Per-provider rate limiting and short-lived session tokens.
- Request size and timeout limits, with an audit log.
See Credential Proxy for the full setup.
SSRF + DNS rebinding
Section titled “SSRF + DNS rebinding”Every outbound HTTP request the extension makes (MCP SSE, telemetry/OTLP export, browser navigation) is validated before it connects:
- Protocol allowlist (
http:/https:only). - Private, loopback, link-local, CGNAT, and cloud-metadata address ranges are blocked — including encoded/obfuscated forms of those addresses.
- URL length bounds.
Outbound telemetry additionally pins the resolved IP to the socket connection to defeat DNS-rebinding, and browser navigation has a post-navigation rebinding backstop.
External security config
Section titled “External security config”.codebuddy/security.json at workspace root. Loaded at activation, reloads on change.
{ "allowedPaths": [ { "path": "/shared/configs", "allowReadWrite": false, "description": "Read-only shared configs" } ], "commandDenyPatterns": ["docker\\s+system\\s+prune", "kubectl\\s+delete\\s+namespace"], "networkAllowPatterns": ["^https://api\\.example\\.com"], "networkDenyPatterns": ["^https?://169\\.254\\.169\\.254"], "blockedPathPatterns": [".credentials", "secrets"]}Always blocked (no config needed): access to well-known secret and credential locations — SSH/GPG keys, cloud-provider credential directories, dotenv (.env) files, and other recognized secret files — is refused regardless of settings. Outbound requests to cloud-metadata endpoints are likewise always blocked.
Invalid user patterns are skipped, and the number and size of patterns are bounded.
Prompt-injection defense
Section titled “Prompt-injection defense”Untrusted text bound for the LLM is normalized (NFKC, to defeat homoglyph tricks), scanned for known instruction-override and role-hijack patterns which are redacted, and length-capped. MCP tool output is additionally wrapped in an untrusted <mcp_response … trust="untrusted"> envelope so the model treats it as data, not instructions.
Input validation
Section titled “Input validation”Every tool argument is validated before dispatch — file paths resolve through validatePathWithinWorkspace() (symlink-resolving, workspace-scoped), URLs go through the outbound-URL guards, and other inputs are bounds- and character-checked.
Sandboxed code execution
Section titled “Sandboxed code execution”Any code CodeBuddy didn’t ship — user/team scripts and model-authored REPL code — runs only inside the QuickJS WASM sandbox, never in the extension host. The sandbox is read-and-transform only: it cannot write files, spawn shells, or reach the network on its own; those paths stay behind the normal modal-approval tool flow. When the code interpreter can dispatch subagents, each subagent’s write reach is fenced. Details in Sandbox and Subagents.
Data privacy
Section titled “Data privacy”- Local by default. All extension data (memory, checkpoints, logs, skills, audit) stays on disk under
.codebuddy/. Never uploaded. - Direct provider calls. Requests go straight to your provider (or to the credential proxy on localhost). No CodeBuddy-controlled intermediary.
- Telemetry opt-in. No data leaves your machine unless you explicitly configure Langfuse or another OTLP endpoint.
- Filesystem permissions.
.codebuddy/is0700, DB files are0600, atomic write-temp-rename to prevent inspection during writes. At-rest encryption (SQLCipher) is on the roadmap. - API key handling. Keys live in the OS keychain via
SecretStorageService, never insettings.json. Cache is zeroed with null bytes ondispose()so heap snapshots can’t recover plaintext. - Connector credentials in terminals. When a connector’s credentials are injected into a spawned command’s environment, they layer over the process environment additively, invalid names are dropped, and core system variables are never overwritten — so a key authenticates a CLI without appearing in the command string. See Connectors.
When to reset
Section titled “When to reset”| Situation | Command |
|---|---|
| MCP server config changed | CodeBuddy: Reset MCP Server Approvals |
| Skill installer prompted for the wrong file | CodeBuddy: Reset Skill Installer State |
| Detected identity wrong (team mode) | CodeBuddy: Reset Access Cache |
| Doubt about any of the above | CodeBuddy: Run Doctor |
Related
Section titled “Related”- Access control — allowlist/denylist team mode
- Credential proxy — full proxy setup
- Permission scoping — permission-scope JSON
- Telemetry — Langfuse + OTLP wiring (with DNS pinning)