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…
Chain
Other
Category
dos
Date
Oct 2025
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
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.
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-registrymirror.
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#
| Impact | HIGH — frontrun donation to newAddress plants a fresh lock that blocks all migrated matured locks until the donation expires |
| Protocol | Remora Dynamic Tokens |
| Vulnerable code | LockUpManager._newAccountSameLocks append-only migration + availableTokens short-circuit |
| Bug class | Ordering grief / frontrun during investor resolve |
| Finding | Cyfrin — Remora Dynamic Tokens v2.1, 2025-10-22 · #63779 · reporter 0xStalin |
| Report | Cyfrin Remora report |
| Source | AuditVault |
| Status | Fixed at commit 3d6d874. Local synthetic PoC. |
| Compiler | ^0.8.24 (PoC) |
TL;DR#
resolveUsermigrates locks by appending old locks after any locks already onnewAddress.availableTokensstops at the first unexpired entry.- A frontrun transfer/donation to
newAddressplants a fresh lock at the front. - All migrated (already matured) locks stay blocked until the grief lock expires.
- HARM:
availableTokens(newUser) == 0even though a migrated lock is fully matured.
The vulnerable code#
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
newAddressbeforeresolveUser.
Attack walkthrough#
- Old user has 4 locks; one is fully matured.
- Griefer donates 1 token to
newAddress(fresh lock atnow). - Admin calls
resolveUser(old, new)— appends old locks after the grief lock. availableTokens(new) == 0despite a matured migrated entry.
Diagrams#
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
- Standalone PoC + full trace: 63779-migrating-the-existing-locks-for-an-investor-when-is-resolve_exp (evm-hack-registry mirror).
- AuditVault finding: 63779-migrating-the-existing-locks-for-an-investor-when-is-resolve.
Alerts & third-party analyses
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.