Skip to content

Blockchain Audit Trails

Kiket anchors audit logs to the Polygon blockchain for tamper-proof verification. This provides cryptographic proof that your audit records have not been modified since creation.

How It Works

  1. Content Hashing: Every audit record is SHA-256 hashed at creation time
  2. Merkle Trees: Hourly, hashes are collected into Merkle trees
  3. Blockchain Anchoring: Merkle roots are submitted to Polygon
  4. Verification: Anyone can verify a record's inclusion without accessing your data
┌─────────────────────────────────────────────────────────┐
│                    Merkle Root                          │
│              (anchored to Polygon)                      │
├───────────────────────┬─────────────────────────────────┤
│       Hash AB         │         Hash CD                 │
├───────────┬───────────┼───────────┬─────────────────────┤
│  Hash A   │  Hash B   │  Hash C   │      Hash D         │
│ Record 1  │ Record 2  │ Record 3  │     Record 4        │
└───────────┴───────────┴───────────┴─────────────────────┘

Benefits

  • Tamper-Proof: Blockchain immutability prevents record modification
  • Independent Verification: Auditors verify proofs without Kiket access
  • Public Transparency: Transaction history viewable on PolygonScan
  • Compliance Ready: SOC 2, ISO 27001, and GDPR compliant audit trails

Verification Methods

Public Verification Page

Visit kiket.dev/verify to verify any proof without logging in.

API Verification

curl -X POST https://api.kiket.dev/v1/audit/verify \
  -H "Content-Type: application/json" \
  -d '{
    "content_hash": "0x7f83b165...",
    "merkle_root": "0x3a4e8c2b...",
    "proof": ["0x1234...", "0x5678..."],
    "leaf_index": 127,
    "tx_hash": "0x9a8b7c6d..."
  }'

CLI Verification

# Verify a proof file
kiket audit verify proof.json

# Verify locally (offline)
kiket audit verify proof.json --local

# Get proof for an AuditLog record (default)
kiket audit proof 12345 --format=file --output=proof.json

# Get proof for an AIAuditLog record
kiket audit proof 12345 --type=AIAuditLog --format=file --output=proof.json

SDK Verification

from kiket_sdk.audit import AuditClient

audit = AuditClient(client)

# Get proof for an AuditLog record
proof = await audit.get_proof(record_id=12345)

# Get proof for an AIAuditLog record
ai_proof = await audit.get_proof(record_id=67890, record_type="AIAuditLog")

# Verify via API
result = await audit.verify(proof)
print(f"Verified: {result.verified}")

# Verify locally (offline)
valid = AuditClient.verify_proof_locally(
    content_hash=proof.content_hash,
    proof_path=proof.proof,
    leaf_index=proof.leaf_index,
    merkle_root=proof.merkle_root
)
import { AuditClient } from '@kiket/sdk';

const audit = new AuditClient(httpClient);

// Get proof for an AuditLog record
const proof = await audit.getProof(12345);

// Get proof for an AIAuditLog record
const aiProof = await audit.getProof(67890, 'AIAuditLog');

// Verify via API
const result = await audit.verify(proof);
console.log(`Verified: ${result.verified}`);

// Verify locally (offline)
const valid = AuditClient.verifyProofLocally(
  proof.content_hash,
  proof.proof,
  proof.leaf_index,
  proof.merkle_root
);
audit = KiketSdk::AuditClient.new(client)

# Get proof for an AuditLog record
proof = audit.get_proof(12345)

# Get proof for an AIAuditLog record
ai_proof = audit.get_proof(67890, record_type: "AIAuditLog")

# Verify via API
result = audit.verify(proof)
puts "Verified: #{result.verified}"

# Verify locally (offline)
valid = KiketSdk::AuditClient.verify_proof_locally(
  content_hash: proof.content_hash,
  proof_path: proof.proof,
  leaf_index: proof.leaf_index,
  merkle_root: proof.merkle_root
)

Viewing Anchors

List Anchors

# List recent anchors
kiket audit anchors

# Filter by status
kiket audit anchors --status=confirmed

# JSON output
kiket audit anchors --format=json

Check Audit Status

kiket audit status

Output:

Blockchain Audit Status
========================================

Recent Anchors (last 5):
  Confirmed: 5
  Pending:   0
  Submitted: 0
  Failed:    0

Latest Anchor:
  Merkle Root: 0x7f83b1657ff1fc53b92dc18...
  Records:     847
  Status:      confirmed
  Network:     polygon_mainnet
  Explorer:    https://polygonscan.com/tx/0x...

Network Configuration

Environment Network Chain ID Explorer
Development Polygon Amoy (testnet) 80002 amoy.polygonscan.com
Production Polygon Mainnet 137 polygonscan.com

Pricing

Blockchain anchoring is included in Starter and above plans:

Plan Monthly Anchors Overage
Free Not included -
Starter 100 $0.10/anchor
Professional 1,000 $0.08/anchor
Enterprise Unlimited -

Smart Contract

The AuditAnchor contract is deployed at:

  • Polygon Amoy: 0x... (testnet)
  • Polygon Mainnet: 0x... (production)

Contract source is available in the kiket repository.

FAQ

How often are records anchored?

Records are batched and anchored every hour. Each anchor can contain up to 10,000 records.

Can I verify without Kiket access?

Yes. The proof contains all information needed for independent verification. Use the public verification page or verify locally with the SDK.

What happens if anchoring fails?

Failed anchors are retried automatically. If an anchor fails 3 times, it's marked as failed and an alert is sent.

Is my data visible on the blockchain?

No. Only cryptographic hashes (Merkle roots) are stored on-chain. The actual audit content remains private in Kiket.

Which audit events are included?

Three types of records are anchored to the blockchain:

AuditLog (general audit trail): - Role changes - User additions/removals - AI data scope updates - AI assignment actions - Secret operations

AIAuditLog (AI operation audit trail): - LLM invocations (task generation, code review, etc.) - Token usage and costs - Model responses and metadata - Developer Aide Suite operations

NotificationAuditLog (notification dispatch audit trail): - Email notification dispatches - Slack notification dispatches - Webhook notification dispatches - Links to source audit logs for transitive verification

All three models compute SHA-256 content hashes at creation time and are included in the hourly Merkle tree anchoring.

Notification Verification

Kiket includes blockchain verification links in notification emails, allowing recipients to independently verify that a notification was legitimately sent by the platform.

How It Works

  1. When an email notification is sent, a NotificationAuditLog is created
  2. The audit log includes a reference to the source action that triggered the notification
  3. A verification URL is included in the email footer
  4. Recipients can click the link to verify the notification's authenticity

All blockchain-verified emails include a footer:

This email is blockchain-verified. Verify authenticity: https://kiket.dev/verify/0x7f83b165...

Transitive Verification

Notification audit logs reference their source audit log, enabling transitive verification:

  1. Verify the notification was sent (NotificationAuditLog)
  2. Click through to verify the action that triggered it (AuditLog)

This proves not only that the notification was sent, but also that the underlying action actually occurred.

Verification Page

Visit the verification URL to see:

  • Verified: Record is anchored to blockchain with block number and transaction hash
  • Pending: Record exists but not yet anchored (anchoring happens hourly)
  • Not Found: No record matches the provided hash

Extension Webhook Payloads

Extension webhooks automatically receive audit context when available:

{
  "event": "workflow.after_transition",
  "issue": { ... },
  "audit_context": {
    "audit_log_hash": "0x7f83b1657ff1fc53b92dc18...",
    "verification_url": "https://kiket.dev/verify/0x7f83b165...",
    "blockchain_status": "pending"
  }
}

Extensions can include this verification URL in their own communications to provide end-to-end verification.