Skip to content

Follow-up (after #596): close caller-data re-injection via page snapshot + tighten data-fill gate #607

Description

@lmorchard

Fast-follow to #596 (hide caller data from the model) and #595 (navigation/Tabstack destination allowlist). #596 is a strict improvement and safe to merge as-is; these are the residuals it leaves open for caller data, tracked here so they don't slip.

1. Snapshot re-injection (the main one)

#596 keeps the caller-data value out of the prompt and the fill_user_data result/events. But after a successful fill the value lives in element.value, and the next page snapshot serializes it straight back into the model context — packages/core/src/browser/ariaTree/ariaSnapshot.ts:256-257 exposes element.value for all inputs/textareas except a narrow credential list (password/cc-*/OTP). So a placed membership code / email / address / phone re-enters context on the following turn. This makes the "the model cannot leak what it never sees" property hold for the prompt/tool-result but not end-to-end.

Fix: redact known caller-data values from the snapshot string node-side (in WebAgent.addPageSnapshot, before compress), reusing a collectSensitiveValues(data) set. Robust to ARIA-ref churn (refs are regenerated every snapshot, so per-ref masking is not viable) and to React reconciliation, since it operates on the serialized string. Apply the same redaction to the extract tool's getMarkdown, which is the same re-injection class.
Known residual to document: sub-threshold-length values (very short secrets) won't be redacted.

2. Tighten the fill_user_data gate (pre-existing weakness, inherited)

fill_user_data reuses assessFill, which exempts operational fields (search boxes, comboboxes, spinbuttons, sliders) from the host-trust check. So a caller secret can be placed into an operational field on an untrusted host (reachable via a link click, which #595 does not gate), where the page's own JS can read element.value; and because it records operationalRefs, the submit gate then allows submitting it to that same host. This is not introduced by #596 — the normal fill tool has the same exemption — but caller data should not inherit the search-box carve-out.

Fix: gate fill_user_data more strictly than assessFill — allow only when the page host is trusted (start host + trusted_hostnames; unsafe_mode overriding), with no operational exemption, and do not add these refs to operationalRefs.

Guardrail

Do not report the indirect-prompt-injection → data-exfiltration finding as closed until item 1 lands: #595 + #596 substantially narrow it, but the snapshot re-injection path remains until the redaction is in.

Related / separate

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions