# Trust Labels

*Two small labels plus session taint enforce the Rule of Two.*

> **Trust Labels** are two very small label sets attached to data, **origin** (`owner`, `agent`, `external`) and **sensitivity** (`public`, `private`, `secret`), plus **session taint**. The NAS enforces the Rule of Two as a session invariant: a session cannot have all of [A] has read external content, [B] touches sensitive data and [C] changes protected state or communicates outward. Completing the third requires a [Human Gate](https://agentnas.com/concepts/human-gate/).

**AN-06** · Conformance level: L3 Guard · Cluster: Authority

## The problem

Prompt injection works because a model cannot tell “instructions” from “data”. Defences at the model layer (classifiers, prompt hardening) leak, and attackers can adapt. At the end of October 2025 Meta proposed the [Agents Rule of Two](https://ai.meta.com/blog/practical-ai-agent-security/): until injection is reliably solved, a session should have at most two of three properties.

The more dependable approach is to bound the consequences **outside** the model. Storage is exactly where every read and write passes, so it is a natural place to turn this rule into a testable invariant.

## How it works

- **Labels.** Three origins, three sensitivities and a `reviewed` flag (set by a gate approval). Import points (web pages, email, uploads) default to `external`; when a secret scanner finds credentials, it labels them `secret` automatically.
- **Session taint.** The summary of everything a run has read (from the read manifest); within a session it only grows, and a new session starts clean.
- **The invariant.** A = the session has read `external`; B = the lease may read `private` or above (threshold configurable); C = the lease may propose a merge into a protected tree, share, delete or send data out. When all three hold in one session, the call that triggers C is denied or sent to a gate.
- **In practice:** under a lease that has both B and C, once a session has read external content, every later C-type action needs a person. To avoid that friction, do the “read external content” work in a separate session without B and pass results on through a structured handoff only.
- **Propagation.** Derivations made by the NAS itself (indexes, summaries) deterministically inherit the union of their input labels; files a run writes inherit the run’s session taint (the conservative choice).
- **Declassification.** Only through a Human Gate, or a **structured handoff:** the output of the tainted session is restricted to fields validated by a JSON Schema (enums, IDs, bounded strings), and only after validation may a privileged session read it. Only what can be validated deterministically can be trusted.
- **Enforcement is at the gateway and the mount** (which know the lease and the session), not inside the model.

## Start small

- Do just two things: label files in the import directory `external`, and by default give a run that has read `external` no egress and no protected merge without a gate.
- Write the policy as deterministic rules in Cedar or Rego, and give readable reasons on denial.
- Run in “log only” mode for a week to see what it would block by mistake, then switch enforcement on.

## Interface sketch

Illustrative only. Field names may change before specification v0.3.

*policy.yaml*

```yaml
# Deterministic policy (Cedar- or Rego-style rules can express the same thing)
session_invariant: rule_of_two
properties:
  A: session.read_origin includes "external"
  B: lease.sensitivity_max >= "private"
  C: lease allows propose_protected | share | delete | egress
on_would_complete_ABC: gate        # never "allow"
rules:
  - id: r-merge-1
    when: session.A and op == "merge" and target.protected
    then: gate
  - id: r-secret-1
    when: session.read_sensitivity == "secret" and op == "egress"
    then: deny
```

## What the specification asks for

- Every import point MUST assign a default label; external content MUST be labelled `external`.
- Session taint MUST only grow within a session.
- Policy evaluation MUST be deterministic and MUST NOT call an LLM.
- A call that would let a session complete A+B+C MUST be denied or sent to a gate.
- Declassification MUST go through a gate or a schema-validated structured handoff.
- Derived data MUST inherit the union of its input labels.

## Borrowed, and what is new

What follows is all established thinking. **What is new:** implementing session taint at the **storage boundary** with the read manifest, and applying labels to memory writes and derived data. We deliberately keep the label lattice to 3×3 because fine-grained lattices lead to label explosion in practice. OpenClaw already does origin labels and isolation inside a single runtime; our difference is only to put this in shared storage.

- [Agents Rule of Two (Meta)](https://ai.meta.com/blog/practical-ai-agent-security/)
- [The lethal trifecta](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/)
- [CaMeL](https://arxiv.org/abs/2503.18813)
- [Fides](https://arxiv.org/abs/2505.23643)
- [Design Patterns for Securing LLM Agents against Prompt Injections](https://arxiv.org/abs/2506.08837)
- [OpenClaw memory architecture](https://docs.openclaw.ai/concepts/memory-architecture)

## Honest limits

- This is **not** a defence against prompt injection; it limits consequences.
- The NAS cannot see tools outside it (a browser, email), so it needs the runtime’s cooperation.
- Taint is conservative and brings friction and false positives; free text outside structured schemas can still carry an attacker’s words.
- Covert channels cannot be eliminated.

## Open questions

- Should the granularity of a label be the file or the paragraph?
- How is the label vocabulary governed across tenants?
- How can false positives be reduced?

## Questions

### Does the Rule of Two stop prompt injection?

It does not stop injection from happening. It makes an injected session **unable to have all three** of “has read untrusted content, touches sensitive data, can change protected state or send data out”, which bounds the consequences. Meta itself stresses that it is a risk-reduction heuristic that does not replace least privilege.

### Why only three origins and three sensitivities?

Because fine-grained label lattices tend to bloat and get switched off in practice. 3×3 is enough to say “who wrote it, how sensitive it is” and makes the reason for a refusal easy to understand. Finer partitions can be done with paths and leases.

### Will session taint leave the agent unable to do anything?

It only restricts three kinds of action: changing a protected tree, sharing or deleting, and sending data out. Reads and writes inside a branch are unaffected. To avoid friction, put the work of reading external content into a session without sensitive data and pass back only results validated against a schema.

## Related concepts

- [Human Gate](https://agentnas.com/concepts/human-gate/): Appears only before irreversible, outward-facing or privilege-raising actions, and shows the real diff.
- [Agent Memory](https://agentnas.com/concepts/agent-memory/): Notes you can read and edit are the truth. Indexes are a cache you can throw away.
- [Capability Lease](https://agentnas.com/concepts/capability-lease/): A narrow authorization for one run, with an expiry and budgets. Child leases can only be narrower.

---

Canonical URL: https://agentnas.com/concepts/trust-labels/
Updated: 2026-11-11 · Draft specification v0.2 · CC BY 4.0
