On the morning of August 1, 2022, the Nomad bridge lost roughly $190 million in under three hours. The size was not the interesting part. The texture was. Most of the wallets that drained it did not write an exploit. They copied one โ pasted the same calldata, swapped the recipient address, and sent it. Hundreds of them. Many had no prior on-chain history at all.
The root cause fit inside a single initialization line: a Merkle root of 0x00 โ the null root, the value a mapping slot holds when nobody has ever written to it โ had been registered as acceptable. From that moment, an unset root and a valid root were the same object to the verifier. The bridge was not fed a lie. It accepted an absence and called it truth.
That distinction, absence versus falsehood, is the most underpriced risk surface in this industry. It is also the one almost nobody audits for, because there is nothing to look at. A missing input throws no exception in the EVM. It returns a value โ zero, empty bytes, a success boolean โ and the protocol treats that value as meaningful.
I have spent nine years staring at this specific failure mode, first as an auditor, later as a full-time trader. The pattern has not changed. Only the size of the loss has.
The Defaults Are Load-Bearing
Start with the machine. The EVM has no concept of "undefined" in the way a high-level language does. Every storage slot is initialized to zero. Every unset address is address(0). Every unset uint is 0. A call to an address with no code returns (true, "") โ success, with empty return data.
That last one is worth sitting with. In Solidity, someAddress.call(data) returns true when someAddress is an externally owned account with no contract behind it. The call did nothing. The boolean says it worked.
This is not a bug in the EVM. It is a design consequence. The chain is a ledger of state transitions, and "no transition" is a legal transition. But it means every protocol that consumes external input is sitting on top of a default-value layer that will happily impersonate a valid answer. The security burden is not detecting malicious data. It is distinguishing "I received nothing" from "I received the right thing."
ERC-20 made this worse by accident. The original standard specifies that transfer returns a bool, but several of the most liquid tokens in existence โ USDT on Ethereum being the canonical example โ return nothing at all. A naive caller doing require(token.transfer(...)) reads the empty return data as a failed call. The entire SafeERC20 pattern exists to patch a decade-old ambiguity: the difference between a function that returns false and a function that returns nothing has cost more money than most chains have in TVL.
Once you see the default-value layer, you start seeing it everywhere. Not as a curiosity. As the load-bearing member of an entire class of exploits.
Three Bridges, Three Nulls
Nomad is the cleanest case because the null was literal. But it is not an outlier. It is a template.
In February 2022, Wormhole lost approximately $326 million on Solana. The attacker did not forge a guardian signature set. They passed an empty one. The verification path relied on a syscall that had been deprecated in the Solana runtime, and the deprecated path returned success rather than failing closed. The bridge's guardian verification was structurally present and functionally absent โ and the two states were indistinguishable to the calling contract. One hundred twenty thousand wrapped ETH minted against nothing.
Eighteen months later, in July 2023, Curve Finance lost on the order of $70 million across several pools. The source code contained @nonreentrant decorators. The lock was there, in the source, in the audit, in the diff. It was not there in the deployed bytecode. A miscompiled storage slot in Vyper versions 0.2.15 through 0.3.0 meant the reentrancy guard read and wrote the wrong location, so the guard evaluated as unlocked every single time. The protection existed as a promise and not as a mechanism.
Three bridges, three different layers of the stack, one shared structure. In each case a verifier asked a question, received a default value, and interpreted it as consent.
History repeats, but the signature changes. The 2018 vintage was integer overflow; the 2020 vintage was oracle manipulation; the 2022โ2023 vintage is default-value confusion. The mechanism mutates. The logic of the failure does not.
Wrong Data Alarms. Missing Data Does Not.
There is a reason nulls are deadlier than lies, and it is not purely technical. It is about instrumentation.
On November 26, 2020, Compound's DAI oracle โ sourced from a single Coinbase Pro market โ printed an anomalous price. The feed was present and wrong. Liquidations cascaded, roughly $80 million of positions were closed at bad prices, and some accounts were wiped. It was ugly. It was also loud. The price number moved on every dashboard in the industry within minutes. Discussion followed immediately. The inputs were bad, but the inputs were visible.
A null input does none of that. When a subgraph redeploys and a protocol's TVL silently reads zero, an automated alert that checks "is TVL below threshold" fires โ but a human chart-watcher reads it as a data gap and moves on. When a liquidity pool sits empty, its reserve values are zero, which is a perfectly valid number. When a sequencer goes quiet, no transaction reverts. The chain is simply still.
Silence before the volatility spike is not the market holding its breath. It is often a data pipeline that has stopped reporting, and the trades that follow it are being priced off nothing.
I learned this the expensive way. In the DeFi Summer of 2020 I put $15,000 into a volatile stable-pool strategy, chasing an APY I had not decomposed. What I did not model was the oracle path. When a related protocol was hit with a flash-loan-induced dislocation, my pool's price ratio moved against me, and the impermanent loss plus slippage took 40% of principal. The lesson was not "high APY is bad." The lesson was that I had priced the yield and never priced the input. Impermanent is a promise, not a guarantee โ and neither is a feed that has never returned 0.
The Empty Market Is an Attack Surface
Move from the oracle to the order book, and the null reappears in a form that has produced a steady stream of 2024 losses: the empty state.
In May 2024, Sonne Finance on Optimism lost roughly $20 million. The exploited market was freshly deployed and effectively empty โ zero supply, zero borrows. An empty market looks like a neutral object. It is not. It is a state where share accounting has no history to anchor against, where a first depositor's rounding error is unconstrained, and where a direct token donation can shift the exchange rate arbitrarily because the denominator is still near zero.
The generalized version is the ERC-4626 inflation attack, and it has been rediscovered dozens of times under dozens of names. An empty vault is not a blank slate. It is an unpriced option on the first depositor's arithmetic.
Compare that to how Uniswap V4 handles callbacks, and you can see what correct design looks like. V4 pools store a hook address, and address(0) means no hook โ that is a legitimate null. But when a hook is configured, the pool manager does not accept an arbitrary return. It requires the callback to return a specific bytes4 selector and reverts if it does not match. If the hook returns nothing, or returns the wrong thing, the pool fails loudly.
That is the discipline the rest of the stack is missing. V4 does not ask "did the callback succeed?" It asks "did the callback return the exact thing I expected?" The first question is answerable by silence. The second is not.
I have a stake in this argument. My own view is that V4's hooks turn the DEX into programmable Lego, and simultaneously raise the complexity ceiling past what 90% of developers will comfortably clear. But the callback-verification pattern they chose is the correct one, and it should be copied far more widely than the hooks themselves.
Where the Nulls Are Hiding Now
If the mechanism is stable across time, the correct exercise is not nostalgia. It is locating the current instances.
Layer 2 data availability. The sequencer on every major rollup is, operationally, a single node. "Decentralized sequencing" has been a slide in a deck for roughly two years. The null case here is precise: if the sequencer stops posting batches to L1, the chain does not experience a visible failure. Block production simply pauses. Users see nothing; L1 sees an inbox that has gone quiet. The forced-inclusion escape hatch in the L1 contracts is the mechanism that is supposed to make this survivable, and it is exercised approximately never, which means its real-world latency under stress is an untested assumption. A rollup whose data availability depends on a single operator posting is a rollup whose state of the world is indistinguishable from an operator that has stopped.
Cross-chain messaging. The omnichain narrative sells deployment counts. Nine chains, twelve chains, one shared codebase. The relevant question is not how many chains a contract lives on. It is what each chain's verifier does when it receives an empty message, a message with a zero payload, or no message at all at a given block height. Those are three different states, and most applications collapse them into two.
The analytics layer. This is the one that touches the reader directly. RPC providers return stale block heights during reorgs. Indexers return partial result sets without erroring. A subgraph that has not been re-synced returns zero rows, which renders identically to zero activity. When I opened a $100,000 ETF-versus-spot ETH arbitrage in early 2024, the edge existed precisely because price data arrived at different moments across five venues โ I was trading the latency of the data, not the price itself. Absence at time T is itself a signal. The market whispers, the blockchain shouts, but a dashboard that has stopped updating does neither.
I should say clearly that I have made this exact mistake in the opposite direction. In May 2022 I refused the "bad actors" framing of the Terra collapse and spent two weeks reverse-engineering UST's stabilization mechanism from Etherscan and DeFi Llama data, building a simulation that showed the death spiral was arithmetically inevitable below a definable liquidity buffer. The model worked and the prediction landed hours before the terminal cascade. But the input that actually mattered was not in the model at all. The failure was not a bad number. It was the absence of any bid โ a quantity that never appears in a supply schedule because it was never there to begin with.
My 2017 audit work on the ERC-20 transferFrom path taught me the earliest version of this lesson. The replay vulnerability I found was not an injected value; it was a value that was valid on two chains at once. Same signature, two ledgers, no domain separation. Reuse is just another form of check-skipped.
And in November 2022, when Celsius's published numbers had stopped being verifiable, I moved $50,000 in USDC into a multi-sig hardware setup in Auckland rather than waiting for confirmation of what the balance sheet actually contained. I did not know Celsius was insolvent. I knew the data was unverifiable, and for risk purposes, unverifiable and false occupy the same cell.
Verify the code, trust the ledger. Which includes trusting it when the ledger says nothing โ and treating that nothing as the loudest line in the block.
The Audit Economy Is Optimized for the Wrong Threat
Here is the contrarian read, and it is uncomfortable for the security industry I used to work inside.
The bug-bounty and audit economy rewards spectacle. It pays for found exploits, for disclosed attack paths, for the dramatic proof-of-concept that drains a forked mainnet in a Foundry test. There is no comparable market for "the verifier accepted an empty input and nobody noticed for eleven months." Absence has no CVE number.
So the collective attention lands on malicious inputs: reentrancy we can demonstrate, oracle manipulation we can plot on a chart, governance attacks we can narrate. Meanwhile the entire default-value layer goes under-reviewed, because reviewing it requires asking a question that has no satisfying answer โ not "can this be broken?" but "what does this do when it is handed nothing?"
The same failure is present in analysis, not just in code. The most dangerous artifact produced in this industry is not a bad prediction. It is a confident, well-formatted report built on an empty data package. A ten-section framework filled with "N/A" reads as systematic rigor and functions as camouflage. If the inputs are absent, the only honest output is a refusal โ and refusing is the one result nobody pays a subscription for.
Risk is the price of admission. But there is a difference between paying for risk and paying for the absence of information while believing you bought the risk. Logic survives the emotional wash, and logic has to be applied to the input set before it is applied to the conclusion. Pattern recognition precedes profit realization; it also precedes loss avoidance. The order matters.
The Null-Input Checklist
What follows is the part that can be executed this week.
For anything you are about to underwrite, ask four questions in this order. First: what does this contract do when the value it expects is 0, address(0), or empty bytes โ not "when it is malicious," but "when it is silent." Second: is there any instrument on my dashboard that would distinguish a data outage from zero activity, and would it alert, or would it just render a clean chart? Third: for any multi-chain deployment, what is the failure mode when the message never arrives โ and does the application distinguish that from an empty message? Fourth: does the guard I am relying on live in the source, in the test suite, or in the deployed bytecode? Only the third one settles the trade.
Track the boring signals. Inbox quiet time on L1 per rollup, measured against the sequencer's stated cadence. The delta between a protocol's last indexed block and current head. Whether a vault's first-depositor threshold is enforced in code or in a deployment script. These will not trend on social media. They will also not be in the post-mortem you read after the fact.
The next large loss will not arrive as an attack. It will arrive as a quiet return of zero, accepted by code that never asked whether zero meant anything. The question worth sitting with is not which protocol is next. It is whether, when the silence comes, your tooling will notice โ or whether it will render it as a flat line and let you call that stability.