| name | tn-threat-model |
| description | Generate security threat model documentation for telcoin-network components.
Trigger on: "threat model", "attack surface", "security architecture", "adversary model", "security doc", "audit prep"
|
Threat Model Generator
Generate structured security threat model documentation for the telcoin-network repo -- a Rust blockchain node combining Narwhal/Bullshark DAG-based BFT consensus with EVM execution via Reth.
Project Context
Telcoin Network is a permissioned-set (staked validator) blockchain with a DAG-based BFT consensus layer (Narwhal/Bullshark) and Reth-based EVM execution. The threat model skill needs to understand the adversary model and key invariants that constrain what attacks are possible:
- Byzantine fault tolerance: tolerates f < n/3 faulty validators.
- Quorum threshold: 2f+1 (calculated as
2*n/3 + 1). Validity threshold: f+1 (calculated as ceil(n/3)).
- Equal voting power: all validators have
EQUAL_VOTING_POWER = 1 — no stake-weighted voting.
- Gossipsub topic access: only current committee members may publish on consensus topics.
- System call isolation:
SYSTEM_ADDRESS (0xfffe...fe) is not callable by external accounts.
- TEL precompile governance: restricted to
GOVERNANCE_SAFE_ADDRESS.
Process
When asked to generate a threat model, follow these phases:
Phase 1: Scope
Determine which component or subsystem to model. Ask the user if unclear. Options include:
- Full system (high-level)
- Consensus (primary DAG, certificate aggregation, Bullshark ordering)
- Networking (libp2p, gossipsub, peer management, Kademlia)
- Execution (EVM, precompiles, system calls, transaction pool)
- Synchronization (epoch chain, consensus chain, state sync)
- RPC (external API surface)
- A specific crate (e.g.,
crates/network-libp2p/, crates/consensus/primary/)
Phase 2: Map Trust Boundaries and Entry Points
Identify all points where untrusted data enters the system. Key entry points in this codebase:
- Gossipsub messages (
crates/network-libp2p/src/consensus.rs) -- certificates, batch announcements, consensus output results. Only committee members should publish. Validated via BLS signature before propagation.
- Request-response messages (
crates/consensus/primary/src/network/) -- vote requests, missing certificate requests, consensus output requests, epoch record requests. Handled by RequestHandler in handler.rs.
- RPC endpoints (
crates/execution/tn-rpc/) -- tn_latestConsensusHeader, tn_genesis, tn_epochRecord, tn_epochRecordByHash. Plus standard Reth JSON-RPC (eth, debug, trace).
- Transaction pool (
crates/tn-reth/src/txn_pool.rs) -- user-submitted transactions entering the mempool.
- Worker batch broadcasts -- batches of transactions from workers to primaries.
- Kademlia DHT --
NodeRecord publication for peer discovery. Committee validators publish records keyed by BLS public key.
- Stream-based sync (
StreamBehavior in the libp2p network) -- bulk data transfer for state sync.
For each entry point, read the relevant handler code and document:
- What data is received
- What validation occurs before processing
- What happens on validation failure (penalty, disconnect, ignore)
- Whether the handler is rate-limited or bounded
Phase 3: Identify Adversary Model and Capabilities
Document the adversary model derived from the protocol's BFT assumptions:
- Byzantine validators: Up to f = floor((n-1)/3) validators may be arbitrarily malicious. They can equivocate (sign conflicting messages), withhold messages, or send malformed data.
- Network adversary: Can delay, reorder, or drop messages between honest nodes. Cannot forge BLS signatures.
- External attacker: No committee membership. Can send transactions via RPC, attempt to connect as a peer, submit malformed requests.
- Compromised key: A validator's BLS keypair is compromised. Attacker can sign valid messages as that validator.
Search for specific adversary handling:
- Equivocation detection:
auth_last_vote map in RequestHandler tracks last vote per authority to detect equivocation early.
- Behind-consensus detection:
behind_consensus() in handler detects when a node is too far behind and switches to catchup mode.
- Committee verification:
get_committee() validates messages against the correct epoch's committee.
Phase 4: Enumerate Attack Vectors per Component
For each component in scope, enumerate concrete attacks. Use subagents to explore code in parallel. Key vectors to investigate:
Consensus attacks:
- Certificate forgery (forge BLS aggregate signatures)
- Equivocation (sign conflicting headers for the same round)
- Parent withholding (withhold certificates to slow DAG progress)
- Round manipulation (propose headers with inflated round numbers)
- GC window exploitation (exploit the garbage collection depth boundary)
Networking attacks:
- Message flooding (overwhelm gossipsub with valid-looking messages)
- Gossipsub amplification (exploit mesh propagation)
- Peer score gaming (manipulate scoring to avoid bans while being malicious)
- Sybil via Kademlia (flood DHT with fake node records)
- Eclipse attack (isolate a validator from honest peers)
Execution attacks:
- Malformed batch injection (batches with invalid transactions)
- System call spoofing (attempt to call system-only functions from external accounts)
- TEL precompile exploits (governance function access, timelock bypass if
faucet feature leaks to mainnet)
- Gas cost undercharging (some precompile operations are undercharged vs EVM equivalent -- see TEL precompile README gas tables)
- Transaction pool resource exhaustion
Sync attacks:
- Epoch record forgery (provide fake epoch records during sync)
- Consensus header manipulation (omit or reorder consensus headers)
- Stale committee injection (serve outdated committee data to syncing nodes)
Phase 5: Catalog Existing Security Controls
Search the codebase for these control categories and document what exists:
- BLS signature verification:
verify_cert(), verify_signature(), verify_secure() in crates/types/src/crypto/. Certificates require quorum (2f+1) valid BLS signatures. Aggregate signature verification via BlsAggregateSignature.
- Peer banning and scoring:
PeerManager in crates/network-libp2p/src/peers/. Penalty levels: Mild (~50 before ban), Medium (~10 before ban), Severe (~5 before ban), Fatal (immediate ban). Score decay over time. Temporary ban cache prevents immediate reconnection.
- System call access control:
SYSTEM_ADDRESS in crates/tn-reth/src/system_calls.rs. EVM handler checks caller is system address. SystemCallable.sol in contracts enforces on-chain.
- TEL precompile guards: Governance-only functions check
GOVERNANCE_SAFE_ADDRESS. Timelock on mainnet mints (7-day). Signature malleability rejection in permit. Double-claim prevention.
- Gossipsub message validation: Source peer must be a staked validator. Invalid messages trigger
Penalty via PeerManager. Topic validation ensures messages arrive on correct topics.
- Equivocation detection:
auth_last_vote map in RequestHandler caches last vote per authority with epoch, round, and header digest.
- Network behavior ordering:
TNBehavior struct places peer_manager first so banned-peer connection denials fire before other behaviors register the connection.
- Epoch chain verification: Syncing nodes verify each epoch record's BLS certificate (2/3+1 signatures) and chain the records via parent hashes. See
SYNC.md.
Phase 6: Identify Gaps
Search for known weakness patterns and flag them:
- HashMap in consensus paths:
HashMap is used in several consensus-critical data structures (e.g., RequestHandler fields, batch_fetcher.rs). HashMaps use SipHash which is DoS-resistant, but ordering non-determinism could cause subtle consensus divergence if iteration order matters. Grep crates/consensus/ for HashMap usage.
- Unbounded channels: Search for
unbounded_channel in consensus paths (crates/consensus/primary/src/certificate_fetcher.rs, crates/consensus/primary/src/certifier.rs). Unbounded channels can be exploited for memory exhaustion if a malicious peer floods the receiver.
- Gas undercharging in precompile: The TEL precompile README documents that
approve, mint (mainnet), burn, and grantMintRole are undercharged relative to worst-case EVM cost. This means these operations are subsidized, which could be exploited for gas-based DoS.
- Peer reputation metric gaps: Check if peer scoring captures all penalty-worthy behaviors. Look for error paths in network handlers that do NOT assess a penalty.
- Rate limiting on RPC: Check whether the
tn_* RPC endpoints have rate limiting or request size bounds.
- Kademlia record validation: Verify that DHT records are validated (BLS key ownership) before being accepted.
- Total supply accounting drift: TEL
totalSupply does not account for native balance changes outside the precompile (gas fees, coinbase rewards). Off-chain indexers must reconcile.
Phase 7: Generate the Threat Model Document
Produce the final document using the output format below. Write it to a location agreed with the user (e.g., docs/threat-model.md or tasks/threat-model-{component}.md).
Output Format
The generated threat model document MUST follow this structure:
# Threat Model: {Component/Scope}
Generated: {date}
Scope: {what was analyzed}
Commit: {git short hash}
## System Overview
Brief architectural description of the component being modeled.
Include a data flow summary showing how messages/data enter and exit the component.
## Trust Boundaries
| Boundary | Inside (Trusted) | Outside (Untrusted) | Crossing Mechanism |
|----------|-------------------|---------------------|--------------------|
| ... | ... | ... | ... |
## Adversary Model
- **Byzantine validators (f < n/3)**: capabilities and constraints
- **Network adversary**: what they can and cannot do
- **External attacker**: no committee keys, limited to RPC/P2P connection
- **Key compromise**: single validator key leaked
## Attack Surface
### {Component 1}
| # | Attack Vector | Entry Point | Preconditions | Impact | Likelihood | Severity |
|---|---------------|-------------|---------------|--------|------------|----------|
| 1 | ... | ... | ... | ... | ... | ... |
### {Component 2}
...
## Security Properties
What MUST hold for the system to be correct:
- [ ] Property 1 (e.g., "No certificate accepted without 2f+1 valid BLS signatures")
- [ ] Property 2
- ...
## Controls Inventory
| Control | Location | Protects Against | Status |
|---------|----------|------------------|--------|
| ... | ... | ... | ... |
## Gaps and Recommendations
| # | Gap | Risk | Recommendation | Priority |
|---|-----|------|----------------|----------|
| 1 | ... | ... | ... | ... |
Rules
- ALWAYS read the actual source code before documenting a control or gap. Do not assume based on naming alone.
- Use subagents to explore multiple crates in parallel when mapping attack surfaces.
- When documenting an attack vector, include the specific code path an attacker would target (file + function).
- For each gap, verify it is actually present by reading the code. Do not flag theoretical issues without evidence.
- Severity ratings use: Critical (consensus break / fund loss), High (network partition / DoS), Medium (degraded performance / information leak), Low (minor / requires unlikely preconditions).
- Likelihood ratings use: High (exploitable by external attacker with no special access), Medium (requires compromised validator or sustained effort), Low (requires multiple compromised validators or race conditions).
- Always check the current git commit hash and include it in the output for reproducibility.
- Cross-reference findings with
SECURITY.md for responsible disclosure context.
- Do not generate a threat model for out-of-scope items (third-party dApps, dependency vulnerabilities, social engineering). See
SECURITY.md scope table.
- When the user asks for "audit prep", generate the full-system threat model and additionally list the top 10 highest-priority items a security auditor should focus on.
- Write the threat model document to the location the user specifies. Default to
tasks/threat-model-{scope}.md if no location is given.
- After generating, ask the user if they want to drill deeper into any specific component or attack vector.