Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Security Model Reference

Technical reference for Gateway's execution security — token delegation, capability manifests, and D1 sandboxing.

For the non-technical version, see What Happens When You're Away.

Threat Model

The primary threat is prompt injection during autonomous execution. A malicious run input attempts to hijack the LLM into accessing resources beyond the procedure's scope — reading private Notion pages, posting unauthorized Slack messages, or exfiltrating data via provider tokens.

Secondary concerns:

  • Users gaming procedures by reading internal evaluation criteria
  • Cross-run data leakage between users
  • Token misuse during multi-party procedure execution

D1 as Security Boundary

During execution, all run data (submissions, logs, state) lives in D1 — not in any provider. This is the core security property.

D1 security boundary: all reads/writes during execution, export to Provider APIs on close only

A prompt injection during step execution has no provider token in scope for D1 reads/writes. Provider tokens only fire for explicitly declared capabilities (Slack posts, Linear issues).

Token Delegation

Different tokens are used at different points in a procedure's lifecycle.

Interactive execution (user present)

ActionToken usedWhy
Read procedure from NotionUser's Notion tokenUser has read access to the procedure
Create run in D1N/A (internal)No provider token needed
Post Slack messageUser's Slack tokenMessage appears as the user
Create Linear issueUser's Linear tokenAttribution to the user

Autonomous execution (cron/Gemini)

ActionToken usedWhy
Read procedure snapshotN/A (from D1)Snapshotted at run creation
Read/write run stateN/A (D1)Internal database, no provider token
Post Slack messageWorkspace bot tokenMessage appears as "Gateway [BOT]"
Create Linear issueRun creator's Linear tokenAttribution to whoever started the run
Export to Notion on closeProcedure creator's Notion tokenScoped to their visibility in Notion

Key constraints

  • No user impersonation during autonomous execution. The bot token is clearly identified. The run creator's token is used for attribution only.
  • No Notion reads during execution. The procedure document is snapshotted into D1 at run creation. Gemini works from the snapshot, not from live Notion.
  • No provider token for D1 operations. Run data, submissions, and logs are stored in D1 with code-enforced ACL. No OAuth token can be hijacked to access them.

Notion integration access

The Gateway Notion integration can only access pages explicitly shared with it. In practice:

ScenarioAccess
Pages inside the Gateway → Procedures treeAutomatic — Gateway created them
Export databases created on run closeAutomatic — Gateway creates them as children of the procedure page
Pages created manually outside the treeNo access — must be shared with the Gateway integration or moved into the tree

This means procedure pages must live inside the Gateway-managed Notion hierarchy. The bootstrap flow (triggered on first Notion connection) creates a Gateway page with a Procedures child database. Everything inside that tree is accessible to both the procedure creator's token and the Gateway integration.

Token-Based Scoping

Rather than declaring explicit capability manifests in procedure documents, access is naturally scoped by the actor's tokens at each point in execution. The procedure document describes what to do; the token model constrains what's reachable.

Enforcement layers

Layer 1 — Token scoping: Each actor can only access what their OAuth token allows. The bot token can post to channels it's been added to. The run creator's Linear token only reaches their teams. The procedure creator's Notion token only sees their workspace.

Layer 2 — Prompt-level: The AI only receives the current step's instructions via get_run, never the full procedure source. The runner skill enforces a step-at-a-time execution model. This is a soft boundary — it relies on the LLM following the instructions faithfully — but the information surface is minimized.

Layer 3 — D1 ACL: Run data access is gated by run_access table joins. Even if prompt-level enforcement is bypassed, the SQL queries enforce who can read what.

Procedure Version Snapshots

When a run starts, the full procedure document is snapshotted into the run's D1 record. This means:

  • Autonomous execution reads from D1, not from live Notion
  • Procedure edits don't affect in-flight runs (until migration)
  • The snapshot locks the procedure logic to the version that started the run

Version mismatch

ScenarioDetectionResolution
Minor edit (1.0 → 1.1)LLM compares snapshot vs current on resumeAdapts — applies new step language going forward
Major edit (1.1 → 2.0)LLM detects structural changeSets needs_migration — admin review required
Procedure deletedRun has snapshot, can still completeLogged as orphaned; admin notified

Slack Bot

Gateway is installed as a Slack app with bot scopes for autonomous execution.

Scopes

ScopeUsed for
chat:writePost messages as Gateway bot
reactions:readPoll for approval reactions
channels:readResolve channel membership for groups
users:readMap Slack users to emails
users:read.emailGet email addresses for cross-provider identity

Token storage

Bot tokens are stored per Slack workspace in D1:

CREATE TABLE slack_workspace (
  workspace_id TEXT PRIMARY KEY,
  bot_token TEXT NOT NULL,
  team_name TEXT,
  created_at TEXT DEFAULT (datetime('now')),
  updated_at TEXT DEFAULT (datetime('now'))
);

User tokens (for interactive execution) remain in the linked_accounts table.