# vyper empty string nonreentrant key silently produces no reentrancy checks at runtime CVE-2023-42441 is a silent semantic mismatch in Vyper's `@nonreentrant` decorator: when the lock key is an empty string (`@nonreentrant("")` or `@nonreentrant('')`), the compiler silently omits all reentrancy lock code from the generated bytecode. The function compiles without error, the decorator appears to be in place, but no lock is ever acquired or checked at runtime. Any function decorated this way has zero reentrancy protection. The root cause is that the compiler's code generation path for `@nonreentrant` treated the empty string as a valid key but then produced no corresponding storage slot allocation or lock/unlock opcodes. The empty key bypassed the internal logic that maps key strings to storage slots, effectively producing a no-op decorator. This falls into the "Class D: Silent Semantic Mismatch" taxonomy of Vyper vulnerabilities — the code appears valid, the compiler accepts it without warnings, but the runtime behavior differs fundamentally from developer intent. Affected versions span from v0.2.9 through v0.3.10. The fix in v0.3.10 added input validation to reject invalid identifiers as nonreentrant keys: empty strings, whitespace-only strings, and strings starting with digits are all disallowed. Contracts compiled with affected versions that used empty string keys as their reentrancy lock are fully vulnerable to reentrancy attacks despite appearing protected. This vulnerability is especially dangerous because it would not be caught by source-level code review — the decorator looks correct. Only bytecode inspection or compiler-version-aware tooling would reveal the missing lock. Since [[reentrancy is possible whenever external calls precede state updates]], any contract relying on an empty-string `@nonreentrant` decorator rather than the [[checks-effects-interactions pattern prevents reentrancy by updating state before external calls|checks-effects-interactions pattern]] is directly exploitable. --- Relevant Notes: - [[reentrancy is possible whenever external calls precede state updates]] — the vulnerability class left unprotected by this bug - [[checks-effects-interactions pattern prevents reentrancy by updating state before external calls]] — defense that works regardless of decorator correctness - [[vyper compiler reentrancy lock storage slot bug broke cross-function reentrancy protection in versions 0.2.15 through 0.3.0]] — another @nonreentrant decorator bug with a different mechanism - [[vyper nonreentrant decorator uses a single global storage lock eliminating cross-function reentrancy by design in versions 0.4.0 and later]] — the redesigned system that eliminates named lock keys entirely - [[vyper default function did not respect nonreentrancy decorator prior to v0.3.0 allowing reentrancy through the fallback path]] — a third @nonreentrant failure from the same era - [[explicit returns from solidity modifiers do not affect function return values allowing silent control flow bypasses]] — analogous silent semantic mismatch: code that appears to enforce a constraint but silently fails Topics: - [[vulnerability-patterns]]