Merkle tree construction for tamper-evident audit logs. Build Merkle root from audit log hashes, proof generation and verification, incremental append, and integrating with secure-logger.sh for L0 hash-chain integrity. Sources: miguelmota/merkletreejs.
Scanned 9/9/2026
Install to Claude Code
npx -y skills add yanacuti1121/Yana-AI --skill merkle-tree-audit --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Merkle Tree Audit?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/yanacuti1121-merkle-tree-audit-yana-ai)More formats (shields.io, HTML) on the badges page.
---
name: merkle-tree-audit
description: Merkle tree construction for tamper-evident audit logs. Build Merkle root from audit log hashes, proof generation and verification, incremental append, and integrating with secure-logger.sh for L0 hash-chain integrity. Sources: miguelmota/merkletreejs.
origin: yana-ai — synthesized from miguelmota/merkletreejs (MIT)
license: Apache-2.0
version: 1.0.0
compatibility: yana-ai >= 1.3.49
---
# /merkle-tree-audit
## When to Use
- Convert secure-logger.sh audit log entries into a Merkle tree root hash
- Prove a specific log entry exists in the audit log without revealing all entries
- Detect any modification to historical audit entries (root hash changes)
- Build tamper-evident audit checkpoints for regulatory compliance
## Do NOT use for
- Real-time log streaming (Merkle tree is built on completed log batches)
- Replacing append-only storage (use [[append-only-hypercore]] for that)
---
## Build Merkle tree from log hashes
```javascript
import { MerkleTree } from 'merkletreejs'
import { createHash } from 'crypto'
import { readFileSync } from 'fs'
function sha256(data: string): Buffer {
return createHash('sha256').update(data).digest()
}
function buildAuditTree(logFile: string): { root: string; tree: MerkleTree } {
const lines = readFileSync(logFile, 'utf8').trim().split('\n').filter(Boolean)
const leaves = lines.map(line => sha256(line))
const tree = new MerkleTree(leaves, sha256, {
sortPairs: true, // deterministic — order-independent root
hashLeaves: false, // leaves are already hashed
})
return { root: tree.getRoot().toString('hex'), tree }
}
const { root, tree } = buildAuditTree('releases/logs/agent-audit.json')
console.log('[merkle] audit root:', root)
```
---
## Generate proof for a specific entry
```javascript
function proveEntry(
tree: MerkleTree,
logLine: string
): { proof: string[]; valid: boolean } {
const leaf = sha256(logLine)
const proof = tree.getProof(leaf).map(p => ({
data: p.data.toString('hex'),
position: p.position,
}))
const root = tree.getRoot()
const valid = tree.verify(tree.getProof(leaf), leaf, root)
return { proof: proof.map(p => p.data), valid }
}
```
---
## Verify proof independently
```javascript
function verifyEntryProof(
logLine: string,
proofHexes: string[],
rootHex: string
): boolean {
const leaf = sha256(logLine)
const root = Buffer.from(rootHex, 'hex')
const proof = proofHexes.map(h => ({ data: Buffer.from(h, 'hex') }))
const tree = new MerkleTree([], sha256, { sortPairs: true })
return tree.verify(proof, leaf, root)
}
```
---
## Periodic checkpoint in secure-logger.sh
```bash
#!/usr/bin/env bash
# checkpoint-audit.sh — build Merkle root from today's audit log
LOG_FILE="releases/logs/agent-audit-$(date +%Y-%m-%d).json"
CHECKPOINT_FILE="releases/logs/merkle-checkpoints.json"
if [[ ! -f "$LOG_FILE" ]]; then
echo "[checkpoint] no log for today"
exit 0
fi
ROOT=$(node -e "
const { MerkleTree } = require('merkletreejs')
const { createHash, readFileSync } = require('crypto'), fs = require('fs')
const lines = fs.readFileSync('$LOG_FILE','utf8').trim().split('\n').filter(Boolean)
const leaves = lines.map(l => createHash('sha256').update(l).digest())
const tree = new MerkleTree(leaves, d => createHash('sha256').update(d).digest(), { sortPairs: true })
console.log(tree.getRoot().toString('hex'))
")
TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "{\"ts\":\"$TS\",\"log\":\"$LOG_FILE\",\"root\":\"$ROOT\"}" >> "$CHECKPOINT_FILE"
echo "[checkpoint] root=$ROOT"
```
---
## Anti-Fake-Pass Checklist
```
❌ sortPairs:false → root depends on insertion order → non-deterministic between restarts
❌ hashLeaves:true when leaves already hashed → double-hashed, proof verification fails
❌ Empty log file → empty tree → root is empty string, not a valid checkpoint
❌ Proof verified against stale root → passes even if tree was rebuilt with modifications
❌ No checkpoint persistence → root lost on restart, cannot verify historical entries
❌ Merkle root alone without timestamp → cannot determine which log version was attested
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!