Reproduced Exploit

Remora — resolveUser lock migration can be griefed to extend lock duration

1. resolveUser migrates locks by appending old locks after any locks already on newAddress. 2. availableTokens stops at the first unexpired entry. 3. A frontrun transfer/donation to newAddress plants a fresh lock at the front. 4. All migrated (already matured) locks stay blocked until the grief loc…

Oct 2025Otherdos3 min read

Chain

Other

Category

dos

Date

Oct 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: 63779-migrating-the-existing-locks-for-an-investor-when-is-resolve. Standalone Foundry PoC and full write-up: 63779-migrating-the-existing-locks-for-an-investor-when-is-resolve_exp in the evm-hack-registry mirror.


Vulnerability classes: vuln/dos/griefing · vuln/logic/ordering · vuln/timestamp

Reproduction: self-contained Foundry PoC with only forge-std. Full trace: output.txt. PoC: test/63779-migrating-the-existing-locks-for-an-investor-when-is-resolve_exp.sol.

AuditVault taxonomy: lang/solidity · platform/cyfrin · has/github · has/poc · severity/high · sector/governance · sector/stable · genome: griefing · temporary · frontrun-exposure · timestamp-dependence


Key info#

ImpactHIGH — frontrun donation to newAddress plants a fresh lock that blocks all migrated matured locks until the donation expires
ProtocolRemora Dynamic Tokens
Vulnerable codeLockUpManager._newAccountSameLocks append-only migration + availableTokens short-circuit
Bug classOrdering grief / frontrun during investor resolve
FindingCyfrin — Remora Dynamic Tokens v2.1, 2025-10-22 · #63779 · reporter 0xStalin
ReportCyfrin Remora report
SourceAuditVault
StatusFixed at commit 3d6d874. Local synthetic PoC.
Compiler^0.8.24 (PoC)

TL;DR#

  1. resolveUser migrates locks by appending old locks after any locks already on newAddress.
  2. availableTokens stops at the first unexpired entry.
  3. A frontrun transfer/donation to newAddress plants a fresh lock at the front.
  4. All migrated (already matured) locks stay blocked until the grief lock expires.
  5. HARM: availableTokens(newUser) == 0 even though a migrated lock is fully matured.

The vulnerable code#

SOLIDITY
newData.tokenLockUp[newData.endInd++] =
    oldData.tokenLockUp[oldData.startInd + i]; // @> VULN: append-only
// ...
} else {
    break; // @> VULN: short-circuit on first unexpired lock
}

Fix: merge locks ordered by time (or prevent newAddress from holding tokens before resolve).


Root cause#

Migration assumes newAddress has no prior locks (or that append preserves chronological order). Combined with short-circuit unlock, a single newer front entry freezes older matured ones.


Preconditions#

  • Old user has matured locks.
  • Attacker can transfer/donate 1 token to newAddress before resolveUser.

Attack walkthrough#

  1. Old user has 4 locks; one is fully matured.
  2. Griefer donates 1 token to newAddress (fresh lock at now).
  3. Admin calls resolveUser(old, new) — appends old locks after the grief lock.
  4. availableTokens(new) == 0 despite a matured migrated entry.

Diagrams#

flowchart TD G["Grief donation lock at now"] --> FRONT["Front of newUser ring"] M1["Matured lock from oldUser"] --> BACK["Appended after grief"] M2["Other old locks"] --> BACK FRONT --> SC["availableTokens short-circuits"] SC --> ZERO["available = 0"]

Impact#

Investor funds remain locked far longer than their original lock schedule after a legitimate address resolve — a griefing / temporary freeze of migrated balances.


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.