Injection Policy

August 14, 2026 ยท View on GitHub

Workcell does not pass host homes, sockets, or complete provider state to the safe path. Use an operator-owned injection policy for each approved input.

Workcell can inject documents, credentials, SSH material, files, and endpoint entries. Credentials, copies, and SSH material can use provider and mode selectors.

Security boundary

Workcell validates each secret source on the host. Workcell stages the source in launcher-owned state.

Workcell mounts the staged source read-only. A crash can leave staged plaintext until cleanup.

Workcell rejects destination names that collide after NFC normalization and Unicode case folding. Workcell writes no content at a destination path it rejects for invalid UTF-8 data.

Store each credential source outside the mounted workspace. Workcell rejects a credential source inside the workspace.

Workcell does not pass host keychains into the runtime. A successful resolver runs on the host and writes a regular staged file.

Policy commands

Use these commands for the entrypoint policy file:

  • workcell auth init
  • workcell auth set
  • workcell auth unset
  • workcell auth status

Use these commands for the merged policy:

  • workcell policy show
  • workcell policy validate
  • workcell policy diff

Use workcell why to explain one credential decision. The command does not start a runtime.

workcell why --credential CREDENTIAL --agent PROVIDER --mode MODE

If an included fragment declares a value, change that fragment. The auth commands change only the entrypoint file.

Schema reference

The tables in this section list the keys that the parsers accept. A Go test compares each marked table with the corresponding parser key set.

Root keys

KeyTypeRequiredApplies toDefaultMeaning
versionIntegerNoAll providers1Schema version. Workcell accepts only 1.
includesPath arrayNoAll providersNoneOperator-owned policy fragments. Paths stay in the entrypoint tree.
documentsTableNoProviders with document supportNoneInstruction document sources.
credentialsTableNoCredential ownerNoneProvider and shared GitHub credential sources.
sshTableNoAll providersNoneSSH configuration, hosts, and identities.
copiesTable arrayNoAll providersNoneFiles or directories for non-reserved targets.
networkTableNoAll providersNoneEndpoint additions and removals. Colima enforces the result only with NETWORK_POLICY=allowlist.

An include path is relative to the file that contains it. Workcell rejects cycles, repeated files, and paths outside the entrypoint tree.

Document keys

KeyTypeRequiredApplies toDefaultMeaning
commonPathNoProviders with document supportNoneProvider-neutral instructions.
codexPathNoCodexNoneCodex instructions.
claudePathNoClaudeNoneClaude instructions.
geminiPathNoGeminiNoneGemini instructions.

Copilot has no document key. Its managed path disables custom instructions.

Credential keys

KeyTypeRequiredApplies toDefaultMeaning
claude_authPath or tableNoClaudeNoneAuth mirrors in ~/.claude/, ~/.claude.json, and ~/.config/claude-code/.
claude_api_keyPath or tableNoClaudeNoneHelper-backed Claude API key.
claude_mcpPath or tableNoClaudeNoneMCP configuration at ~/.mcp.json. This is not an auth mode.
codex_authPath or tableNoCodexNoneCodex auth at ~/.codex/auth.json.
copilot_github_tokenPath or tableNoCopilotNoneExport as COPILOT_GITHUB_TOKEN only to the managed child.
gemini_envPath or tableNoGeminiNoneValidated Gemini authentication at ~/.gemini/.env. See Gemini environment file.
gemini_oauthPath or tableNoGeminiNoneOAuth state at ~/.gemini/oauth_creds.json.
gemini_projectsPath or tableNoGeminiNoneProject registry at ~/.gemini/projects.json. This is supplemental input.
gcloud_adcPath or tableNoGeminiNoneADC at ~/.config/gcloud/application_default_credentials.json. This is supplemental input.
github_hostsTableNoClaude, Codex, GeminiNoneShared auth at ~/.config/gh/hosts.yml. Set a provider list.
github_configTableNoClaude, Codex, GeminiNoneShared config at ~/.config/gh/config.yml. Set a provider list.

Each value can be a direct path or an entry table. The shared GitHub keys must use a table with providers.

Copilot does not receive shared GitHub CLI state.

Gemini environment file

Use KEY=value assignments in gemini_env. Workcell accepts these modes:

ModeRequired keys
Gemini API keyGEMINI_API_KEY
Google Code AssistGOOGLE_GENAI_USE_GCA=true
Vertex API keyGOOGLE_GENAI_USE_VERTEXAI=true and GOOGLE_API_KEY
Vertex projectGOOGLE_GENAI_USE_VERTEXAI=true, a project key, and a location key

A project key is GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID. A location key is GOOGLE_CLOUD_LOCATION, GOOGLE_CLOUD_REGION, CLOUD_ML_REGION, VERTEX_LOCATION, or VERTEX_AI_LOCATION.

Only listed keys are valid. Values other than authentication selectors must not be empty. GOOGLE_GENAI_USE_GCA and GOOGLE_GENAI_USE_VERTEXAI accept only trimmed, case-insensitive true or false values. Do not set both selectors to true. Set GOOGLE_API_KEY only with GOOGLE_GENAI_USE_VERTEXAI=true. Set a project key when you set a location key.

Resolver entry keys

The resolver reads these keys before it renders the policy:

KeyTypeRequiredApplies toDefaultMeaning
sourcePathOne of source or resolverAll credential keysNoneDirect host source outside the workspace.
resolverStringOne of source or resolverSupported resolver keysNoneBuilt-in host resolver. It cannot occur with source.
materializationephemeral or persistentNoResolver entriesephemeralResolved-file lifetime. Auth resolvers require ephemeral.
providersProvider arrayNoAll credential keysIn-scope providersProvider selector. Shared GitHub keys require it.
modesMode arrayNoAll credential keysAll modesMode selector.

The supported resolvers are:

  • codex-home-auth-file for codex_auth
  • claude-macos-keychain for claude_auth

The Claude resolver records the intended source. It stops the launch because Workcell does not provide a supported export path.

Rendered credential entry keys

The resolver removes resolver and materialization. It writes a staged source for the renderer.

KeyTypeRequiredApplies toDefaultMeaning
sourcePathYesAll credential keysNoneStaged or direct host source outside the workspace.
providersProvider arrayNoAll credential keysIn-scope providersProvider selector. Shared GitHub keys require it.
modesMode arrayNoAll credential keysAll modesMode selector.

SSH keys

KeyTypeRequiredApplies toDefaultMeaning
enabledBooleanNoAll providersInferredExplicit SSH injection switch.
configPathNoAll providersNoneSSH configuration file.
known_hostsPathNoAll providersNoneKnown-hosts file.
identitiesPath arrayNoAll providersNonePrivate-key identity files.
providersProvider arrayNoAll providersAll providersProvider selector.
modesMode arrayNoAll providersAll modesMode selector.
allow_unsafe_configBooleanNoAll providersfalseAccept an SSH configuration with unsafe directives.

Workcell rejects group-writable or world-writable known_hosts files. It requires owner-owned and owner-only SSH configuration and identity files. Identity basenames must be unique. They must not be config or known_hosts.

allow_unsafe_config lowers assurance. It does not forward SSH_AUTH_SOCK. It skips the SSH directive safety check. It permits Include to load other configuration. It permits LocalCommand, PermitLocalCommand, and ProxyCommand to run commands. It permits PKCS11Provider and SecurityKeyProvider to load provider libraries.

The session status reports lower-assurance unsafe SSH configuration.

Copy keys

KeyTypeRequiredApplies toDefaultMeaning
sourcePathYesAll providersNoneHost file or directory.
targetContainer pathYesAll providersNoneDestination below /state/agent-home or /state/injected.
classificationpublic or secretYesAll providersNoneSecurity controls and file mode.
providersProvider arrayNoAll providersAll providersProvider selector.
modesMode arrayNoAll providersAll modesMode selector.

Workcell rejects writes to reserved control-plane targets. It checks secret sources for owner-only access and stages them as read-only.

Network keys

KeyTypeRequiredApplies toDefaultMeaning
allow_endpointshost:port or [ipv6]:port arrayNoAll providersNoneAdd exact endpoint entries. Colima enforces the result only with NETWORK_POLICY=allowlist.
deny_endpointshost:port or [ipv6]:port arrayNoAll providersNoneRemove exact entries after all additions.

Each port must be 1 through 65535. A host name can contain ASCII letters, digits, periods, and hyphens. It must not start with a period or contain two periods.

A numeric dotted value must be a valid IPv4 address. A bracketed value must be a valid IPv6 address.

Provider selectors accept claude, codex, copilot, and gemini.

Mode selectors accept strict, development, build, and breakglass.

Credential use

Direct staged files are the primary supported credential path. See the provider bootstrap matrix for maturity and live evidence.

Workcell supports copilot_github_token through the staged credential path. For Copilot, Workcell does not use host GitHub CLI or Copilot state.

The managed Copilot wrapper removes the staged token from direct mounts. It uses a temporary host mount and a transient runtime file. The wrapper deletes the runtime file before it starts the managed child.

The wrapper exports COPILOT_GITHUB_TOKEN only to that child. The Workcell entrypoint stays as PID 1 and scrubs its environment.

See the GitHub Copilot CLI delivery record for the complete token-transfer controls.

Workcell does not support Google Antigravity CLI. Do not put Antigravity keys in an operator policy.

Network rules

The launcher builds ALLOW_ENDPOINTS from these sources:

  • provider_endpoints.
  • provider_auth_recovery_extra_endpoints for a Gemini CLI launch with TTY input and output, no selected auth, and no agent or provider arguments. Dry-run, prepare-only, and arbitrary-command modes do not add these endpoints.
  • target_broker_endpoints.
  • credential_extra_endpoints.
  • Google account authentication endpoints from a selected gemini_env mode.
  • Global and location-specific Vertex endpoints from a selected gemini_env mode.
  • Versioned profile EXTRA_ENDPOINTS.
  • [network].allow_endpoints.
  • snapshot-cloudflare.debian.org:443 and snapshot.debian.org:443 for a non-remote ephemeral launch.

It removes every [network].deny_endpoints entry from the session list and the list for bootstrap build containers.

On colima with NETWORK_POLICY=allowlist, Workcell enforces the result with IPv4 and IPv6 DOCKER-USER rules. The rules allow resolved IP addresses and ports. They do not filter TLS host names.

The enforcement scope is one Colima profile. It is not one session. The last launch replaces the rules for all active containers in that profile.

On a Colima allowlist profile, a runtime-image rebuild temporarily applies the broader bootstrap endpoints to all active profile containers. Workcell restores ALLOW_ENDPOINTS after the build.

Do not rebuild the profile while another profile container is active.

Workcell does not isolate the profile-wide egress rules for concurrent sessions that use different complete endpoint sets. A breakglass launch clears the Workcell allowlist for the profile. That clear state remains until a later allowlist launch applies new rules.

Do not run sessions with different complete endpoint sets at the same time in one profile.

allow_endpoints broadens the allowed set. deny_endpoints removes exact entries after all additions. Policy cannot change NETWORK_POLICY or disable enforcement directly.

A denied host can share an IP address with an allowed host. In that case, the denied host stays reachable at the IP layer.

Host-side rebuild downloads do not use the Colima firewall.

Other targets do not receive this allowlist. Their launch summary reports egress_enforcement=none.

Target stateegress_enforcementWorkcell enforcement
Colima with allowlistallowlistProfile-wide IPv4 and IPv6 rules
Colima with unrestricted networknoneNone
Docker DesktopnoneNone
aws-ec2-ssm previewnoneNone
gcp-vm previewnoneNone

The remote targets are launch-blocked. Their preview plans rely on provider firewall controls if live launch support ships later.

Instruction precedence

Adapters with native document support use this order:

  1. Adapter baseline document.
  2. Repository AGENTS.md.
  3. Repository provider overlay, such as CLAUDE.md or GEMINI.md.
  4. documents.common.
  5. Provider-specific policy document.

The Copilot adapter masks .github/copilot-instructions.md, .github/instructions, and .github/copilot. Its managed wrapper disables custom instructions.

Examples

Keep each source outside the workspace. Workcell rejects operator-controlled symbolic links in source paths, parent paths, and copied directories. Use owner-only permissions for secret sources.

Provider credentials

version = 1

[credentials]
codex_auth = "/home/example/secrets/codex-auth.json"
claude_auth = "/home/example/secrets/claude-auth.json"
copilot_github_token = "/home/example/secrets/copilot-token.txt"
gemini_env = "/home/example/secrets/gemini.env"

Provider-native keys apply only to the provider that owns them.

Shared GitHub CLI state

[credentials.github_hosts]
source = "/home/example/secrets/gh-hosts.yml"
providers = ["codex", "claude", "gemini"]

[credentials.github_config]
source = "/home/example/secrets/gh-config.yml"
providers = ["codex", "claude", "gemini"]

Network changes

[network]
allow_endpoints = ["registry.internal.example:443"]
deny_endpoints = ["chatgpt.com:443"]

See the complete example for documents, credentials, and copies.

Explicit limits

Policy reader trust boundary

The policy reader accepts at most 16 MiB for one policy file. The reader accepts at most 64 MiB and 4,096 files for one include bundle. The limits include the entrypoint and each included policy file. The reader accepts a regular file only. The current user must own the file. Group and other users must not have write permission.

The file must have exactly one hard link. Group and other users can read a policy file. On Darwin, it accepts only group:everyone deny delete with no ACL flags. On Linux, it rejects unproved ACL types and NFS, CIFS, and SMB descriptor filesystems. On Linux, it accepts POSIX ACLs on root-owned system ancestors only on ext2, ext3, ext4, XFS, Btrfs, tmpfs, and OverlayFS filesystems. The directory mode proves that the access ACL gives no non-owner write permission. A default ACL cannot change access to that existing ancestor. The reader checks each descendant separately. The reader rejects POSIX ACLs on policy files, current-user directories, and sticky transit directories.

The reader opens each path component by descriptor. The descriptor walk rejects symbolic links that reach the reader. Some entrypoint callers resolve a selected symbolic link before this walk. It accepts non-writable root-owned ancestors and root-owned sticky transit directories before the user anchor. It requires current-user ownership below the user anchor.

It rejects group or other write permission below that anchor. The reader rejects other foreign-owned ancestors and non-sticky writable ancestors. On Darwin, it canonicalizes /var, /etc, and /tmp below /private before the walk.

The reader checks metadata before the first read and after the first and last bounded reads. It rejects identity, owner, group, mode, link-count, and size changes. It rejects byte-count and modification changes. It reads the descriptor again to reject same-length in-place changes. The parser and SHA-256 source record use the accepted descriptor snapshot.

  • The safe path does not accept arbitrary environment variables that contain secrets.
  • The safe path does not pass a complete host home.
  • [[copies]] cannot write Workcell control-plane paths.
  • Workcell does not forward SSH_AUTH_SOCK.
  • Workcell reads an injection manifest only from a regular file of 16 MiB or less.
  • Workcell writes an injection manifest only to a regular file of 16 MiB or less.
  • Workcell reads a direct-mount specification only from a regular file of 1 MiB or less.
  • Workcell writes a direct-mount specification only to a regular file of 1 MiB or less.
  • Processes in one session do not receive isolation from each other.
  • Copilot does not receive host provider homes, keychains, or ambient CLI auth.
  • Strict mode does not set provider telemetry or content-capture variables.
  • The Colima egress allowlist is profile-wide and uses IP addresses and ports.