Forge Trust & Security
Forge is a secure, portable AI Agent runtime. Run agents locally, in cloud, or enterprise environments without exposing inbound tunnels. Here's how.
Project Health
Live Status
Architecture
Security Architecture
Atomicity. Security. Portability. Every layer of Forge's architecture is designed to make these properties verifiable, not just claimed.
Forge's security is organized as a defense-in-depth stack. Each layer addresses a different threat surface, and layers are independently enforceable. No single layer failing compromises the entire system.
Content filtering, PII detection, jailbreak protection
Inbound and outbound messages are checked against configurable policy rules. Built-in guardrails include content filtering, PII detection (email, phone, SSN), and jailbreak phrase detection. Modes: enforce (blocking) or warn (logging).
EgressEnforcer + EgressProxy + NetworkPolicy
Three-level outbound network control: an in-process Go RoundTripper validates every HTTP request, a localhost proxy enforces the same rules on subprocess traffic (curl, wget, Python), and Kubernetes NetworkPolicy restricts pod-level egress in production.
Env isolation, binary allowlists, arg validation
External code runs through sandboxed executors with environment isolation, binary allowlists, argument validation (rejects shell injection patterns), configurable timeouts, and output size limits. No shell expansion — ever.
AES-256-GCM, Argon2id, per-agent isolation
Secrets are encrypted at rest using AES-256-GCM with Argon2id key derivation. Storage is per-agent with a provider chain: agent-local encrypted → global encrypted → environment variables. Files are 0600, excluded from git and Docker.
Ed25519 signing, SHA-256 checksums
Every build computes SHA-256 checksums of all artifacts and signs them with Ed25519. Verification at runtime checks checksums and validates signatures against a trusted keyring. Production builds reject dev-open egress and dev-only tools.
Outbound-only connections, no public listeners
Forge agents never expose inbound listeners. No ngrok, no Cloudflare tunnels, no inbound webhooks. Slack uses Socket Mode (outbound WebSocket), Telegram uses long-polling. The dev server binds to localhost only. Zero inbound attack surface by default.
Layer 6
Network Posture
A running Forge agent has zero inbound attack surface by default. This is a fundamental design constraint, not a configuration option.
No Public Tunnels
Forge does not create ngrok, Cloudflare, or similar tunnels. There is no mechanism for inbound connections from the public internet.
No Inbound Webhooks
Channels use outbound-only connections. Slack uses Socket Mode (outbound WebSocket via apps.connections.open). Telegram uses long-polling via getUpdates.
Local-Only HTTP
The A2A dev server binds to localhost by default. It is never exposed to the network without explicit configuration.
Explicit Bindings
Every network binding is explicit and logged. No hidden listeners, no background services, no surprise ports.
Layer 5
Egress Control
Forge restricts outbound network access at three independent levels, each catching traffic that could bypass the previous layer.
Three-Level Enforcement
In-Process Enforcer
A Go http.RoundTripper wraps every outbound HTTP request from in-process tools. Validates destination domain against the resolved allowlist before forwarding.
Subprocess Proxy
A local EgressProxy on 127.0.0.1:<port> validates domains for subprocess HTTP traffic via HTTP_PROXY/HTTPS_PROXY injection.
Kubernetes NetworkPolicy
In containerized deployments, generated Kubernetes NetworkPolicy manifests enforce egress at the pod level, restricting traffic to allowed domains on ports 80/443.
Proxy Architecture
┌─────────────────────────────────────────────────────┐
│ forge run │
│ │
│ In-process HTTP ──→ EgressEnforcer (RoundTripper) │
│ │
│ Subprocesses ──→ HTTP_PROXY ──→ EgressProxy │
│ (curl, wget, 127.0.0.1:<port> (validates │
│ python, etc.) domains) │
└─────────────────────────────────────────────────────┘ Egress Modes
| Mode | Behavior |
|---|---|
| deny-all | All non-localhost outbound traffic blocked |
| allowlist | Only explicitly allowed domains (exact + wildcard) |
| dev-open | All traffic allowed (development only) |
Domain Matching Rules
- • Exact match:
api.openai.commatchesapi.openai.com - • Wildcard match:
*.github.commatchesapi.github.combut notgithub.com - • Case insensitive:
API.OpenAI.COMmatchesapi.openai.com - • Localhost bypass:
127.0.0.1,::1, andlocalhostare always allowed in all modes
Domain Resolution
Allowed domains are resolved from three sources, combined and deduplicated:
- Explicit domains — listed in
forge.yamlunderegress.allowed_domains - Tool domains — automatically inferred from registered tool names (e.g.,
web_search→api.tavily.com) - Capability bundles — pre-defined domain sets for common services (e.g.,
slack→slack.com,hooks.slack.com,api.slack.com)
Configuration
# forge.yaml
egress:
profile: standard
mode: allowlist
allowed_domains:
- api.example.com
- "*.github.com"
- hooks.slack.com
capabilities:
- slack
- telegram Production vs Development
| Setting | Production | Development |
|---|---|---|
| Profile | strict / standard | permissive |
| Mode | deny-all / allowlist | dev-open |
| Dev tools | Filtered out | Included |
| Network policy | Enforced | Not generated |
| Egress proxy | Active | Skipped |
| Container egress | NetworkPolicy | Proxy |
Layer 4
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 with the following controls:
| Control | Detail |
|---|---|
| Environment isolation | Only PATH, HOME, and explicitly declared env vars passed through |
| Egress proxy injection | HTTP_PROXY/HTTPS_PROXY route subprocess HTTP through the egress proxy |
| Configurable timeout | Per-skill timeout_hint in YAML frontmatter (default: 120s) |
| No shell | Runs bash <script> <json-input>, not through a shell interpreter |
| Scoped env vars | Only env vars declared in the skill's requires.env section are passed |
CLIExecuteTool — 7 Security Layers
The cli_execute tool provides layered security enforcement:
| # | Layer | Detail |
|---|---|---|
| 1 | Binary allowlist | Only pre-approved binaries can execute |
| 2 | Binary resolution | Resolved to absolute paths via exec.LookPath at startup |
| 3 | Argument validation | Rejects arguments containing $(, backticks, or newlines |
| 4 | Timeout | Configurable per-command timeout (default: 120s) |
| 5 | No shell | Uses exec.CommandContext directly — no shell expansion |
| 6 | Environment isolation | Only PATH, HOME, LANG, explicit passthrough vars, and proxy vars |
| 7 | Output limits | Configurable max output size (default: 1MB) to prevent memory exhaustion |
Configuration
# forge.yaml
tools:
- name: cli_execute
config:
allowed_binaries: ["git", "curl", "jq", "python3"]
env_passthrough: ["GITHUB_TOKEN"]
timeout: 120
max_output_bytes: 1048576 Skill Trust
Trust Model
Trust is computed, not declared. Contributors cannot set their own trust level.
Trust Levels
| Level | Value | Visible | Executable | Used For |
|---|---|---|---|---|
| Failed | -1 | No | No | Skills that fail validation or security analysis |
| Untrusted | 0 | Yes | No | Discovered but not evaluated, or failed remote signature |
| Under Review | 1 | Yes | No | Has warnings, pending admin promotion |
| Trusted | 2 | Yes | Yes | Passed all gates — fully active |
Autowire Pipeline
Skills are autodiscovered and trust-evaluated through a pipeline:
Directory Scanner → Frontmatter Parser → Security Analyzer → Trust Evaluator
Find dirs Parse YAML Verify hints Assign trust
with SKILL.md + validate vs actual content level Security Analyzer Checks
| Check | What | Severity |
|---|---|---|
| Egress/network mismatch | trust_hints.requires_network: false but egress domains declared | Critical |
| Shell/scripts mismatch | trust_hints.requires_shell: false but scripts/ exists | Critical |
| Dangerous script patterns | curl|sh, eval, rm -rf /, chmod 777 | Critical |
| Hardcoded secrets | API_KEY=... patterns in scripts | Critical |
| Broad binary request | Requiring bash, sh directly | Warning |
| Overly permissive egress | Wildcard patterns, CDN domains | Warning |
| Env var leak risk | Scripts that echo/print secrets | Warning |
Trust Rules by Tier
Embedded Skills
Always Trusted — curated by Forge maintainers.
Local Skills (strict)
Validation fail → Failed. Security critical → Failed. Security warning → Under Review. All clean → Trusted.
Remote Skills (leveled)
Failed at remote → Failed (never shown). Invalid signature → Untrusted. Untrusted registry → capped at Under Review. Trusted registry + clean → Trusted.
Layer 3
Secrets Management
Forge provides encrypted secret storage with per-agent isolation and defense-in-depth.
Encryption
AES-256-GCM
Authenticated encryption
Argon2id
Memory-hard, resistant to GPU attacks
File format: salt(16 bytes) || nonce(12 bytes) || ciphertext. Plaintext format is JSON key-value map.
Storage Hierarchy
Secrets are resolved in order, with earlier sources taking priority:
| # | Source | Location |
|---|---|---|
| 1 | Agent-local | <agent-dir>/.forge/secrets.enc |
| 2 | Global | ~/.forge/secrets.enc |
| 3 | Environment | os.Getenv() |
Passphrase Handling
| Context | Behavior |
|---|---|
| forge run (TTY) | Prompts interactively if FORGE_PASSPHRASE not set |
| forge run (CI/CD) | Reads from FORGE_PASSPHRASE environment variable |
| forge init (first time) | Prompts for passphrase + confirmation |
| forge init (subsequent) | Prompts once and validates against existing file |
File Safety
- •
.forge/directories are automatically added to.gitignore - •
*.encfiles are excluded in.dockerignore - • Secret files use
0600permissions (owner-only read/write) - • Secret files never appear in container images
CLI Commands
forge secret set OPENAI_API_KEY # Prompts for value securely
forge secret set SLACK_BOT_TOKEN xoxb-... # Inline value
forge secret get OPENAI_API_KEY # Shows value and source
forge secret list # Lists all keys
forge secret delete OLD_KEY # Removes a key
forge secret set API_KEY --local # Agent-local secret Layer 2
Build Signing & Integrity
Forge supports Ed25519 signing of build artifacts for supply chain integrity verification.
Signing Flow
forge build computes SHA-256 checksums of all generated artifacts
If a signing key exists at ~/.forge/signing-key.pem, checksums are signed with Ed25519
checksums.json is written with checksums, signature, and key ID
Verification Flow
Validates SHA-256 checksums of all files against checksums.json
Verifies the Ed25519 signature against trusted keys in ~/.forge/trusted-keys/
If checksums.json doesn't exist, verification is skipped (opt-in model)
Key Management
forge key generate # Generate Ed25519 keypair
forge key generate --name ci-key # Named keypair
forge key trust ~/.forge/signing-key.pub # Add to trusted keyring
forge key list # List signing + trusted keys Production Build Safety
The build pipeline includes a secret-safety stage that enforces production constraints:
- • Blocks production builds that only use
encrypted-filewithoutenvprovider - • Warns if
.dockerignoreis missing alongside a generated Dockerfile - • Rejects
dev-openegress mode in production builds - • Filters out dev-only tools (
local_shell,local_file_browser)
Layer 1
Guardrails
The guardrail engine checks inbound and outbound messages against configurable policy rules.
Built-in Guardrails
| Guardrail | Direction | Description |
|---|---|---|
| content_filter | Inbound + Outbound | Blocks messages containing configured blocked words |
| no_pii | Outbound | Detects email addresses, phone numbers, and SSNs via regex |
| jailbreak_protection | Inbound | Detects common jailbreak phrases ("ignore previous instructions", etc.) |
Enforcement Modes
| Mode | Behavior |
|---|---|
| enforce | Blocks violating messages, returns error to caller |
| warn | Logs violation, allows message to pass |
Runtime
# Run with guardrails enforced
forge run --enforce-guardrails
# Default: warn mode (log only)
forge run Observability
Audit Logging
All runtime security events are emitted as structured NDJSON to stderr with correlation IDs for end-to-end tracing.
Event Types
| Event | Description |
|---|---|
| session_start | New task session begins |
| session_end | Task session completes (with final state) |
| tool_exec | Tool execution start/end (with tool name) |
| egress_allowed | Outbound request allowed (with domain, mode) |
| egress_blocked | Outbound request blocked (with domain, mode) |
| llm_call | LLM API call completed (with token count) |
| guardrail_check | Guardrail evaluation result |
Correlation Threading
Every event carries a 16-hex-character correlation_id that links all events within a single task session. The source field distinguishes in-process enforcer events from subprocess proxy events ("source": "proxy").
Example Output
{"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"}} Deployment
Container Security
Every forge build generates container-ready security artifacts for production deployment.
Build Artifacts
| Artifact | Purpose |
|---|---|
| egress_allowlist.json | Machine-readable domain allowlist |
| network-policy.yaml | Kubernetes NetworkPolicy restricting pod egress |
| Dockerfile | Container image with minimal attack surface |
| checksums.json | SHA-256 checksums + Ed25519 signature |
Container Runtime Behavior
When Forge detects it's running inside a container (via KUBERNETES_SERVICE_HOST or /.dockerenv):
- • The local
EgressProxyis not started —NetworkPolicyhandles egress enforcement at the infrastructure level - • All other security controls (guardrails, execution sandboxing, audit logging) remain active
- • Secrets must use the
envprovider (encrypted files can't be decrypted without a passphrase)
Production Build
forge package --prod
Production builds enforce: no dev-open egress mode, no dev-only tools, secret provider chain must include env, and .dockerignore must exist if a Dockerfile is generated.
Reporting
Responsible Disclosure
Report a Vulnerability
If you discover a security vulnerability in Forge, please report it responsibly.
Security Contact
Response Timeline
- • Acknowledge within 48 hours
- • Fix within 90 days
GitHub Security Advisories
Standards
Compliance & Standards
Available Today
- Apache 2.0 open-source license
- NDJSON audit logs with correlation threading
- AES-256-GCM encrypted secrets at rest
- Ed25519 signed builds with checksum verification
- Layered egress enforcement with NetworkPolicy
Roadmap
- SOC 2 Type II readiness
- HIPAA-compliant skill packs (via Hub Enterprise)
- SIEM integration guides
- Dependency vulnerability scanning (
govulncheck)