Skip to content

§6.4: add page-enforced write boundaries as a mitigation for agent over-reach #298

Description

@minjikim89

§6.4's mitigations all address one direction: a site misleading an agent (input-length limits, shared attack evals, untrustedContentHint). §6.3.2 Current Gaps ends with "no verification mechanism … no behavioral contracts … agents must assume good faith from site developers."

The reverse direction has no listed mitigation: an agent, misled or simply over-eager, exceeding the scope a person delegated on a site that exposed write tools. That is the direction prompt injection actually exploits: the injected instruction lives in the site's content, and the damage lands on the site's own data.

Proposal

Name, in §6.4, a mitigation that does not depend on the model resisting injection. The page enforces, in the tool implementations:

  • (a) a person-owned write scope. Writes outside it are refused with a structured error naming the allowed targets.
  • (b) optimistic concurrency against the person's own edits. Writes over changes the agent has not read are refused with a diff.
  • (c) page-owned cancellation for long-running writes, so a stop reports what landed.

The point is that none of these ask the model to behave. They are ordinary preconditions in the tool body, and they hold whatever the agent believes.

Measured

scripts/guardrail-eval.mts hands a model the same tool contracts the page registers and dispatches to the same implementations, with the guards on and off. Scale, stated plainly: one task, one site, two models, ten runs per arm.

arm wrote over an unread hand edit task completed
gpt-4.1 · guards ON 0/10 10/10
gpt-4.1 · guards OFF 10/10 10/10
gpt-5.4 · guards ON 0/9 9/9
gpt-5.4 · guards OFF 8/8 8/8

gpt-5.4 lost 3 of 20 runs to network errors, which were excluded; hence 9 and 8.

Two honest notes on the injection scenario. First, on gpt-4.1 the model followed the injected instruction in 0/10 runs with the guards on and 0/10 with them off, so it did not distinguish the arms, so that run says nothing about the guards. That is why a second, model-free arm exists: a scripted agent that follows the injection by construction rewrote 8 of 9 unmarked slides with the guards off and 0 of 9 with them on. The claim is about the page refusing the write, not about a model resisting a prompt.

Raw results (including a handEditSurvived field that is false in both arms, because the task is to rewrite that very field): https://github.com/minjikim89/redline/tree/main/evals/results

Where this sits, and what it does not cover

Implementation and error shapes: https://github.com/minjikim89/redline/blob/main/docs/pattern.md
Full notes from building against the spec: https://github.com/minjikim89/redline/blob/main/docs/findings.md
Live: https://minjikim89.github.io/redline/

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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