VerificationBenchmarksPricingDemo
Log InGet API Key

Tampered Receipt Detection

Version: 1.0.0
Status: Production
Last Updated: 2026-05-23
Editor: Eric Beans, H33.ai, Inc.
Canonical URL: https://h33.ai/verification/tampered-receipt/

1. Scope

This walkthrough demonstrates how a HATS verifier detects post-signing modification of a governance node. The input bundle is identical to the valid bundle in HATS-VW-001, except that node 1's action_type field has been changed from COMPUTE_EXECUTE to DATA_EXPORT after the node was signed. This modification invalidates the node hash and, consequently, all signatures over that hash.

The expected verifier output is FAILED, with the failure localized to node 1.

2. Definitions

Canonical Serialization
The deterministic byte representation of a governance node. Field order is fixed by the schema: node_index, action_type, payload_hash, timestamp, predecessor_hash. Whitespace is normalized. Changing any field produces a different serialization and therefore a different hash.
Node Hash Mismatch
The condition where the recomputed SHA3-256 digest of a node's canonical serialization does not match the declared node_hash field. Indicates that the node's content was modified after the hash was computed.
Post-Signing Modification
Any change to a governance node's content after its signatures were generated. Because signatures are computed over the node_hash, and the node_hash is computed over the canonical serialization, any content change invalidates both the hash and all signatures.

3. Tampered Input

The following bundle is identical to the valid bundle except for node 1. The action_type field has been changed. The modification is highlighted below.

tampered-receipt.json (node 1 excerpt)
{ "node_index": 1, "action_type": "COMPUTE_EXECUTE", "action_type": "DATA_EXPORT", "payload_hash": "d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4", "timestamp": "2026-05-15T14:30:01.247Z", "predecessor_hash": "c7a8b9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7", "node_hash": "e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5", "signatures": { "ml_dsa_65": "ML-DSA-65:3045022100...truncated...c9d0e1f2a3", "falcon_512": "FALCON-512:3045022100...truncated...b2c3d4e5f6", "slh_dsa": "SLH-DSA-SHA2-128f:3045022100...truncated...a7b8c9d0e1" } }

The attacker changed COMPUTE_EXECUTE to DATA_EXPORT but did not (and could not, without the private keys) recompute the node_hash or re-sign the node. The node_hash and all three signatures still correspond to the original COMPUTE_EXECUTE content.

4. CLI Command

$ hats verify tampered-receipt.json

5. Detection Mechanism

5.1. Hash Recomputation

The verifier computes the canonical serialization of node 1 using the current field values (including the tampered action_type = DATA_EXPORT). It then computes SHA3-256 over this serialization.

ValueSHA3-256 Digest
Declared node_hashe5f6a7b8c9d0e1f2a3b4c5d6e7f8...d4e5
Recomputed (with DATA_EXPORT)1a2b3c4d5e6f7a8b9c0d1e2f3a4b...8c9d

The digests differ. The verifier reports a node hash mismatch at node 1.

5.2. Cascade Effects

Once the node hash mismatch is detected, the verifier also notes that:

  1. All three signatures on node 1 will fail verification, because they were computed over the original (correct) node_hash, not the recomputed digest.
  2. Node 2's predecessor_hash chain remains intact (it references node 1's declared node_hash, which has not been changed). However, the declared node_hash itself is invalid, so the chain is semantically broken even though the predecessor link is syntactically correct.

The verifier halts at the first failure by default. With --continue-on-error, it reports all failures but still returns a non-zero exit code. The hash mismatch is always reported before signature failures because hash verification precedes signature verification in the check order.

6. Expected Output

stdout
$ hats verify tampered-receipt.json HATS Verifier v1.0.0 Bundle: b8f3c2a1-4e5d-4a6b-9c8d-7e6f5a4b3c2d Session: s-20260515-143000-a1b2c3 Checking schema .............. OK Checking chain integrity ..... OK (3 links) Checking node hashes ......... FAILED Node 1 [DATA_EXPORT]: hash mismatch declared: e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5 recomputed: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0a1 Result: FAILED Failure: NODE_HASH_MISMATCH at node 1 Field: action_type (declared: DATA_EXPORT) Impact: All signatures on node 1 are invalid (signed over different content) Duration: 12ms

7. JSON Output

{ "status": "FAILED", "bundle_id": "b8f3c2a1-4e5d-4a6b-9c8d-7e6f5a4b3c2d", "failure": { "type": "NODE_HASH_MISMATCH", "node_index": 1, "action_type": "DATA_EXPORT", "declared_hash": "e5f6a7b8c9d0e1f2...d4e5", "recomputed_hash": "1a2b3c4d5e6f7a8b...e0a1", "message": "Node 1 canonical serialization hash does not match declared node_hash. Content was modified after hashing." }, "nodes_checked": 2, "nodes_passed": 1, "duration_ms": 12 }

8. Why This Attack Fails

The HATS governance model binds content to cryptographic identity through a two-layer commitment:

  1. Layer 1: Hash binding. The node_hash is the SHA3-256 digest of the node's canonical serialization. Changing any field changes the serialization, which changes the digest, which creates a mismatch with the declared node_hash.
  2. Layer 2: Signature binding. All three PQ signatures are computed over the node_hash. Even if an attacker recomputes the node_hash after modification, they cannot produce valid signatures without the private keys for all three families.

An attacker would need to compromise ML-DSA-65, FALCON-512, and SLH-DSA-SHA2-128f private keys simultaneously to forge a tampered node that passes verification. This requires breaking three independent post-quantum hardness assumptions.

9. Failure Mode Summary

CheckStatusDetail
Schema validationPASSDATA_EXPORT is a valid action type
Chain integrityPASSPredecessor hashes link correctly (syntactically)
Node 0 hashPASSUnmodified node
Node 1 hashFAILHash mismatch: content changed post-hashing
Node 1 ML-DSA-65FAILSignature over wrong hash (skipped: hash already failed)
Node 1 FALCON-512FAILSignature over wrong hash (skipped: hash already failed)
Node 1 SLH-DSAFAILSignature over wrong hash (skipped: hash already failed)
Node 2 hashSKIPPEDVerification halted at node 1

Conformance test vector ID: HATS-VW-002-TAMPERED-RECEIPT