Security Model
Implemented isolation and authorization controls, with their scope and remaining trust assumptions.
Treat PR content, comments and repository automation as untrusted input. The controls below describe source behavior, not a certification, a penetration-test result or a guarantee against prompt injection.
The deployed-engine lineage is son-of-anton-review on feat/cloudflare-native. Extended operator authorization belongs to unmerged feat/greptile-operator-parity; dashboard session handling belongs to anton-ui-trace-parity. Do not infer that these are one deployed security boundary.
Validation isolation
The native container injects a Cloudflare Sandbox collector. The Worker receives an archive and validation shell, unpacks them into the sandbox workspace, executes there, and attempts sandbox destruction in finally. The orchestration container retains the model-provider key; the separate sandbox is where this validation path runs PR scripts.
If the Cloudflare Sandbox collector or binding is missing, validation refuses rather than falling back to local execution. Unknown executor selection also refuses. This does not mean validation always ran or passed: a refusal produces a missing-validation result.
local execution is explicitly available when GILF_ALLOW_LOCAL_VALIDATION=1. self-host requires GILF_SELF_HOST_VALIDATION=1 plus an executor command. That command is responsible for isolation, networking and compute teardown. The launcher cannot prove that an operator-supplied command uses a secure container or VM.
The general executor resolver falls back to managed-crabbox after explicit and legacy configuration. Native environment projection instead supplies managed-cf-sandbox. These are different defaults at different layers.
Sources: engine cloudflare-native/container/entrypoint.mjs:325-343; cloudflare-native/src/state-transport.js:615-679; src/validation-executor.js:61-97,524-579; cloudflare-native/src/container-env.js:72-85.
Child processes and repository configuration
The Codex child uses buildCodexExecEnv with inheritEnv: false. Its allowlist includes process basics such as PATH, HOME, locale and certificate variables, plus an explicit CODEX_HOME. Provider, App, webhook and queue keys are not copied by this helper.
This is environment reduction, not full filesystem or network isolation. The allowed home paths and configured agent credentials remain relevant. When execution is allowed, the Codex arguments include --dangerously-bypass-approvals-and-sandbox; the no-execution path instead uses --disable shell_tool --sandbox read-only. Do not generalize the no-execution setting into a guarantee for all reviews.
Crabbox refuses repository-supplied automation configuration unless GILF_CRABBOX_ALLOW_REPO_CONFIG=1. The runner also checks out the pinned headSha with git checkout --force --detach; it does not rely solely on a moving branch reference.
Sources: engine src/codex-review-runner.js:1280-1284,1901-1904,2185-2221,2843-2844,3121-3125.
App key and token boundary
The native broker Worker is configured without public routes or a workers.dev domain, and its fetch handler always returns 404. The App private key is absent from the container forwarding allowlist. Normal clone calls request repository-scoped read permissions; publication requests narrower check or pull-request write permissions.
The remaining boundary matters: handleBrokerRequest forwards caller-supplied installation, repository and permission scope. The broker applies defaults but does not enforce a purpose allowlist or bind scope to a review lease. A compromised orchestration container is not limited to its initial clone token. See Key broker.
Node self-host can load the App key in server.mjs and worker.mjs; do not claim the native key separation for that deployment.
Sources: engine cloudflare-native/wrangler.key-broker.jsonc:16-26; cloudflare-native/src/key-broker.js:13-33; cloudflare-native/src/key-broker-core.js:26-55; cloudflare-native/src/state-transport.js:583-599; cloudflare-native/container/entrypoint.mjs:110-123; src/github-publisher.js:13-78; server.mjs:52-59; worker.mjs:35-40.
Webhooks, commands and publication
Native ingress validates the webhook HMAC against GITHUB_WEBHOOK_SECRET. Its comparison checks length and XOR-accumulates the equal-length strings; this is separate from operator bearer-token handling. Signature verification authenticates the webhook delivery, not the commenter's permission to request a review.
The command authorization helper accepts explicitly allowed users or associations, defaulting to OWNER, MEMBER and COLLABORATOR. Ingress is a superset event filter, not the authoritative review-policy gate. Do not infer authorization merely from an event being queued.
Native publication defaults to shadow when unset, but the checked-in Wrangler configuration explicitly sets GILF_PUBLISH_MODE=live. Live publication requires a supplied authenticated client. Shadow publication still needs read-token minting for private repository preparation. Approval requires a pinned head SHA. Native publication claims protect against blind resends after ambiguous writes, not against all possible misuse of a compromised publisher.
Sources: engine cloudflare-native/src/ingress.js:22-58,280-285; src/commands.js:29-39; cloudflare-native/src/publish-mode.js:26-35,44-67; cloudflare-native/wrangler.jsonc:133; cloudflare-native/container/entrypoint.mjs:97-123; src/github-publisher.js:50-65.
Operator API authorization is branch-specific
The parity Worker uses Authorization: Bearer <token>. Its resolver reads SON_OF_ANTON_<NAME> before legacy GILF_<NAME>. These aliases apply to that Worker, not all engine environment variables.
| Legacy token variable | Route scope |
|---|---|
GILF_OPERATOR_READ_TOKEN | Ordinary operator GET routes, except key management |
GILF_OPERATOR_ADMIN_TOKEN | Key listing/creation/revocation and designated configuration/queue mutations |
GILF_OPERATOR_COMMAND_TOKEN | Command creation |
GILF_OPERATOR_BRIDGE_TOKEN | Command updates and command reads |
Static-token comparison uses timingSafeEqual after a length check. Tokens are route-specific, not a role hierarchy: an admin token is not automatically accepted as a read or command token. Dynamic anton_ keys have an explicit route allowlist and read / memory:write scopes; they cannot manage keys or create review commands.
For static-token calls, the Worker accepts x-operator-actor, defaulting to service-admin. That label is caller-supplied attribution by a trusted service-token holder, not independently authenticated human identity. The Node dashboard instead compares its bearer token using string equality and only serves GET requests.
Sources: parity cloudflare/src/env.js:1-9; cloudflare/src/worker.js:31-81,115-135; engine src/operator-dashboard.js:601-620.
Dashboard sessions
The parity BFF authenticates its opaque __Host-anton-session cookie, not a caller-supplied bearer. It uses Secure, HttpOnly and SameSite=Lax, with a 12-hour session lifetime. WorkOS validation pins the client-scoped issuer, verifies RS256 signatures through JWKS, requires subject and expiry, and checks WORKOS_ALLOWED_USER_IDS. It does not require an audience claim.
The BFF forwards server-configured backend tokens, and mutations require same-origin JSON requests. Static assets are served outside the API authentication gate; protected data requests are gated. This is source behavior, not confirmation of live WorkOS or backend configuration.
Sources: UI worker/bff-sessions.js:4-6,24-25,69-75,294-297; worker/workos-auth.js:11-18,43-79; worker/index.js:24-73; worker/proxy-utils.js:95-100.
Data and egress limits
Memory file reads use pinned Git objects, reject non-regular blobs and enforce path/file/byte bounds. These checks are specific to memory ingestion, not a blanket statement about every repository read.
Egress enforcement must be verified per executor. The native sandbox transport shown here does not accept or enforce an allowed-domain list. Setting E2B network variables only on the Worker also has no effect when those variables are absent from the container forwarding allowlist. Do not describe the native runtime as globally default-deny.
Trace attributes, events, errors and optional input/output can be persisted. The parity API omitting input/output fields is not storage redaction. Treat trace and operator access as sensitive.
Sources: engine src/review-memory-runtime.js:12-41; cloudflare-native/src/state-transport.js:625-679; cloudflare-native/src/container-env.js:15-70; cloudflare-native/src/trace-buffer.js:104-117; parity cloudflare/src/review-trace-queries.js:34-64.