pub struct Taint {
pub private: bool,
pub untrusted: bool,
}Expand description
What has entered this conversation so far.
The lethal trifecta only bites when all three are present at once: private data, untrusted content, and a way to send. Two of them are properties of the transcript, so they are tracked here; the third is a property of the tool about to run.
Fields§
§private: boolA tool has returned data the user considers private.
untrusted: boolA tool has returned content a third party could have written — which is to say, possible instructions from an attacker.
Implementations§
Source§impl Taint
impl Taint
Sourcepub fn trifecta_armed(&self) -> bool
pub fn trifecta_armed(&self) -> bool
True once an outbound tool could be used to exfiltrate.
Sourcepub fn arm_for_content(&mut self, messages: &[Message])
pub fn arm_for_content(&mut self, messages: &[Message])
Arm the private leg for content that entered the conversation without a tool call — today, an image the user attached.
A screenshot is captured, not composed, and that is the whole argument. Inbound text arms nothing because the user chose every word of it; the same reasoning does not reach a screenshot, where the user chose the window and not everything in it. Incidental private data is the normal case rather than the exception — it is most of why people screenshot instead of retyping.
It also keeps the posture of an unchanged user action unchanged.
Before images existed, attaching one in Slack armed private because
the model had to fs_read it; putting the pixels on the user turn
removed the tool call and, with it, the taint. A feature that
silently loosens the interlock as a side effect is the shape this
project keeps finding, and the fix belongs here rather than in a note
asking front-ends to remember.