Reproduced Exploit

SXT — [C-01] Accepting duplicate signatures from one signer

Threshold = 2. Attacker submits the same valid (v,r,s) twice. Both recover to one attestor; both count. validateMessage returns true.

Mar 2025Otheruntagged2 min read

Chain

Other

Category

untagged

Date

Mar 2025

Source

AuditVault

EVM Playground

Source-level debugger — step opcodes and Solidity in sync

evm-hack-analyzer

The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.

Loading fork state…

Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 63314-c-01-accepting-duplicate-signatures-from-one-signer-pashov-a. Standalone Foundry PoC and full write-up: 63314-c-01-accepting-duplicate-signatures-from-one-signer-pashov-a_exp in the evm-hack-registry mirror.


Vulnerability classes: broken-logic · role-bypass · bridge-validator-threshold

Reproduction: self-contained Foundry PoC, forge-std only.

AuditVault taxonomy: severity/high · sector/staking · platform/pashov · broken-logic · role-bypass · bridge-validator-threshold


Key info#

ImpactHIGH — single attestor meets multi-sig threshold via replayed signature
ProtocolSXT SubstrateSignatureValidator
Vulnerable codevalidateMessage increments count without signer dedup
Bug classMissing signature uniqueness check
FindingPashov · SXT 2025-03-31 · #63314

TL;DR#

Threshold = 2. Attacker submits the same valid (v,r,s) twice. Both recover to one attestor; both count. validateMessage returns true.

The vulnerable code#

SOLIDITY
if (attestorIndex < attestorsLength && _attestors[attestorIndex] == recoveredAddress) {
    ++validSignaturesCount; // @> VULN no dedup
}
// FIX: skip if signer already counted

Diagrams#

flowchart LR S1["sig of attestor A"] --> V["validateMessage"] S1b["same sig again"] --> V V --> T["validCount equals 2"] T --> OK["threshold met"]

Impact#

Forged multi-attestor consensus from one honest signature → bridge/message validation bypass.

Sources#


Sources & further analysis#

Reproductions & code

Alerts & third-party analyses

  • Web3Sec X hacked database: search.
  • Rekt leaderboard: search.
  • Solodit incident search: search.

These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.