Security
UID isolation, git policy, egress, HMAC, and what is not protected.
The executor assumes a pull request can contain hostile code. Isolation is process and network policy, not a promise that a model will behave.
UID isolation
| Process | UID |
|---|---|
| Controller | 1000 |
| Agent, workers, repository checks | 60531, via a sudo helper |
The child environment is an allowlist. There is no same-UID fallback when sudo is missing. Timeout cleanup signals the process group. The Docker run uses --init so orphan descendants are reaped. A descendant that starts a new session is not stopped by that signal.
Collected agent output must be a regular file, not a symlink, and at most 64 MiB.
security.allow_same_uid: true disables this split. It is valid only with autonomy.dry_run: true. Doctor then WARNs on row agent_uid: agents can read controller secrets through procfs. The hosted launcher refuses allow_same_uid even for a dry run.
Executable config is moved aside
For the duration of a call, these paths are stashed and then restored. The commit still contains them. They do not execute during the call.
| Agent | Paths |
|---|---|
| acpx (every agent) | .acpxrc.json |
claude | .mcp.json, .claude/settings.json, .claude/settings.local.json |
codex | .codex |
kimi | .kimi, .kimi-code |
grok-build | .grok |
opencode | opencode.json, opencode.jsonc, .opencode |
These instruction files stay in place: CLAUDE.md, AGENTS.md, .claude/commands, .claude/agents.
Git policy
- Git metadata is moved out of the checkout.
- The agent cannot stage, commit, change refs, or change git config.
- Hooks are disabled.
- Repo config is an allowlist.
- Submodules are not used.
- Push is allowed only to a matching GitHub HTTPS origin. The token is in the environment, not in argv. SSH push is not used.
Egress
Egress is not implemented in this repository's Python. The hosted worker uses an SNI gateway (autofeat-egress-gw in the go-live notes): TCP 443 is redirected, and nginx ssl_preread allows a host list. The live list is nixos egress.allowedHosts.
Documented categories: GitHub, Anthropic, OpenAI and codex, Moonshot and kimi, xAI and grok, GCP OAuth2, Pub/Sub, and Secret Manager. Later notes also allow auth.kimi.com and grok.com. There is no npm registry. Examples refused in those notes: api.mixpanel.com, http-intake.logs.us5.datadoghq.com, registry.npmjs.org. Treat that list as the doc snapshot. Confirm the live hosts in nixos before you rely on a name.
HMAC and redaction
Directives are HMAC-signed with the signing key. require_signature defaults to true. The portal cannot forge a signature.
The scanner masks GitHub, provider, cloud, Slack, package, Sourcegraph, JWT, age, and private-key shapes, plus assignment, HTTP auth, and git-config shapes, and Gitleaks defaults. register_environment_secrets() snapshots environment names that contain TOKEN, KEY, SECRET, or PASSWORD. Masking hides a string in logs and comments. It does not stop a process that already holds the value.
What is not protected
- A child that creates a new session can outlive the timeout signal.
allow_same_uidlets the agent read controller secrets. Do not use it on a host that holds real keys. The hosted launcher refuses it.- Branch protection is still required. autofeat does not replace required reviews you configured on GitHub, except where
auto_approveasks the App to approve. GitHub may ignore an approval from the App that opened the pull request. - Instruction files (
CLAUDE.md,AGENTS.md) are visible to the agent on purpose. - Redaction is masking, not prevention.
- The egress host list is operator config in nixos, not a check inside
.autofeat/config.yml.