Skip to content

TAB-1104: hide caller data from the model (fill by key at the sink)#596

Merged
lmorchard merged 3 commits into
mainfrom
stafford/tab-1104-hide-caller-data-from-model
Jul 20, 2026
Merged

TAB-1104: hide caller data from the model (fill by key at the sink)#596
lmorchard merged 3 commits into
mainfrom
stafford/tab-1104-hide-caller-data-from-model

Conversation

@srbiv

@srbiv srbiv commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Caller data (from /v1/automate) was JSON.stringify'd into the task prompt (prompts.ts {{ data }}), so the model could read a secret and place it into a goto URL, a Tabstack URL, or done(). Hiding the value is the root fix — the model cannot leak what it never sees.

Change

  • prompts.ts: render only the data KEYS, not values; buildTaskAndPlanPrompt takes dataKeys; hasUserData threaded into the tool list and the step-error feedback prompt.
  • New fill_user_data(ref, key) tool (in webActionTools): resolves data[key] and substitutes it at browser.performAction; the value is never returned or emitted (only a {{key}} mask).
    • Runs the same assessFill gate as regular fill (blocked on untrusted hosts) and records agentFilledRefs/operationalRefs — never approvedRefs, so the form-submit gate still applies.
    • Maps select/checkbox/radio to the right browser action.
  • webAgent.ts: pass data to the tools; pass keys (not values) to the prompt.

Why hide, not scrub

Detecting the secret in an outbound URL is a blocklist — encoding/param/method evade it. The model never receiving the value is structural: no domain, encoding, or sink matters.

Testing

  • fill_user_data unit tests: blocked on untrusted host (no performAction, SECURITY_BLOCKED_UNAUTHORIZED_FILL), allowed on trusted host (value masked, ref in agentFilledRefs not approvedRefs), unknown key, select field, BrowserException.
  • prompts test: keys rendered, values absent.
  • Live-verified on this branch: same-domain attack, model fully cooperating — the real canary never left (collector saw only the literal placeholder); agent aborted, stating it could not substitute a data key into goto.
  • Full suite: core 918, cli/server/extension typecheck all pass.

Complements #595 (destination allowlist). Related: TAB-1104.

…TAB-1104)

Caller data was JSON-rendered into the task prompt, so the model could read a secret and place it into a goto/tabstack URL or done(). Render only the data KEYS; add fill_user_data(ref, key) which substitutes the value at the browser sink and never returns or emits it (only a {{key}} mask). It runs the same assessFill gate as regular fill and records agentFilledRefs (never approvedRefs), so it cannot fill caller data into fields on untrusted hosts. The model never holds the value, so it cannot exfiltrate it regardless of domain or encoding. Keys-only prompt, hasUserData threaded into the tool list and step-error prompt, select/checkbox mapping.
@srbiv
srbiv requested a review from a team July 17, 2026 20:24

@lmorchard lmorchard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 and think I'll go ahead and merge this and rebase a follow-up against this for #607

@lmorchard
lmorchard merged commit 8339bd2 into main Jul 20, 2026
13 checks passed
@lmorchard
lmorchard deleted the stafford/tab-1104-hide-caller-data-from-model branch July 20, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants