initializdocs
DeveloperForge runtimeSecurity

Security Overview

Forge's layered security architecture from network posture to guardrails.

Forge is designed with security as a foundational principle, not an afterthought. This document describes the complete security architecture — from network-level egress controls to encrypted secrets, build signing, execution sandboxing, and runtime guardrails.

Security Model

Forge's security is organized in layers, each addressing a different threat surface:

┌──────────────────────────────────────────────────────────────┐
│                    Skill Guardrails                           │
│    (deny commands/output/prompts/responses per skill)         │
├──────────────────────────────────────────────────────────────┤
│                    Global Guardrails                          │
│              (content filtering, PII, jailbreak)             │
├──────────────────────────────────────────────────────────────┤
│                  Authentication (a2a)                         │
│  (Pluggable provider chain: OIDC, AWS Sigv4, GCP IAP,         │
│   Azure AD, http_verifier, static_token loopback)             │
├──────────────────────────────────────────────────────────────┤
│                    Egress Enforcement                        │
│  (EgressEnforcer + EgressProxy + SafeDialer + NetworkPolicy) │
├──────────────────────────────────────────────────────────────┤
│                  Execution Sandboxing                        │
│  (env isolation, binary allowlists, arg validation,          │
│   file:// blocking, shell denylist)                          │
├──────────────────────────────────────────────────────────────┤
│                   Secrets Management                         │
│         (AES-256-GCM, Argon2id, per-agent isolation)         │
├──────────────────────────────────────────────────────────────┤
│                   Build Integrity                            │
│           (Ed25519 signing, SHA-256 checksums)               │
├──────────────────────────────────────────────────────────────┤
│                   Network Posture                            │
│       (outbound-only connections, no public listeners)       │
└──────────────────────────────────────────────────────────────┘

Table of Contents

Authentication

The /tasks HTTP endpoint requires every caller to authenticate through a pluggable provider chain configured in forge.yaml. Forge ships six provider types and holds no IdP secrets — every provider verifies against a third party (STS, GCP JWKS, AAD JWKS, your custom verifier) or a local file.

ProviderUse caseWire format
static_tokenLoopback (channel adapters, local Web UI dashboard)Bearer literal
oidcGeneric OIDC IdP (Keycloak, Auth0, Okta, Google)Bearer JWT
aws_sigv4AWS IAM identities (Lambda, EC2, EKS, SSO users)Bearer forge-aws-v1.<base64>
gcp_iapBehind GCP HTTPS LB + IAPX-Goog-Iap-Jwt-Assertion: <jwt>
azure_adMicrosoft Entra IDBearer JWT
http_verifierCustom /verify endpoint you operateOpaque token

The chain is first-match-wins with fail-closed on rejection — a malformed token of type A doesn't fall through to type B. The local Web UI dashboard and channel adapters use an auto-prepended static_token (the runtime.token file under .forge/) so they keep working regardless of how external auth is configured.

See Authentication Providers for the complete reference, including per-provider security model, client-side recipes, and mesh (agent-to-agent) patterns.


Network Posture

Forge agents are designed to never expose inbound listeners to the public internet:

  • No public tunnels — Forge does not create ngrok, Cloudflare, or similar tunnels
  • No inbound webhooks — Channels use outbound-only connections
    • Slack: Socket Mode (outbound WebSocket via apps.connections.open)
    • Telegram: Long-polling via getUpdates; webhook mode binds to 127.0.0.1 only
  • Local-only HTTP server — The A2A dev server binds to localhost by default
  • Rate limiting — Per-IP token bucket rate limiting on the A2A server (read: 60 req/min, write: 10 req/min) with automatic 429 responses and Retry-After headers
  • Request size limits — A2A server enforces MaxHeaderBytes (1 MiB) and request body limits (2 MiB via http.MaxBytesReader) to prevent denial-of-service via oversized payloads
  • CORS restriction — The A2A server restricts Access-Control-Allow-Origin to localhost by default; configurable via --cors-origins flag, FORGE_CORS_ORIGINS env var, or cors_origins in forge.yaml
  • Security response headers — All A2A responses include X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer, X-Frame-Options: DENY, and Content-Security-Policy: default-src 'none'
  • No hidden listeners — Every network binding is explicit and logged

This means a running Forge agent has zero inbound attack surface by default.


Egress Enforcement

Forge restricts outbound network access at multiple levels:

1. IP Validation

All egress paths reject non-standard IP formats (octal, hex, packed decimal, leading zeros) that could bypass allowlist checks. IPv6 transition addresses (NAT64, 6to4, Teredo) embedding private IPv4 addresses are also blocked.

2. In-Process Enforcer

The EgressEnforcer is a Go http.RoundTripper backed by a SafeTransport that validates resolved IPs post-DNS. Every outbound HTTP request from in-process tools (http_request, web_search, LLM API calls) is checked against IP validation, domain allowlist, and post-resolution CIDR blocking.

3. Subprocess Proxy

Skill scripts and cli_execute subprocesses bypass Go-level enforcement. A local EgressProxy on 127.0.0.1:<random-port> validates domains and resolved IPs for subprocess HTTP traffic via HTTP_PROXY/HTTPS_PROXY env var injection.

4. Redirect Credential Stripping

HTTP clients used by http_request and webhook_call tools strip Authorization, Cookie, and Proxy-Authorization headers when a redirect crosses origin boundaries (different scheme, host, or port).

5. Kubernetes NetworkPolicy

In containerized deployments, generated Kubernetes NetworkPolicy manifests enforce egress at the pod level, restricting traffic to allowed domains on ports 80/443.

Modes

ModeBehavior
deny-allAll non-localhost outbound traffic blocked
allowlistOnly explicitly allowed domains (exact + wildcard)
dev-openAll traffic allowed (development only)

Domain Resolution

Allowed domains are resolved from three sources:

  1. Explicit domains — Listed in forge.yaml under egress.allowed_domains
  2. Tool domains — Automatically inferred from registered tool names (e.g., web_searchapi.tavily.com)
  3. Capability bundles — Pre-defined domain sets for common services (e.g., slackslack.com, hooks.slack.com, api.slack.com)

Localhost (127.0.0.1, ::1, localhost) is always allowed in all modes.

For full details on egress enforcement, see Egress Security.


Execution Sandboxing

Forge agents execute external code through two sandboxed executors, both designed to minimize the attack surface of subprocess execution.

SkillCommandExecutor

Skill scripts run via SkillCommandExecutor (forge-cli/tools/exec.go):

ControlDetail
Environment isolationOnly PATH, HOME, and explicitly declared env vars are passed through
Egress proxy injectionHTTP_PROXY/HTTPS_PROXY env vars route subprocess HTTP through the egress proxy
OAuth token resolutionWhen OPENAI_API_KEY is set to the sentinel __oauth__, the executor resolves OAuth credentials and injects the access token and OPENAI_BASE_URL
Model passthroughThe configured LLM model name is injected as REVIEW_MODEL so skill scripts use the correct model
Configurable timeoutPer-skill timeout_hint in YAML frontmatter (default: 120s)
No shellRuns bash <script> <json-input>, not through a shell interpreter
Scoped env varsOnly env vars declared in the skill's requires.env section are passed

CLIExecuteTool

The cli_execute tool (forge-cli/tools/cli_execute.go) provides 13 security layers:

#LayerDetail
1Shell denylistShell interpreters (bash, sh, zsh, etc.) filtered at construction and blocked at execution
2Binary allowlistOnly pre-approved binaries can execute
3Binary resolutionBinaries are resolved to absolute paths via exec.LookPath at startup
4Argument validationRejects arguments containing $(, backticks, newlines, or file:// URLs
5File protocol blockingBlocks file:// URLs (case-insensitive) to prevent filesystem traversal
6Path confinementPath arguments inside $HOME but outside workDir are blocked
7TimeoutConfigurable per-command timeout (default: 120s)
8No shellUses exec.CommandContext directly — no shell expansion
9Working directorycmd.Dir set to workDir for relative path resolution
10Environment isolationOnly PATH, HOME, LANG, explicit passthrough vars, proxy vars, GH_CONFIG_DIR (auto-set only for gh), and KUBECONFIG/NO_PROXY (only for kubectl/helm — restores kubeconfig access and bypasses egress proxy for the K8s API server when HOME is overridden)
11Output limitsConfigurable max output size (default: 1MB) to prevent memory exhaustion
12Skill guardrailsSkill-declared deny_commands and deny_output patterns via hooks
13Custom tool entrypoint validationCustom tool entrypoints are validated against path traversal, symlink escape, absolute paths, and non-regular files

Configuration

tools:
  - name: cli_execute
    config:
      allowed_binaries: ["git", "curl", "jq", "python3"]
      env_passthrough: ["GITHUB_TOKEN"]
      timeout: 120
      max_output_bytes: 1048576

Secrets Management

Forge provides AES-256-GCM encrypted secret storage with Argon2id key derivation, per-agent isolation, and a three-tier resolution hierarchy (agent-local -> global -> environment). Secrets are managed via forge secret set|get|list|delete.

Cross-Category Secret Reuse Detection

At startup, the runtime detects when the same secret value is shared across different purpose categories (e.g., OPENAI_API_KEY and TELEGRAM_BOT_TOKEN having the same value). This prevents credential reuse mistakes that could escalate the impact of a single token compromise. Categories: llm, search, telegram, slack.

For full details, see Secrets Management.


Build Integrity

Forge supports Ed25519 signing and SHA-256 checksumming of build artifacts for supply chain integrity. At runtime, forge run can verify artifacts against trusted keys before execution.

For full details, see Build Signing & Verification.


Guardrails

The guardrail engine checks inbound and outbound messages against policy rules including content filtering, PII detection, and jailbreak protection. Guardrails run in enforce (blocking) or warn (logging) mode.

Skill Guardrails

Skills can declare domain-specific guardrails in their SKILL.md frontmatter. These guardrails operate at four hook points — blocking unauthorized commands (deny_commands), redacting sensitive output (deny_output), intercepting capability enumeration probes (deny_prompts), and replacing binary-enumerating LLM responses (deny_responses). Skill guardrails fire at runtime without requiring forge build.

For full details, see Content Guardrails.


Audit Logging

All runtime security events are emitted as structured NDJSON to stderr with correlation IDs for end-to-end tracing.

Event Types

EventDescription
session_startNew task session begins
session_endTask session completes (with final state)
tool_execTool execution start/end (with tool name)
egress_allowedOutbound request allowed (with domain, mode)
egress_blockedOutbound request blocked (with domain, mode)
llm_callLLM API call completed (with token count)
guardrail_checkGuardrail evaluation result

Example

{"ts":"2026-02-28T10:00:00Z","event":"session_start","correlation_id":"a1b2c3d4","task_id":"task-1"}
{"ts":"2026-02-28T10:00:01Z","event":"tool_exec","correlation_id":"a1b2c3d4","fields":{"tool":"tavily_research","phase":"start"}}
{"ts":"2026-02-28T10:00:01Z","event":"egress_allowed","correlation_id":"a1b2c3d4","fields":{"domain":"api.tavily.com","mode":"allowlist","source":"proxy"}}
{"ts":"2026-02-28T10:00:05Z","event":"tool_exec","correlation_id":"a1b2c3d4","fields":{"tool":"tavily_research","phase":"end"}}
{"ts":"2026-02-28T10:00:06Z","event":"session_end","correlation_id":"a1b2c3d4","fields":{"state":"completed"}}

The source field distinguishes in-process enforcer events from subprocess proxy events.

When the inbound A2A request carries orchestrator headers, events are additionally tagged with workflow_id / stage_id / step_id / invocation_caller. See Workflow Correlation IDs for the header contract and outbound propagation rules.


Container Security

Build-Time Artifacts

Every forge build generates container-ready security artifacts:

ArtifactPurpose
egress_allowlist.jsonMachine-readable domain allowlist
network-policy.yamlKubernetes NetworkPolicy restricting pod egress
DockerfileContainer image with minimal attack surface
checksums.jsonSHA-256 checksums + Ed25519 signature

Runtime Behavior in Containers

When Forge detects it's running inside a container (via KUBERNETES_SERVICE_HOST or /.dockerenv):

  • The local EgressProxy is not startedNetworkPolicy handles egress enforcement at the infrastructure level
  • All other security controls (guardrails, execution sandboxing, audit logging) remain active
  • Secrets must use the env provider (encrypted files can't be decrypted without a passphrase)

Production Build Checks

forge package --prod

Production builds enforce:

  • No dev-open egress mode
  • No dev-only tools (local_shell, local_file_browser)
  • Secret provider chain must include env (not just encrypted-file)
  • .dockerignore must exist if a Dockerfile is generated

DocumentDescription
AuthenticationPluggable auth providers (OIDC, AWS Sigv4, GCP IAP, Azure AD, etc.) gating the a2a HTTP server
Egress SecurityDeep dive into egress enforcement: IP validation, SafeDialer, profiles, modes, domain matching, proxy architecture, NetworkPolicy
Secrets ManagementEncrypted storage, per-agent secrets, passphrase handling
Build Signing & VerificationKey management, build signing, runtime verification
Content GuardrailsPII detection, jailbreak protection, custom rules
ArchitectureSystem design, module layout, and data flows
ToolsTool system including cli_execute security layers
SkillsSkill definitions and runtime execution
CommandsCLI reference including security-related flags

On this page