Skip to content

Merkle Tree Audit Logs

Merkle trees provide an efficient way to verify the integrity of audit logs using cryptographic hashing.

What is a Merkle Tree?

A Merkle tree is a binary tree where:

  • Leaf nodes contain hashes of individual data blocks (audit events)
  • Parent nodes contain hashes of their children
  • Root node (Merkle root) represents a cryptographic summary of all data
Merkle Tree Audit Log StructureROOTH(1,2)CombinedH(3,4)CombinedEvent 1LoginEvent 2ConnectEvent 3TransferEvent 4LogoutVerification Proof for Event 2Event 2Target+H(E1)Sibling+H(3,4)Sibling=ROOTMatch!Key BenefitsO(log n) verification complexityOnly 3 hashes needed to verify 1 of 4 eventsTamper-evident by designEfficient storage of proofs

Fig. 1 – Merkle tree structure showing events, combined hashes, and verification proof path

Why Use Merkle Trees?

Efficient Verification

To verify any single event, you only need:

  • The event itself
  • The path from that event to the root (O(log n) hashes)
  • NOT the entire dataset

For 1 million events, you only need ~20 hashes to verify any single event.

Tamper Detection

If any event is modified:

  1. Its hash changes
  2. Parent hash changes
  3. All ancestors change up to the root
  4. Merkle root no longer matches

Snapshot Integrity

The Merkle root serves as a cryptographic fingerprint of the entire audit log at a point in time.

How InTunnel Uses Merkle Trees

Event Hashing

Each audit event is hashed:

python
event_hash = SHA256(
    event_id + 
    event_type + 
    timestamp + 
    user_id + 
    ip_address + 
    json(details) +
    previous_hash
)

Tree Construction

Events are grouped into batches and tree is built bottom-up:

python
def build_merkle_tree(events):
    # Hash all events
    leaves = [sha256(event) for event in events]
    
    # Build tree level by level
    while len(leaves) > 1:
        next_level = []
        for i in range(0, len(leaves), 2):
            left = leaves[i]
            right = leaves[i+1] if i+1 < len(leaves) else left
            next_level.append(sha256(left + right))
        leaves = next_level
    
    return leaves[0]  # Merkle root

Creating Snapshots

Administrators can create Merkle snapshots to capture the audit log state:

bash
curl -X POST https://intunnel.cloud/api/security/merkle-snapshot \
  -H "Cookie: session=YOUR_ADMIN_SESSION"

Response:

json
{
  "success": true,
  "snapshot": {
    "merkle_root": "a3f2b8c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9...",
    "event_count": 15432,
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

Verification Process

Verifying a Single Event

To verify event "B" exists and hasn't been modified:

        Root: H(AB+CD)

    ┌───────┴───────┐
    │               │
  H(AB)          H(CD)  ◄─── Need this

┌───┴───┐
│       │
H(A)   H(B)  ◄─── Have this
 │      │
 ▼      ▼
(A)    [B]   ◄─── Verifying this

     Need H(A) to verify

Proof path for B:

  1. H(A) - sibling of B
  2. H(CD) - sibling of H(AB)

Verification:

  1. Compute H(B) from event B
  2. Compute H(AB) = hash(H(A) + H(B))
  3. Compute Root = hash(H(AB) + H(CD))
  4. Compare with stored Merkle root

API Usage

Query audit events:

bash
curl "https://intunnel.cloud/api/security/audit?limit=10" \
  -H "Cookie: session=YOUR_ADMIN_SESSION"

Response includes event hashes for verification:

json
{
  "events": [
    {
      "id": "evt_123456",
      "event_type": "USER_LOGIN",
      "timestamp": "2024-01-15T09:00:00Z",
      "user_id": "user_789",
      "hash": "a1b2c3d4e5f6..."
    }
  ]
}

Benefits Summary

BenefitDescription
Space EfficientO(log n) proof size
Fast VerificationO(log n) hash operations
Tamper EvidentAny change invalidates the root
Snapshot FriendlyRoot = fingerprint of entire log

TIP

Merkle trees are also used in Git, Bitcoin, and Ethereum for the same reasons - efficient, verifiable data integrity.

Released under the MIT License.