agents/skills/injectable/l1/p2p-dos-and-eclipse/SKILL.md
L1 trigger - audits peer-to-peer networking for DoS vectors (resource exhaustion, amplification), eclipse attack susceptibility, and discovery table poisoning (Kademlia/devp2p).
npx skillsauth add plamentsv/plamen p2p-dos-and-eclipseInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
L1 trigger:
L1_PATTERN=trueAND (p2p/ORnetwork/ORdiscovery/ORlibp2pORdevp2pORenrORdiscv5detected in recon subsystem map) Inject Into:depth-network-surfaceLanguage: Go and Rust Finding prefix:[P2P-N]Status: v0.1 draft, Round 4 exemplars pending
Recon identifies a P2P subsystem. Most attacks in this class are out-of-scope for typical bounty programs but are in scope for Plamen audits — firms like Sigma Prime and OpenZeppelin explicitly cover them. Severity downgrades to Low/Info when the exploit only eclipses a single node (see severity-matrix.md); upgrades when reachable by arbitrary peers and amplifies across the network.
Every P2P subsystem has a finite set of entry points for remote adversary bytes. Enumerate them using LSP workspace/symbol and ast-grep:
| Entry point type | How to find | Example functions |
|---|---|---|
| Message handlers | Trait/interface impl names ending in Handler, Service, Listener | handleGetBlockHeaders, on_new_pooled_transaction_hashes |
| Decoders | Functions taking &[u8] or Reader and returning protocol types | decode_enr, rlp_decode |
| Connection accepters | TCP/QUIC listener accept loops | acceptLoop, handle_connection |
| Discovery responders | UDP packet handlers for discovery protocol | handleDiscv5Packet, process_find_node |
| Gossip handlers | Pubsub topic subscribers | process_gossip_message |
Write the enumeration into scratchpad/p2p_surface.md before proceeding.
Attacker sends N bytes, node does O(N²) or O(N*log(N)) work. Classic example: decompression bombs, hash-map insertion of attacker-chosen keys (hash DoS), large RLP lists.
Check:
Tag: [P2P-ASYMMETRIC:{loc}:{input-size}→{work-cost}]
Handlers that buffer or queue indefinitely.
Check:
append / Vec::push in a loop that can be driven by adversary: is there a bound?Tag: [P2P-UNBOUNDED:{structure}:{growth-driver}]
Handlers that can loop forever or spend minutes on malicious input.
Check:
for loop in a handler: what bounds termination? Attacker-controlled?Tag: [P2P-CPU:{loc}:{termination-condition}]
Attacker opens N connections with M peers, filling the connection table.
Check:
Tag: [P2P-SLOTS:{limit}:{diversification}], [P2P-BOOTSTRAP-FLOOD:{cap-or-unbounded}]
Attacker sends small message, node sends large response — used to DDoS third parties.
Check:
Tag: [P2P-AMPLIFY:{request-bytes}→{response-bytes}]
For each gossip handler that RECEIVES data and then FORWARDS it to other peers (re-gossip), trace the dedup path. This is a separate concern from 2a (single-message cost) — it covers network-multiplication attacks.
Check:
.send() call, not after?verify_signature → record_seen → broadcast. Any other order is a finding.Fail mode: an N-peer network re-gossips each message O(N²) times, saturating bandwidth in an "echo chamber" pattern. NEAR / Tendermint / Geth have all had variants of this bug. Combined with seen-cache poisoning, an attacker can both flood the network AND censor legitimate items.
Tag: [P2P-AMPLIFY:re-gossip-dedup:{file}:{line}] and [P2P-CACHE-POISON:record-before-verify:{file}:{line}]
Many P2P implementations naively use for peer in active_peers { client.send(peer, msg).await; } to broadcast. Each peer's response time blocks the next. A single slow peer (intentional or not) delays the entire broadcast cycle.
Check:
.await or in parallel with tokio::join_all / FuturesUnordered / select!.peer_count × per-peer-timeout. If this exceeds block time, propagation is broken under adversarial peer growth.Tag: [P2P-CPU:sequential-broadcast:{loc}]
An eclipse attack isolates a target node by monopolizing its peer table entries.
On restart, the node uses a static bootstrap list, then populates its peer table from responses. If an attacker can intercept or outrun the bootstrap response, they control the initial peer set.
Check: What bootnodes are used? Are they hardcoded or configurable? What happens if all bootnodes are unreachable?
Discovery v5 uses signed ENRs. Can an attacker poison a victim's ENR cache with malicious entries?
Check: ENR signature verification on every incoming record. ENR seqnum monotonic update.
Tag: [ECLIPSE:{vector}:{countermeasure-state}]
Known exemplar class: devp2p issue #109 (Ethereum discv5 eclipse concerns); academic low-resource eclipse attacks on older Geth.
Most clients have a peer scoring system: peers that misbehave (send invalid data, stall, equivocate) accumulate negative score and get banned.
i32, repeatedly adding -MAX causes wrap. Geth has historically had integer-overflow issues in peer scoring.Tag: [P2P-SCORE:{vulnerability-class}]
If the protocol uses gossipsub or similar pubsub:
Tag: [GOSSIP:{param}:{value-or-unbounded}]
[FUZZ-PASS] (D2PFuzz or libfuzzer on decoder) > [LSP-TRACE] > [CODE-TRACE]NEAR Signature::verify pre-auth handshake panic (December 2023) — $150,000 bounty. In SECP256K1 branch of Signature::verify(), Message::from_slice(data).expect("32 bytes") panics when payload > 32 bytes; RecoveryId::from_i32().unwrap() panics on recovery byte > 3. A single crafted Tier1Handshake/Tier2Handshake message kills any node. Pre-auth = any peer can do it. Fixed PR #10385 (commit e0f0da5c3dde29122e956dfd905811890de9a570). Zellic Web3 Ping of Death. Skill catch point: pre-auth panic check — for every handshake / pre-auth message handler, trace every .unwrap(), .expect(), panic!(), slice index, conversion. Assert graceful error return for all input classes.
Marcus-Heilman low-resource Ethereum eclipse (2018) — Geth's Kademlia discovery table could be monopolized by an attacker with only 2 IPs. Fixed in geth 1.8 (Feb 2018). Low-Resource Eclipse Attacks on Ethereum. Skill catch point: Section 3a — bucket eviction policy, IP/ASN stratification, rate-limit on new peer announcements.
D2PFuzz differential p2p bugs across 5 clients (IEEE 2025) — network-layer differential fuzzer found 15 unique bugs, 12 previously unknown by mutating DevP2P messages and diffing responses across geth, erigon, reth, besu, nethermind. Network-Layer Differential Fuzzing for Ethereum. Skill catch point: Section 1 — enumerate every DevP2P message type; verify response semantics against spec for valid / malformed / boundary / timing inputs; compare against ≥2 other client responses.
Henningsen "false friends" Ethereum eclipse (2019) — follow-up to Marcus-Heilman. Geth's peer-eviction policy could be gamed with valid-looking false-friend nodes. Eclipsing Ethereum Peers with False Friends. Skill catch point: Section 4 — audit peer scoring for monotonicity; new peers from unknown sources must not displace established trusted peers.
Geth CVE-2025-24883 RLPx handshake crash — all-zero secp256k1 public key accepted without subgroup validation. Single malicious peer crashes any node. GHSA-q26p-9cq4-7fc2. Skill catch point: cryptographic handshake inputs must be validated as on-curve AND in-subgroup BEFORE any math operation. (Shared with bls-aggregation-audit Section 2.)
Insert as new Section 2f (highest priority): Pre-auth message handlers are the hottest P2P surface. Every panic in a pre-auth path is a single-packet node-kill primitive. Methodology:
.unwrap(), .expect(, panic!(, slice indexing [i], type assertion .(T) without ok, unreachable!(), integer divisionTag: [P2P-PANIC-PREAUTH:{handler}:{panic-site}]
Peer scoring only works if rewards AND penalties are both applied. A one-sided system lets malicious peers farm reputation without consequence. This section forces enumeration.
Required artifact: write {SCRATCHPAD}/peer_scoring_symmetry.md:
# Peer Scoring Symmetry: {protocol_name}
| Event | Reward path | Penalty path | Symmetric? |
|---|---|---|---|
| Successful block delivery | score.rs:L42 +1 | — | **ASYMMETRIC** |
| Invalid block response | — | score.rs:L78 -5 | OK |
| Health check failure | — | — | **MISSING** |
| /get_data served | +1 | — | **FARMABLE** |
Methodology:
peer_score, reputation, scoring).check_health specifically: does it decrement on HTTP errors / timeouts, or only on explicit Ok(false)? A no-op on failure is a finding./get_data, request_blocks): if the success path increments score with no rate limit or deduplication → FARMABLE finding.Tag: [PEER-SCORE-ASYMMETRIC:{event}], [PEER-SCORE-FARMABLE:{event}], [PEER-SCORE-NO-PENALTY:{failure_class}]
p2p/ and discovery/handleRLP, decode_rlp, handle_message function definitionsMaxSize, MAX_, limitmempool-asymmetric-dos, consensus-safety-invariants (equivocation detection interacts with peer scoring)depth-network-surfacedocs/l1-mode/severity-matrix.mddevelopment
Prepare Solidity projects for a security audit — test coverage, test quality, NatSpec docs, code hygiene, dependency health, best-practice enforcement, deployment readiness, and project documentation checks. Generates a scored Audit Readiness Report and optionally runs static analysis. Trigger on: "prepare for audit", "audit readiness", "pre-audit check", "audit prep", "NatSpec check", or any request to review a Solidity codebase before a security review.
development
Launch the Plamen deterministic Web3 security audit pipeline
development
Run the Plamen smart-contract audit wizard in Codex
testing
Launch the Plamen deterministic L1 infrastructure audit pipeline