Skip to content

Security Deep Dive

RunTimeAdmin edited this page Oct 28, 2026 · 15 revisions

Security Deep Dive

**Referenced Files in This Document** - [SECURITY.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/SECURITY.md) - [site/SECURITY.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/site/SECURITY.md) - [docs/SECURITY_AND_MAINNET_READINESS_REVIEW.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/docs/SECURITY_AND_MAINNET_READINESS_REVIEW.md) - [src/SigvaraReputation.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraReputation.sol) - [src/SigvaraStaking.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraStaking.sol) - [src/SigvaraIdentity.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraIdentity.sol) - [src/SigvaraOracleBond.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/SigvaraOracleBond.sol) - [test/SecurityFixes.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/SecurityFixes.t.sol) - [test/StakingInvariant.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/StakingInvariant.t.sol) - [oracle/adversarial.test.js](https://github.com/RunTimeAdmin/Sigvara/blob/main/oracle/adversarial.test.js) - [src/TimelockedGrants.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/TimelockedGrants.sol) - [src/InflowGuard.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/src/InflowGuard.sol) - [docs/adr/0004-operator-custody.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/docs/adr/0004-operator-custody.md) - [docs/adr/0005-governance-and-emergency-powers.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/docs/adr/0005-governance-and-emergency-powers.md)

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion
  10. Appendices

Introduction

This document provides a comprehensive security deep dive for Sigvara, focusing on advanced threat models, vulnerability assessment methodologies, mitigation strategies, formal verification approaches, and operational security guidance. It synthesizes the protocol’s smart contract design, off-chain oracle behavior, SDK responsibilities, and audit findings into an actionable security reference for developers, auditors, operators, and consumers.

Sigvara is a computed reputation and staked slashing layer built on top of ERC-8004 identity. The system combines:

  • On-chain identity anchoring with Ed25519 public key storage.
  • Off-chain scoring that proposes six-factor reputation scores.
  • A challenge window before finalization.
  • Staked bonds with committee-initiated slashing and dispute handling.
  • Optional operator performance bonding for oracle participants.

The repository includes a published security policy, site-specific security guidance, and a detailed mainnet readiness review that identifies critical gaps such as missing external audits, centralized oracle operation, and governance hardening requirements.

This page describes the contracts on main. The Arc testnet proxies have run these contracts since 26 October 2026, apart from the bound on upholding a dispute, which they take at their next upgrade. They keep the role administrators written by the September initialisation, so the timelocked grants of the fund-moving roles do not apply there, and every privileged role on testnet is a single EOA.

Section sources

Project Structure

The security-relevant structure centers around four core Solidity contracts, an off-chain oracle implementation, and extensive test suites covering unit tests, fuzzing, invariants, adversarial scenarios, and regression fixes.

graph TB
subgraph "On-Chain Contracts"
Identity["SigvaraIdentity.sol"]
Reputation["SigvaraReputation.sol"]
Staking["SigvaraStaking.sol"]
OracleBond["SigvaraOracleBond.sol"]
end
subgraph "Off-Chain"
Oracle["oracle/index.js<br/>adversarial.test.js"]
end
subgraph "Tests"
Unit["test/*.t.sol"]
Invariant["test/StakingInvariant.t.sol"]
Fixes["test/SecurityFixes.t.sol"]
end
Identity --> Reputation
Identity --> Staking
Reputation --> Staking
Reputation --> OracleBond
Oracle --> Reputation
Unit --> Identity
Unit --> Reputation
Unit --> Staking
Unit --> OracleBond
Invariant --> Staking
Fixes --> Identity
Fixes --> Reputation
Fixes --> Staking
Fixes --> OracleBond
Loading

Diagram sources

Section sources

Core Components

Sigvara’s security model relies on clear separation between identity, reputation, staking, and optional operator bonding. Each component has specific roles, state transitions, and attack surfaces.

Key components:

  • SigvaraIdentity: Anchors agent identities, manages operator control, status transitions, and Ed25519 keys.
  • SigvaraReputation: Stores six-factor reputation scores, enforces challenge windows, maturity, and evidence roots.
  • SigvaraStaking: Manages stake bonds, slashing initiation/dispute/execution, unbonding queues, and proceeds distribution.
  • SigvaraOracleBond: Tracks operator performance bonds, active set admission, slashing, and demotion logic.

Security properties include:

  • Role-based access control using OpenZeppelin upgradeable patterns.
  • Reentrancy guards and CEI (Checks-Effects-Interactions) ordering.
  • Bond enforcement to ensure slashability before scoring or activation.
  • Challenge windows and dispute mechanisms to prevent unilateral score changes.
  • Maturity gating to prevent farm-and-cash-out attacks.
  • Grants of the roles that move funds or change an agent's standing wait for the timelock, while the admin can still revoke them at once.
  • A second key (the admin) rules on disputed slashes and can veto a slash, so the committee that files is not also the judge.
  • A guardian can pause new inflows for three days at a time and nothing else.
  • Floors and ceilings on the parameters the admin can change at once.

Section sources

Architecture Overview

The architecture follows an optimistic scoring model where off-chain computation proposes scores that are anchored on-chain after a challenge period. Slashing and reputation zeroing are coordinated through role-gated interactions.

sequenceDiagram
participant Agent as "Agent Operator"
participant Oracle as "Reputation Oracle"
participant Reputation as "SigvaraReputation"
participant Identity as "SigvaraIdentity"
participant Staking as "SigvaraStaking"
participant Committee as "Slashing Committee"
participant Admin as "Admin"
Agent->>Identity : registerAgent()
Agent->>Staking : depositStake(didHash, amount)
Oracle->>Reputation : proposeReputation(didHash, data, evidenceRoot)
Reputation->>Identity : _requireScorable(didHash)
Reputation-->>Oracle : ScoreProposed event
Committee->>Reputation : rejectReputation(didHash)
Reputation-->>Committee : ScoreRejected event
Oracle->>Reputation : finalizeReputation(didHash)
Reputation->>Identity : read status via stakeView
Reputation-->>Consumers : ReputationUpdated event
Committee->>Staking : initiateSlash(didHash, victim, evidenceHash)
Staking->>Identity : updateStatus(Suspended)
Staking-->>Committee : SlashInitiated event
Agent->>Staking : disputeSlash(didHash)
Staking-->>Agent : SlashDisputed event
Admin->>Staking : resolveDispute(didHash, uphold)
Staking->>Identity : updateStatus(Slashed)
Staking->>Reputation : zeroReputation(didHash)
Loading

Diagram sources

Section sources

Detailed Component Analysis

Reputation Contract Security Model

The reputation contract implements an optimistic proposal system with strict factor caps, identity binding, bond checks, and evidence roots. It also introduces maturity to prevent immediate spendability of newly earned scores.

Key security features:

  • Factor cap validation prevents out-of-range inputs.
  • Identity registry binding ensures only registered, non-slashed agents can be scored.
  • Minimum stake requirement enforced via stake view prevents unslashable reputation farming.
  • Evidence root commitment enables third-party verification of payment-backed scoring.
  • Maturity rate per day controls how quickly earned scores become spendable.
  • A proposal remembers who made it, and finalization (still permissionless) refuses one whose proposer has since lost ORACLE_ROLE or, when an operator registry is configured, its standing as an active operator or signer, so removing a key also ends what it has pending.
  • The review window is fixed when a score is proposed (finalizableAt), so changing the window later does not move the end of a pending proposal.
  • The challenge window (1 hour to 7 days) and the maturity rate (above 0, at most 100 points a day) have floors and ceilings.
flowchart TD
Start(["proposeReputation Entry"]) --> CheckRole["Check ORACLE_ROLE"]
CheckRole --> RequireScorable["_requireScorable(didHash)"]
RequireScorable --> ValidateCaps["Validate factor caps"]
ValidateCaps --> StorePending["Store PendingScore + evidenceRoot"]
StorePending --> EmitEvent["Emit ScoreProposed"]
EmitEvent --> End(["Exit"])
subgraph "Finalize Flow"
FinalizeStart["finalizeReputation Entry"] --> CheckWindow["Check challenge window<br/>and that the proposer is still authorized"]
CheckWindow --> AnchorScore["Anchor matured score"]
AnchorScore --> WriteReputation["Write finalized ReputationData"]
WriteReputation --> ResetMaturity["Reset maturity anchor"]
ResetMaturity --> EmitUpdate["Emit ReputationUpdated"]
EmitUpdate --> FinalizeEnd(["Exit"])
end
Loading

Diagram sources

Section sources

Staking and Slashing Mechanics

The staking contract manages stake bonds, unbonding queues, slashing initiation, dispute resolution, and proceeds distribution. It enforces minimum stake floors, prevents self-victimization, and ensures slashed agents remain terminal.

Critical security properties:

  • Dispute-freeze mechanism prevents bond release during disputes.
  • Unbonding queue remains slashable until claimed.
  • Challenge period floor prevents instant slashes.
  • Proceeds are credited, not pushed, to avoid recipient failures blocking settlement.
  • Burn address accumulation invariant ensures slashed value cannot be recovered.
  • The committee files and the admin rules, so no single key is accuser, judge and payee. An upheld ruling waits for the challenge deadline, so a dispute never brings a slash forward, and is refused once the dispute can be expired. The admin can also veto a pending or disputed proposal.
  • A proposal nobody executes can be lapsed by anyone 14 days after its deadline (expireSlash), and after any dropped proposal the committee waits one challenge period before filing against the same agent again.
  • The challenge period (3 to 30 days) and the unbonding period (1 to 90 days) have floors and ceilings, in the initializer as well as the setters, and the minimum stake cannot be zero.
  • A guardian pause closes new stake deposits and nothing else: withdrawals, claims, disputes, rulings and slash execution are never covered.
stateDiagram-v2
[*] --> Active
Active --> Suspended : "initiateSlash()"
Suspended --> Disputed : "disputeSlash()"
Disputed --> Executed : "resolveDispute(uphold=true)"
Disputed --> Cancelled : "resolveDispute(uphold=false) or vetoSlash()"
Disputed --> Expired : "expireDispute()"
Suspended --> Cancelled : "vetoSlash() or expireSlash()"
Executed --> [*]
Cancelled --> Active : "_dropProposal()"
Expired --> Cancelled : "_dropProposal()"
Active --> Suspended : "self-suspend"
Suspended --> Active : "operator self-resume"
Loading

Diagram sources

Section sources

Identity and Operator Transfer Security

The identity contract anchors agent identities, manages operator control, and enforces collateral checks during status transitions. It also supports secure operator transfers with handover tracking to restart score maturity.

Security highlights:

  • Registration requires agent-signed digest bound to chain and registry.
  • Status transitions enforce collateral via stake view.
  • Slash suspension lock prevents operator self-reinstatement mid-challenge.
  • The stake view that decides who counts as bonded can only be repointed through the timelock (setStakeView needs UPGRADER_ROLE), and the staking-core role is granted through it too, since a contract that answers yes for everyone would switch the collateral gate off.
  • Operator transfer requires recipient acceptance and collateral check.
  • Handover tracking restarts maturity to prevent liquid reputation trading.
classDiagram
class SigvaraIdentity {
+registerAgent(agentAddress, ed25519PubKey, signature) bytes32
+rotatePublicKey(didHash, newEd25519PubKey) void
+updateStatus(didHash, newStatus) void
+offerOperatorTransfer(didHash, newOperator) void
+acceptOperatorTransfer(didHash) void
+computeDidHash(agentAddress) bytes32
-_pushToOperatorIndex(operator, didHash) void
-_removeFromOperatorIndex(operator, didHash) void
}
class SigvaraStaking {
+depositStake(didHash, amount) void
+initiateSlash(didHash, victim, evidenceHash) void
+disputeSlash(didHash) void
+executeSlash(didHash) void
+claimSlashProceeds() uint256
}
class SigvaraReputation {
+proposeReputation(didHash, data, evidenceRoot) void
+finalizeReputation(didHash) void
+zeroReputation(didHash) void
+getTotalScore(didHash) uint8
}
SigvaraIdentity --> SigvaraStaking : "status updates"
SigvaraStaking --> SigvaraIdentity : "slash status"
SigvaraReputation --> SigvaraIdentity : "scorable checks"
Loading

Diagram sources

Section sources

Oracle Bond and Operator Accountability

The oracle bond contract manages operator performance bonds, active set admission, slashing, and demotion. It ensures operators cannot dodge accountability by exiting during unbonding.

Key security mechanisms:

  • Bond deposits require approval and credit actual received amount.
  • Active operators must maintain minimum bond; slashing below threshold triggers demotion.
  • Unbonding period keeps bonds slashable during exit cooldown.
  • Zero-bond operators are cleared to allow re-registration.
  • The key an oracle service signs with can be separated from the key that holds the bond: an operator names a signer, which answers for it in isActiveOperator but cannot start an unbond or withdraw the bond, and the operator clears it in one transaction.
  • The slasher role is granted through the timelock, and the registry never lets one address be both the slasher and the slash beneficiary. Changing the beneficiary is a timelocked call.
  • The unbonding period is held between 1 and 90 days, and a guardian pause closes only new bond deposits.
flowchart TD
Deposit["depositBond(amount)"] --> CreditReceived["Credit actual received amount"]
CreditReceived --> UpdateStatus["Set Bonded if None"]
UpdateStatus --> Admit["admit(operator) -> Active"]
Admit --> Monitor["Monitor activity/slashing"]
Monitor --> Slash{"slash(operator, amount)?"}
Slash --> |Yes| Deduct["Deduct bond"]
Deduct --> Demote{"bond < bondAmount?"}
Demote --> |Yes| Demoted["Demote to Bonded"]
Demote --> |No| KeepActive["Keep Active"]
Slash --> |No| Unbond["initiateUnbond()"]
Unbond --> ExitCooldown["Unbonding cooldown"]
ExitCooldown --> Withdraw["withdrawBond()"]
Loading

Diagram sources

Section sources

Dependency Analysis

The contracts have carefully managed dependencies to avoid circular imports while maintaining necessary cross-contract interactions.

graph LR
Identity["SigvaraIdentity.sol"] --> Staking["SigvaraStaking.sol"]
Identity --> Reputation["SigvaraReputation.sol"]
Staking --> Identity
Reputation --> Identity
Reputation --> OracleBond["SigvaraOracleBond.sol"]
OracleBond -.-> Reputation
Loading

Diagram sources

Section sources

Performance Considerations

Security and performance are balanced through several optimizations:

  • Efficient struct packing for reputation factors.
  • View functions for maturity calculation to avoid write costs.
  • Paged operator agent queries to handle large operator portfolios.
  • Gas-aware removal operations using index tracking.

Recommendations:

  • Monitor gas usage for batch operations.
  • Use pagination for large data sets.
  • Optimize oracle proposal batching to reduce per-agent costs.

Troubleshooting Guide

Common security issues and their mitigations:

Vulnerability Reporting

  • Report vulnerabilities privately to security@sigvara.xyz.
  • Include affected component, impact, reproduction steps, and suggested mitigation.
  • Avoid public disclosure before fix availability.

Section sources

Common Attack Vectors and Mitigations

  • Sybil Attacks: Mitigated through per-payer caps, tenure requirements, and external trust factors.
  • Wash Trading: Bounded by fee/success caps and time-decayed tenure scoring.
  • Slashing Dodge: Fixed by including unbonding amounts in slashable balance.
  • Self-Victimization: Prevented by rejecting reporter=victim in slash initiation.
  • Zero-Bond Operators: Cleared to allow re-registration after full slash.
  • Compromised or conflicted committee: A slash pays a quarter of the bond to whoever filed it, so the admin rules on disputes and can veto, an upheld ruling waits for the challenge deadline, and a dropped proposal starts a one-period re-file cooldown. Revoking a compromised member also stops what it had already filed from being executed, because a slash is executed only while its reporter still holds the role.
  • Stolen oracle signing key: The signer cannot move the bond, and the operator clears it at once; finalization refuses what a removed or cleared key proposed.
  • Admin key compromise: A compromised admin Safe can still grant itself ORACLE_ROLE or GUARDIAN_ROLE and move a parameter within its bounds at once (the minimum stake and the bond amount have a floor of one and no ceiling). It cannot upgrade, install a slasher or committee member, or repoint the stake view, reputation's operator registry or the slash beneficiary without 48 hours of public notice. It also cannot shorten a withdrawal that is already queued, because the claim time is fixed when the withdrawal is queued. ADR 0005 records the first part as a stated trust assumption.
  • Live bug while a fix is built: The guardian pauses new registrations, deposits, score proposals and bond deposits for three days, which outlasts the 48 hour upgrade delay.

Section sources

Formal Verification Approaches

  • Invariant Testing: Solvency, conservation, and collateralization invariants. There are 11 invariant tests: six on staking and five on the operator bond registry's signer mappings and accounting.
  • Fuzzing: 1000/5000 runs for contract tests.
  • Adversarial Scoring Tests: Measure attack costs against scoring caps.
  • Regression Tests: Pin specific security fixes.

Section sources

Conclusion

Sigvara demonstrates strong engineering fundamentals with clear architecture, comprehensive testing, and thoughtful security considerations. However, mainnet deployment requires addressing critical gaps including external audits, decentralized oracle consensus, governance timelocks, and operational hardening. The protocol’s design effectively balances security with functionality through bond enforcement, challenge windows, and maturity gating.

Key recommendations:

  • Complete external security audit before mainnet.
  • Implement multi-oracle consensus.
  • Deploy governance timelock for admin roles.
  • Harden oracle key management with HSM.
  • Integrate dispute arbitration (UMA/Kleros).
  • Establish incident response procedures.

Appendices

Mainnet Readiness Checklist

Based on the security review, the following items must be addressed before mainnet deployment:

Category Item Status
Security External audit completed ❌ Not performed
Security All Critical/High findings resolved ❌ Multiple open
Deployment Governance timelock configured ❌ Not deployed
Deployment Committee multisig deployed ❌ Not deployed
Operations Oracle monitoring/alerting ⚠️ Partial
Operations Incident response plan ❌ Not documented

The table follows the 17 September review. Since then ADR 0005 has recorded the split of upgrade and admin authority, the guardian pause and the launch floors and ceilings, ADR 0004 has recorded the operator signer registry, and a public challenge watcher has run since 20 September, which makes monitoring partial: the watcher alerts when the checker disagrees with the primary, while the primary's own epoch failures show only on /health and /metrics, which an operator has to scrape and alert on. The governance timelock and the committee multisig are still not deployed on a live network (the handover is rehearsed on a fork of the testnet), and no external audit has been completed.

Section sources

Cryptographic and Key Management Best Practices

  • Use HSM-backed key management for oracle private keys.
  • Keep the bond off the signing key: have the operator name the key on the host as its signer (setSigner), so a stolen server key can speak but cannot start an unbond or withdraw the bond.
  • Implement threshold signatures for critical operations.
  • Rotate keys without service interruption.
  • Validate RPC endpoints and consider running own nodes.
  • Secure API authentication with per-client keys and request signing.

Section sources

Overview

Clone this wiki locally