On-Chain Attestations
Attestations are the core Web3 primitive in Tamandua Sentinel. They create cryptographic, tamper-evident records of security events on the Solana blockchain without exposing sensitive telemetry.
What is an Attestation?
An attestation is a signed statement that a security event occurred. It contains:
- Cryptographic hashes proving the event's existence
- Metadata describing severity, technique, and timing
- Pseudonyms linking to organization/agent without identification
- Verification state tracking review status
- Bounty information for rule author rewards
Attestations are stored as Solana accounts (PDAs) or embedded in Memo Program transactions, depending on configuration.
Attestation Schema (v2)
The current attestation format includes:
{
"t": "tamandua_attestation",
"v": 2,
"ih": "incident_hash_hex",
"mh": "manifest_hash_hex",
"s": 4,
"m": "T1555.003",
"rh": "rule_hash_hex",
"op": "org_pseudonym_hex",
"ap": "agent_pseudonym_hex",
"ts": 1715180400,
"ic": 3,
"it": ["hash_sha256", "domain", "ip"],
"cf": 0.95,
"tlp": "amber",
"tc": "infostealer",
"mf": "redline_stealer"
}
Field Reference
| Field | Name | Type | Description |
|---|---|---|---|
t | Type | string | Attestation type identifier |
v | Version | integer | Schema version |
ih | Incident Hash | hex | SHA256 of redacted alert payload |
mh | Manifest Hash | hex | SHA256 of public IOC manifest |
s | Severity | 1-5 | 1=Info, 2=Low, 3=Medium, 4=High, 5=Critical |
m | MITRE Technique | string | ATT&CK technique ID |
rh | Rule Hash | hex | SHA256 of detection rule ID |
op | Org Pseudonym | hex | SHA256 of organization ID |
ap | Agent Pseudonym | hex | SHA256 of agent ID |
ts | Timestamp | unix | When incident occurred |
ic | IOC Count | integer | Number of public IOCs |
it | IOC Types | array | Types of IOCs included |
cf | Confidence | float | Detection confidence 0.0-1.0 |
tlp | TLP | string | Traffic Light Protocol (clear/amber) |
tc | Threat Class | string | infostealer/ransomware/c2/endpoint_threat |
mf | Malware Family | string | Optional family name |
Attestation Types
Incident Attestation
Created when a high-severity alert is generated:
# Automatically when alert is created (if enabled)
{:ok, alert} = Alerts.create_alert(params)
# Triggers: Attestation.attest_alert(alert)
# Or manually
{:ok, tx_signature} = TamanduaServer.Solana.Attestation.attest_alert(alert)
The attestation includes a full public manifest stored locally:
manifest = %{
schema: "tamandua.attestation_manifest",
version: 2,
tlp: "amber",
incident_hash: "abc123...",
severity: "high",
mitre_technique: "T1555.003",
rule_hash: "def456...",
ioc_count: 3,
ioc_types: ["hash_sha256", "domain"],
redacted_ioc_count: 4,
confidence: 0.95,
threat_class: "infostealer",
malware_family: "redline_stealer",
iocs: [
%{type: "hash_sha256", value: "abc...", source: "tamandua"},
%{type: "domain", value: "evil.com", source: "tamandua"}
]
}
Health Attestation
Created to prove endpoint monitoring posture:
posture = %{
window_started_at: ~U[2025-05-07 00:00:00Z],
window_ended_at: ~U[2025-05-08 00:00:00Z],
critical_alerts: 0,
high_alerts: 0,
active_alerts: 0
}
{:ok, tx_signature} = TamanduaServer.Solana.Attestation.attest_agent_health(agent, posture)
Health manifest format:
{
"t": "tamandua_health",
"v": 1,
"ph": "posture_hash_hex",
"op": "org_pseudonym_hex",
"ap": "agent_pseudonym_hex",
"st": "monitored",
"ca": 0,
"ha": 0,
"aa": 0,
"wh": 24,
"pp": "default",
"ts": 1715180400
}
Status values:
monitored- Endpoint healthy, no critical issuesat_risk- High-severity alerts presentcritical- Critical alerts presentnot_reporting- Endpoint offline during window
Fleet Health Attestation
Aggregates health across all endpoints for an organization:
{
"t": "tamandua_fleet",
"v": 1,
"fh": "fleet_hash_hex",
"op": "org_pseudonym_hex",
"st": "monitored",
"ta": 50,
"ca": 0,
"wa": 2,
"pp": "balanced",
"ts": 1715180400
}
Remediation Attestation
Created when a response action completes:
{
"t": "tamandua_remediation",
"v": 1,
"rh": "remediation_hash_hex",
"at": "quarantine",
"op": "org_pseudonym_hex",
"ap": "agent_pseudonym_hex",
"st": "success",
"ih": "incident_reference_hex",
"ts": 1715180400
}
Action types:
kill- Process terminatedquarantine- File quarantinedisolate- Host isolated from networkrollback- System restoredplaybook- Playbook completed
Creating Attestations
Automatic (Recommended)
Enable automatic attestation in your configuration:
# config/runtime.exs
config :tamandua_server, TamanduaServer.Alerts,
auto_attest: true,
attest_severity_threshold: "high" # Only high/critical alerts
Manual via API
# Create attestation for an alert
curl -X POST https://your-server/api/v1/alerts/{alert_id}/attest \
-H "Authorization: Bearer $TOKEN"
# Response
{
"data": {
"tx_signature": "5Uy3...",
"solscan_url": "https://solscan.io/tx/5Uy3...?cluster=devnet",
"attestation_hash": "abc123..."
}
}
Via Elixir
alias TamanduaServer.Solana.Attestation
# Attest an alert
{:ok, tx_signature} = Attestation.attest_alert(alert)
# Get Solscan URL
url = Attestation.solscan_url(alert)
# => "https://solscan.io/tx/5Uy3...?cluster=devnet"
# Check if already attested
Attestation.attested?(alert)
# => true
Batch Attestations
For high-volume deployments, attestations are batched:
alias TamanduaServer.Solana.RelayBatch
# Queue attestation for batch publication
{:ok, batch_info} = RelayBatch.queue_attestation(%{
ih: incident_hash,
s: 4,
m: "T1555.003",
rh: rule_hash,
op: org_pseudonym,
ap: agent_pseudonym,
ts: timestamp
})
# batch_info
%{
batch_id: "batch_57185",
position: 12,
queue_size: 12
}
# Check batch status
RelayBatch.status()
%{
enabled: true,
queue_size: 12,
batch_size: 50,
batch_interval_ms: 30000,
stats: %{
total_queued: 1234,
total_published: 1200,
total_batches: 24,
last_batch_at: ~U[2025-05-08 12:00:00Z]
}
}
Batch transactions combine up to 50 attestation hashes in a single Solana transaction, reducing costs to ~$0.00002 per attestation.
Privacy Guarantees
IOC Sanitization
Only these IOC types can appear in attestations:
| Type | Example | Allowed |
|---|---|---|
hash_sha256 | abc123... | Yes |
hash_sha1 | def456... | Yes |
hash_md5 | 789abc... | Yes |
domain | evil.com | Yes (public only) |
ip | 1.2.3.4 | Yes (public only) |
url | https://evil.com/payload | Yes (public only) |
hostname | victim-pc.local | No - Redacted |
username | john.doe | No - Redacted |
path | C:\Users\... | No - Redacted |
command_line | powershell -enc | No - Redacted |
Private IP/Domain Detection
# These are automatically filtered:
# Private IPs (RFC1918, localhost, link-local)
10.x.x.x # => Redacted
192.168.x.x # => Redacted
172.16-31.x.x # => Redacted
127.x.x.x # => Redacted
# Private domains
*.local # => Redacted
*.lan # => Redacted
*.internal # => Redacted
*.corp # => Redacted
Traffic Light Protocol
Attestations are classified by TLP:
- TLP:CLEAR - No IOCs redacted, all data is public
- TLP:AMBER - Some IOCs redacted, contains privacy-sensitive indicators
The TLP is determined automatically based on redaction count:
tlp = if redacted_ioc_count > 0, do: "amber", else: "clear"
Pseudonymization
Organization and agent IDs are never stored directly. Instead, SHA256 hashes are used:
def pseudonymize(id) when is_binary(id) do
:crypto.hash(:sha256, id)
end
# Example:
org_id = "org_abc123"
pseudonym = pseudonymize(org_id)
# => <<0x1a, 0x2b, ...>> # 32 bytes
# Displayed as: "1a2b3c4d..."
This ensures:
- Same org/agent always produces same pseudonym (for correlation)
- Pseudonym cannot be reversed to real ID
- Privacy preserved while allowing pattern analysis
Incident Hash Computation
The incident hash uniquely identifies an alert without exposing sensitive data:
def compute_incident_hash(alert) do
payload = [
to_string(alert.id),
to_string(alert.severity),
extract_mitre_technique(alert),
to_string(rule_id),
DateTime.to_iso8601(alert_timestamp),
pseudonymize(alert.organization_id) |> Base.encode16(case: :lower),
pseudonymize(alert.agent_id) |> Base.encode16(case: :lower)
]
|> Enum.join("|")
:crypto.hash(:sha256, payload)
end
This hash:
- Is deterministic (same alert = same hash)
- Contains no sensitive data
- Can be used to verify attestation authenticity
Viewing Attestations
Solscan Explorer
Every attestation includes a Solscan link for public verification:
https://solscan.io/tx/5Uy3...?cluster=devnet
The transaction memo contains the JSON attestation data.
Dashboard
Attested alerts show blockchain verification status:
- Transaction signature
- Solscan link
- Attestation timestamp
- Verification status
API
# Get attestation details for an alert
curl https://your-server/api/v1/alerts/{alert_id}/attestation \
-H "Authorization: Bearer $TOKEN"
{
"data": {
"tx_signature": "5Uy3...",
"solscan_url": "https://solscan.io/tx/5Uy3...?cluster=devnet",
"incident_hash": "abc123...",
"manifest_hash": "def456...",
"attestation_timestamp": "2025-05-08T12:00:00Z",
"verified": false
}
}
Best Practices
- Enable automatic attestation for high/critical alerts
- Use batch mode for high-volume deployments
- Monitor attestation success via
/api/v1/solana/status - Archive manifests locally for verification
- Review TLP classification before enabling public sharing
Next Steps
- Proof Verification - Verify attestations on-chain
- Bounty System - Earn rewards for rule contributions
- Solana Program - Technical integration details