A Call to Nothing Returns True: The Fail-Open Bug in Crypto's Automated Research Layer

CryptoLeo • • Bitcoin

Nine sections. Nine tables. Every cell populated. Every cell read the same three words: information insufficient.

The document was not corrupted. It was not truncated and it was not a draft. It arrived with a risk matrix, a four-row Howey test, a token supply schedule, a competitive landscape table and a disclaimer. It arrived complete in every dimension except the one that matters. The input to the pipeline that produced it was an empty array. The output was a formatted report.

Somewhere between those two facts sits the most common bug class in this industry, and almost nobody is auditing it.

In Solidity, a low-level call to an address that contains no code returns true. Not false. Not an error. True, with empty return data, and any contract that writes require(success) without checking returndata.length will happily proceed as though it has just executed something. Emptiness is indistinguishable from success at the machine level. That is not a metaphor. It is a design decision made in 2014 and inherited by every system that has been built on top of it since, including the ones that do not run on a blockchain at all.

The vacuum that got filled

Crypto has spent the last eighteen months in chop. Sideways price action is unglamorous, but it does something useful to an industry: it strips the narrative premium off projects that were never worth the multiple, and it forces allocators to actually look at what they own. When the tide stops moving, people start reading.

The problem is that there is nothing to read. There are on the order of tens of thousands of tokens with some claim to liquidity, and there are perhaps a few hundred analysts globally who can produce a defensible opinion on any of them. That ratio does not resolve. It has never resolved. The long tail of crypto assets has been dark territory since 2017, and the standard workaround — a Telegram group, a Dune dashboard, a founder's willingness to answer DMs — is not diligence. It is vibes with a chart attached.

Into that gap walked the automated research pipeline. The pitch is predictable because it is correct: 24/7 coverage, nine analytical dimensions, institutional-grade formatting, a fraction of the cost of a junior analyst who will leave for a fund in fourteen months. Every allocator I speak to has either bought one of these or built one internally. Most of them are running on top of a large language model with a retrieval layer and a prompt template that specifies the output sections.

I understand the demand. I have spent the better part of a year auditing AI-crypto hybrids, including a decentralized training-data marketplace where I demonstrated that the proof-of-work mechanism intended to prevent data poisoning was Sybil-exploitable, because the incentive to submit honest data was strictly dominated by the incentive to submit cheap data at scale. The lesson I took from that engagement was not about AI and not about blockchain. It was about seams. When you bolt a verification layer onto an incentive layer, the exploit almost never lives inside either component. It lives in the contract between them.

The pipeline I was handed last week has the same shape. It has two stages. Stage one reads a source document and extracts structured facts: title, source, project, claims, timeline. Stage two consumes those facts and emits a nine-dimension analysis covering technology, tokenomics, market structure, ecosystem position, regulatory posture, team and governance, risk, narrative and supply-chain transmission.

A Call to Nothing Returns True: The Fail-Open Bug in Crypto's Automated Research Layer

Stage one returned nulls. Every field. No title, no source, no project name, no claims, and — critically — an empty information-point array. Stage two received that, and stage two had a template with nine required sections.

So it filled them.

The oracle problem, restated

There is a version of this failure that every DeFi auditor knows by heart, and it is worth stating plainly because the pipeline industry appears not to have internalized it.

An oracle always answers. latestRoundData() on a Chainlink aggregator returns a price, a round ID and an updatedAt timestamp. It does not return an error when the feed is stale. It returns a number, and the number is old, and if the consuming contract does not explicitly check updatedAt against a heartbeat threshold, it will price a liquidation against a market that no longer exists. The oracle is not lying. It is answering a question it was asked in the past, with full confidence, in the present.

An oracle's default behavior under failure is to answer. That is the entire class of exploit in one sentence, and it has drained more value than every reentrancy bug combined.

The EVM has a second, older variant. In November 2017, a library contract in the Parity multisig wallet was left uninitialized — its initWallet function had never been called on the implementation itself, only on the proxies that delegated to it. Anyone could call it. Someone did, took ownership of the library, and then killed it, freezing roughly 150,000 ETH. The bug was not that the code was wrong. The code did exactly what it was written to do. The bug was that an empty state was treated as a valid state, and valid states are callable.

The same pattern reappears in the ERC-4626 vault standard. The first-depositor inflation attack works precisely because the vault starts empty. Zero shares outstanding means the attacker can donate assets directly to the contract, inflate the share price, and cause the next depositor's rounding to work in the attacker's favor. The empty state is not a neutral starting condition. It is an attack surface.

And it reappears, in its purest form, in the token approval loophole I documented in 2021 on a high-profile PFP contract. The project had inherited an outdated OpenZeppelin version with a known approval-pattern weakness. The bug was not exotic. The contract did what it was told with an input nobody had validated. I wrote it up under the title 'Art is Volatile, Code is Not,' and what made people angry was not the finding. It was the implication: the marketing had been audited by thousands of people and the contract had been audited by nobody.

Now read the pipeline report again. Nine sections, each one a table, each table populated with rows, each row labeled with a dimension that had no data behind it. It is a zero-initialized struct that compiled.

What a null input actually costs

The instinct is to call this harmless. No funds moved. No private key leaked. The worst case is a wasted afternoon.

I disagree, and the disagreement is structural rather than moral.

The failure is not that the report contained wrong information. It is that the report contained no information and was formatted identically to a report that did. At the leaf level — the cell, the row, the table — the distinction is legible. Every cell says 'N/A - information insufficient,' which is unusually disciplined. At the aggregation layer it is invisible. A downstream consumer does not read cells. A downstream consumer reads structure: nine sections present, tables non-empty, risk matrix complete, disclaimer attached. The PDF exporter does not know. The Telegram bot that pushes summaries does not know. The allocator skimming at 7:40 a.m. before a Monday investment committee does not know, because the shape of the document communicates completeness more loudly than the text communicates its absence.

That is the transmission chain, and it is the thing worth being afraid of. Empty input becomes a plausibly complete artifact, which becomes a slide, which becomes a position.

I have seen this exact failure mode in a different costume. In 2024, working with legal counsel on the spot-Bitcoin ETF filings, I modeled the liquidity-flow implications of the new custody framework and found that the attestation structure contained a single point of failure that no clause explicitly prohibited. The proofs existed. The proofs were published on a schedule. And the proofs were structurally incapable of demonstrating the thing they were cited to demonstrate, because they attested to a snapshot rather than to a flow. Nobody was lying. The document was complete. The completeness was the problem.

An automated research report that is consumed by an investment committee is the same artifact class. It is a record. If the committee minutes a decision that cites a nine-dimension analysis, that document now exists in a file that a regulator, an auditor or a plaintiff can request. Under MiCA's research and disclosure expectations, under the SEC's marketing rule, under any ordinary fiduciary standard, the question 'who verified this' has an answer, and the answer is nobody. That is not a technical risk. That is a liability with a timestamp on it.

The bug is in the seam, not the model

Here is where I part company with most of the commentary I have seen on this class of problem. The temptation is to blame the model — to argue that it hallucinated, or that it should have known better, or that a larger context window would have caught the empty array. All three of those explanations are wrong, and all three lead to the wrong fix.

The model did not hallucinate. Read the report carefully and you will find that it refused to invent a token supply, refused to name a counterparty, refused to assign a risk rating. It produced the scaffolding and left the scaffolding empty. That is a substantially better outcome than the alternative, which is a report that says 'TVL: $42M' with total confidence and no way for the reader to discover that the number came from nowhere.

The failure is in the interface. Stage two declared, in effect, a function signature of analyze(Facts facts) where Facts is a struct. Solidity has no null. A struct parameter is never absent — it is zero-initialized. So stage two received a zero-initialized Facts, and being a well-behaved function, it computed on it. Solidity's type system cannot express 'I do not know.' Neither can a JSON schema with required fields. Neither could this pipeline.

A bug in the contract is a feature in the exploit. The absence of a null type is not a flaw in Solidity; it is a property that you are supposed to defend against with a require. The pipeline had no require. It had a template.

The correct behavior at the seam is one line: require(facts.length >= 3, "EMPTY_INPUT"). Revert. Emit nothing. Let the caller handle the revert, because the caller is the only party positioned to decide whether an empty result is a retryable condition or a terminal one. A function that returns a formatted response to an unanswerable query is, in the only vocabulary that matters here, unaudited.

I want to be precise about why this is a systems problem and not a prompting problem. Prompt engineering is the practice of persuading a model to behave correctly on the inputs you thought of. Interface design is the practice of making incorrect behavior impossible on the inputs you did not. The industry has invested enormously in the first and almost nothing in the second, which is why every few months we get a new demonstration of a model that will confidently summarize a document it was never given. That is not a capability failure. It is a missing assertion.

The report's own authors understood this. Buried at position seven of nine, in a section about process risk, the document states that 'unable to rate' is itself the largest risk signal, and recommends tagging the output STATUS: EMPTY_INPUT to block automatic aggregation downstream. That is the correct fix. It is also the only section in the entire document that could be written without any input at all, because it was a question about the pipeline rather than a question about the world.

Self-referential analysis is the only analysis that cannot be empty. That is not a small observation.

A Call to Nothing Returns True: The Fail-Open Bug in Crypto's Automated Research Layer

The incentive that manufactures filled tables

None of this is an accident, and none of it is a model failure. It is an incentive failure, and I have written this story before in a different context.

Liquidity mining did not produce liquidity. It produced a number that looked like liquidity for as long as the subsidy ran, and then it produced a cliff. The mechanism was not deceptive; it was exactly as advertised. Pay for a metric and the metric arrives, whether or not anything underneath it does. TVL became a marketing surface, mercenary capital became a business model, and the projects that survived were the ones that stopped paying for the number and started paying for the thing.

Automated research has the same structure with a different unit. Vendors are compensated for coverage, not for abstention. A report that says 'insufficient data across nine dimensions' is a report the customer cannot paste into a deck, cannot forward to an LP, and cannot defend in a quarterly letter. A report with nine tables is a deliverable. The commercial gradient points, with enormous force, toward template completion.

Nobody in this chain is acting in bad faith. The vendor is responding to procurement. The analyst is responding to the vendor. The allocator is responding to the shape of the document because the shape is all they have time to read. And the model, which has no stake in any of it, does what the schema asks.

Smart contracts do not care about your narrative, and neither does a JSON template. Both will execute whatever you hand them. The difference is that one of them reverts when the input is malformed, and only because somebody wrote the revert.

What the bulls got right

The reflexive response from the security side of this industry — my side — is to declare the whole category fraudulent and go back to reading bytecode. That response is wrong, and I want to say so clearly, because the criticism is more useful if it is aimed at the right target.

The abstentions in that report were correct, and correctness under pressure is rare enough to be worth naming. The pipeline did not invent a supply schedule. It did not name a fake competitor. It distinguished between 'rated zero' and 'not rated,' which is a distinction that a striking number of human analysts fail to make. I have read diligence memos, written by people with CFA certificates and Bloomberg terminals, that list 'TVL: $0' for a protocol whose dashboard they simply could not find. The machine was more honest than the professional.

We audited the soul, and it was hollow — but it told us it was hollow. That is a materially different outcome from a system that tells us it is full.

More importantly, the demand is legitimate. Long-tail coverage in this market is genuinely broken, and it has been broken for nine years. A fund with fifty million under management and four hundred names on a watchlist cannot hire four hundred analysts, and pretending otherwise is the same category error as dismissing DeFi in 2020 because a fork got drained. The pipeline exists because a real gap exists. The gap is not going to close on its own.

And there is one more thing the report got right that deserves more credit than it will receive. It audited its own output. It flagged decision-chain contamination as its highest-priority risk, distinguished a process failure from a content failure, and explicitly recommended against downstream consumption. Most post-mortems in this industry are written after the drain. This one was written before, by the system itself, in the seventh of nine sections, which is approximately where you would expect an honest finding to be buried.

Logic is the only currency that never inflates. The pipeline had a little of it, and spent it in the wrong place.

The accountability question nobody wants to answer

Here is the prediction, and I will date it: within eighteen months there will be a public incident in which an allocator's automated research pipeline consumes a malformed or absent input, emits a well-formed report, and that report moves capital into a position that no human being ever actually evaluated.

It will not be called a hack. There will be no exploit contract, no attacker address, no on-chain trail. It will be called a process failure, which is the industry's term for a loss with no accountable party. The post-mortem will recommend additional review layers. The review layers will be automated.

The reason I am confident is that the failure has already happened at least once, in the document I am holding, and it cost nothing only because nobody acted on it. The difference between a near-miss and an incident is a Monday.

The remedy is not better models and it is not more dimensions. It is an assertion at every seam where a downstream system consumes an upstream artifact, and it is a signature on the abstentions. Every automated report should carry the name of a human who is willing to be asked why it says what it says — not just when the tables are full, but specifically when they are not. An abstention with a name on it is a professional judgment. An abstention without one is a formatting artifact.

Reproducibility is the highest form of respect, and the only respect a pipeline can show its input is to refuse when the input is absent. The call to nothing returns true. Somebody has to be the require.

The next decade of exploits will not be found in Solidity. The compiler is getting better, the auditors are getting better, and the contracts are slowly getting boring, which is the highest compliment a contract can receive. The glue is not getting boring. The glue is where the templates live, and the templates are the part nobody has agreed to be responsible for.

So: who signs the N/A?