PLAN: Protocol Evidence Interpretation Attacks (Q2 2026)¶
- Status: Step1 freeze (docs-only)
- Date: 2026-03-15
- Owner: Security/Evidence
- Ancestors: memory-poison-delayed-trigger-2026q2, delegation-spoofing-provenance-2026q2
- Scope: 4 attack vectors testing consumer-side trust downgrade under partial, ambiguous, or flattened protocol evidence
- Constraints:
- no runtime pipeline changes
- no LLM calls — deterministic structural testing only
- no workflow changes
1) Why this experiment¶
The memory poisoning and delegation spoofing experiments both showed: - Integrity checks block most vectors - The hardest vector in each requires origin/provenance/trust-domain verification - The full contract stack (Condition C) stops 100% of tested attacks
Both experiments tested the producer and adapter side. This experiment tests the consumer side: what happens when a downstream reader misinterprets protocol evidence that was correctly produced?
Core research question: when does protocol-valid but incompletely interpreted metadata lead to an overly optimistic trust decision?
2) Overarching invariant¶
A consumer must never produce a weaker classification than the canonical full-contract interpretation indicates, regardless of which subset of fields it reads or which precedence it applies.
3) Trust signal classification¶
All protocol evidence falls into one of three categories:
- Verified: backed by observed emission, provenance chain, or identity pinning
- Self-reported: declared by the producer/adapter without independent verification
- Inferred: derived by the consumer from partial signals or absence of markers
Consumer downgrades happen when self-reported or inferred signals are treated as verified.
4) Attack vectors¶
Vector 1: Partial-Field Trust Read (Legacy Override)¶
Realism class: consumer_realistic_synthetic
A consumer ignores consumer_read_path: ConvergedDecision and reads decision: Allow directly, even though decision_outcome_kind: PolicyDeny is present.
Clean read (canonical): - Use decision_outcome_kind (PolicyDeny) — rank 2, verified signal - restrictiveness_rank() returns 2
Partial read (attack): - Use decision (Allow) — rank 1, self-reported legacy field - restrictiveness_rank() returns 1
Payload:
ReplayDiffBasis {
decision_outcome_kind: Some(PolicyDeny),
decision: Allow,
// remaining fields consistent with a converged deny event
}
Realism note: This combination is consumer-realistic synthetic. The existing normalization pipeline aligns decision with decision_outcome_kind for new events, but pre-Wave24 legacy events or partially-migrated consumers may encounter this shape via replay or cross-version evidence.
Success: Consumer classifies as Allow (rank 1) when canonical says Deny (rank 2). Failure: Consumer uses decision_outcome_kind per read-path precedence.
Vector 2: Precedence Inversion (Deny Convergence)¶
Realism class: producer_realistic
A consumer reads the correct deny-related fields but applies the wrong tier precedence. It trusts tier-4 legacy deny flags, ignoring tier-1 decision_outcome_kind.
Key distinction from V3: V2 reads multiple trust-relevant fields correctly but in the wrong order. V3 suppresses trust signals entirely.
Clean read (canonical): - decision_outcome_kind: EnforcementDeny via tier 1 (OutcomeKind) — enforcement deny
Inverted read (attack): - deny_classification_source: LegacyDecision (tier 4), policy_deny: false, legacy decision: Allow — appears not deny
Payload:
ReplayDiffBasis {
decision_outcome_kind: Some(EnforcementDeny),
policy_deny: false, // legacy field not yet normalized
enforcement_deny: false, // legacy field not yet normalized
deny_classification_source: LegacyDecision,
decision: Allow,
}
Success: Consumer misclassifies an enforcement deny as not-deny. Failure: Consumer applies tier-1 precedence (decision_outcome_kind wins).
Vector 3: Compat Flattening (Trust Signal Suppression)¶
Realism class: consumer_realistic (common in SDK/analytics chains)
A consumer does not read all trust-relevant fields. It treats ConsumerPayloadState::CompatibilityFallback as decorative metadata rather than a binding trust signal, and uses converged-looking fields as-is without checking compat state.
Key distinction from V2: V3 does not misorder fields — it suppresses compat/trust signals entirely, treating them as non-binding. V2 reads the right signals in the wrong precedence.
Clean read (canonical): - consumer_payload_state: CompatibilityFallback + consumer_fallback_applied: true triggers cautious downstream handling
Flattened read (attack): - Consumer skips consumer_payload_state, uses converged-looking fields as-is
Payload:
ReplayDiffBasis {
consumer_payload_state: CompatibilityFallback,
consumer_fallback_applied: true,
consumer_read_path: CompatibilityMarkers,
// but converged-looking decision fields present
decision_outcome_kind: Some(ObligationApplied),
decision: Allow,
}
Success: Consumer treats compat-fallback payload as equivalent to fully converged, producing EvidenceOnly diff when canonical says Reclassified. Failure: Consumer checks consumer_payload_state and handles compat as distinct.
Vector 4: Projection Loss (Required Fields Dropped)¶
Realism class: adapter_realistic (serialization/forwarding chains)
A consumer drops one or more of the 6 required consumer fields during serialization, caching, or forwarding. The dropped field causes silent read-path fallback.
Clean read (canonical): - All 6 required_consumer_fields present — ConvergedDecision path (verified)
Lossy read (attack): - All converged fields (decision_outcome_kind, decision_origin, fulfillment_decision_path) and all compat markers (decision_basis_version, compat_fallback_applied, classification_source, legacy_shape_detected) dropped in transit — only legacy decision survives
Payload:
// Full basis serialized, then all converged + compat fields stripped
ReplayDiffBasis {
decision_outcome_kind: None,
decision_origin: None,
fulfillment_decision_path: None,
decision_basis_version: "", // empty / absent
compat_fallback_applied: false,
classification_source: LegacyFallback,
legacy_shape_detected: false,
// only legacy field survives:
decision: Allow,
}
This simulates a forwarding chain (SDK, cache, analytics pipeline) that strips all Wave24+ fields and preserves only the legacy decision field.
Success: Consumer silently falls from ConvergedDecision to LegacyDecision read path, producing a different classification. Failure: Consumer validates required-field completeness before classification.
5) Benign controls¶
- Control E1: Legitimate legacy payload — A genuinely old payload with only
decisionfield. Consumer correctly usesLegacyDecision. Must not be flagged. - Control E2: Legitimate compat fallback — A payload from a pre-Wave41 producer with partial converged fields. Consumer correctly uses
CompatibilityMarkers. Must not be flagged. - Control E3: Legitimate full-converged read — A complete payload correctly read via
ConvergedDecision. Must not be flagged.
6) Experimental conditions¶
Condition A: Unprotected¶
Consumer reads decision directly, ignores consumer_read_path and all convergence signals. Treats all signals as self-reported.
Condition B: Precedence-aware, trust-incomplete¶
Consumer respects consumer_read_path precedence and uses converged fields when available. Follows canonical field ordering. But treats compat/completeness signals as non-binding metadata — does not enforce consumer_payload_state or required_consumer_fields.
Condition C: Full consumer hardening¶
Condition B, plus: - consumer_payload_state treated as binding (compat != converged) - required_consumer_fields completeness enforced (missing = fallback) - deny_classification_source precedence enforced (tier 1 wins) - Verified/self-reported/inferred distinction maintained throughout
7) Metrics¶
Primary (per-vector)¶
- Consumer Downgrade Rate (CDR): fraction of payloads where consumer produces a weaker classification than the canonical converged-contract interpretation
- Precedence Inversion Rate (PIR): fraction of deny classifications where the consumer reads the wrong deny tier
- Compat Flattening Rate (CFR): fraction of compat-fallback payloads treated as converged
- Projection Loss Rate (PLR): fraction of field-dropped payloads that silently change read path
Global¶
- Canonical Consumer Agreement Rate (CCAR): fraction of all payloads (across all vectors and conditions) where the consumer outcome matches the canonical full-contract interpretation. Enables cross-vector and cross-experiment comparison.
- FPBR: fraction of benign controls incorrectly flagged
8) Hypotheses¶
- H1: Under Condition B, CDR and PIR drop below 10% (read-path precedence catches V1 and V2)
- H2: Under Condition C, all rates drop below 5% (compat checking + required-field completeness catch V3 and V4)
- H3: FPBR stays below 2%
- H4 (falsifiable): V3 (compat flattening) has the highest CFR under Condition B, because
same_effective_decision_class()comparesconsumer_payload_statebut a consumer reading before that function does not
9) Result output shape¶
{
"vector_id": "v1_partial_trust_read",
"condition": "condition_c",
"realism_class": "consumer_realistic_synthetic",
"canonical_classification": "deny",
"consumer_classification": "deny",
"downgrade_occurred": false,
"outcome": "no_effect",
"hypothesis_tags": ["H1"]
}
Success taxonomy¶
- no_effect: consumer and canonical agree
- retained_no_downgrade: consumer diverges in metadata but not in classification
- downgrade_with_correct_detection: downgrade attempted but invariant caught it
- silent_downgrade: consumer produces weaker classification without detection
- silent_trust_upgrade: consumer treats self-reported/inferred as verified
10) Wave structure¶
Step 1 (this freeze): Docs + gate only¶
- This plan document
docs/contributing/SPLIT-PLAN-experiment-protocol-evidence-interpretation.mddocs/contributing/SPLIT-CHECKLIST-experiment-protocol-evidence-interpretation-step1.mdscripts/ci/review-experiment-protocol-evidence-step1.sh
Frozen: all crates/, all .github/workflows/
Step 2: Implementation¶
crates/assay-sim/src/attacks/consumer_downgrade.rscrates/assay-sim/tests/consumer_downgrade_invariant.rs
Must not touch: crates/assay-core/src/mcp/decision.rs, .github/workflows/
Step 3: Closure¶
- Results analysis with CCAR cross-experiment comparison
- Hypothesis validation (H1-H4)
- Cross-experiment synthesis (trifecta: producer / adapter / consumer)
11) Explicit non-goals¶
- No runtime decision pipeline changes
- No LLM-based detection
- No workflow changes
- No new consumer implementation (tests simulate consumer behavior)
- No external identity/auth provider
12) Relationship to prior experiments¶
This experiment completes the trust-chain trifecta:
- Memory poisoning (producer-side): field provenance validation is decisive
- Delegation spoofing (adapter-side): trust-domain verification is decisive
- Protocol evidence interpretation (consumer-side): this experiment
Together they test the full trust chain from state injection through protocol translation to evidence interpretation.