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: Hashes are collected into Merkle trees at regular intervals
  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

What Gets Anchored

Issue Lifecycle

  • Issue creation, updates, and deletion
  • Status transitions and workflow changes
  • Comment additions and modifications
  • Attachment uploads

AI Operations

  • AI agent invocations and decisions
  • Auto-assignment recommendations
  • Generated content and suggestions
  • Model performance metrics

Configuration Changes

  • Workflow definition updates
  • Extension installations and settings
  • Project settings modifications
  • Organization-wide configuration

Security Events

  • User permission changes
  • API key management
  • OAuth connection changes
  • GitHub sync operations

Notification Dispatches

  • Email notification dispatches
  • Slack notification dispatches
  • Webhook notification dispatches
  • Links to source audit logs for transitive verification

All three audit models (AuditLog, AIAuditLog, NotificationAuditLog) compute SHA-256 content hashes at creation time and are included in the Merkle tree anchoring.

Anchoring Frequency

Plan Standard High-Frequency Immediate
Starter Hourly -- --
Professional Hourly 15 minutes --
Enterprise Hourly 15 minutes Configurable

High-Frequency Anchoring (Professional+)

Organizations with compliance requirements can enable 15-minute anchoring intervals for faster verification times.

Immediate Anchoring (Enterprise)

Critical actions can trigger immediate anchoring (within a 5-minute batched window):

  • Role changes (user permissions modified)
  • Approval decisions (granted or denied)
  • API key creation/revocation
  • Secret management operations

Viewing Anchors

Admin Dashboard

Organization admins can view blockchain anchoring status at /blockchain:

  • Total Anchors -- Number of Merkle roots submitted
  • Confirmed -- Successfully verified on-chain
  • Pending -- Awaiting blockchain confirmation
  • Failed -- Needs retry (automatic)

Activity Log

Users can view their organization's audit trail at /audit_trail:

  • Filter by action type, resource, or date range
  • See blockchain verification status for each action
  • Export personal audit history

Record Badges

Throughout the application, look for blockchain status indicators:

  • Verified (green chain icon) -- Record is blockchain-anchored
  • Pending (yellow clock icon) -- Awaiting next anchor batch

CLI Commands

# 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

Verifying Records

Verification confirms that:

  1. A record's content hash exists in a Merkle tree
  2. That Merkle root was submitted to the Polygon blockchain
  3. The transaction was confirmed with sufficient block confirmations
  4. The record content matches its original hash

Public Verification Page

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

Web Interface

Visit /audit_trail/verify to use the verification tool:

  1. By Content Hash -- Enter the SHA-256 hash of the record content
  2. By Record Reference -- Select the record type and ID

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..."
  }'

Response:

{
  "verified": true,
  "anchor": {
    "id": 123,
    "merkle_root": "0xdef456...",
    "tx_hash": "0x789abc...",
    "block_number": 12345678,
    "confirmed_at": "2026-01-15T10:30:00Z",
    "network": "polygon_mainnet",
    "explorer_url": "https://polygonscan.com/tx/0x789abc..."
  },
  "proof": {
    "leaf_index": 42,
    "proof_path": ["0xaaa...", "0xbbb...", "0xccc..."]
  }
}

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
)

Independent Verification

You can verify proofs independently without trusting Kiket:

  1. Get the proof data from the API or compliance export
  2. Recompute the Merkle root using the content hash and proof path
  3. Check the blockchain for the anchor transaction
  4. Verify the Merkle root in the transaction matches your computation
// Example: Independent Merkle proof verification
const crypto = require('crypto');

function verifyProof(contentHash, proofPath, expectedRoot) {
  let current = contentHash;

  for (const sibling of proofPath) {
    // Sort hashes for consistent ordering
    const pair = [current, sibling].sort();
    current = crypto
      .createHash('sha256')
      .update(Buffer.from(pair[0] + pair[1], 'hex'))
      .digest('hex');
  }

  return current === expectedRoot;
}

Understanding Verification Results

Result Meaning
Verified Record is confirmed on the blockchain with anchor ID, Merkle root, transaction hash, block number, and explorer link
Not Found Record hasn't been anchored yet, invalid hash format, or record doesn't exist
Verification Failed Merkle proof doesn't match -- contact support if unexpected

Verification for Compliance

For compliance audits, you may need to demonstrate:

  1. Chain of custody -- Export the full audit trail with proofs
  2. Independent verification -- Auditors can verify proofs themselves
  3. Blockchain transparency -- All transactions are public on Polygon

See Compliance Reports for generating exportable reports with embedded proofs.


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.

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"
  }
}

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.

Troubleshooting

"Record not found"

  • Ensure the content hash is correctly formatted (64 hex characters)
  • Check if the record type and ID are valid
  • The record may be pending anchoring

"Anchor not confirmed"

  • The transaction is submitted but awaiting confirmations
  • Wait 5-10 minutes and retry
  • Check network status on Polygonscan

"Verification failed"

  • Contact support -- this indicates a potential data integrity issue
  • Provide the content hash and anchor ID for investigation

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.