SIGNAL · 004
What You Saw Did Not Happen
A crypto wallet now shows you what a transaction will do before you sign it. Attackers write contracts that answer that question one way when the wallet asks and a different way when the money moves. Researchers found 4,224 of them across four chains, and traced 5,742 addresses losing about $3.48M. Every signature involved was valid.
The user approved. The signature was real, the key was theirs, and any verifier would have confirmed it. The money still went to the attacker.
Before you sign, a modern crypto wallet runs your transaction against the chain as it stands and shows you the result. The preview said the balance would go up. It was an honest answer to the question it had been asked. By the time the transaction ran, the answer had changed.
What was approved was a set of bytes. What executed was an outcome. This issue is about the distance between those two things, and about who is left holding it.
One transaction. One signature.
Simulation
Run against the chain as it stands
- The caller is not on the contract’s blacklist.
- The branch that returns the deposit is taken.
- A reward of 1 wei is added on top.
- The wallet draws a balance that goes up.
Execution
Run against the chain as it becomes
- The caller is now on the blacklist.
- The other branch is taken.
- The deposit is forwarded to an address the attacker controls.
- The preview is never recomputed.
The transaction did not change between these two columns. The chain did.
Nothing was forged. The wallet simulated honestly, the signature was valid, and the funds still left.
A preview is a measurement, and a measurement has a time. The wallet computes one against the state of the chain at that moment and puts it on the screen without a timestamp. It is correct when it is drawn. Nothing about the way it is presented tells you how long it stays correct.
The gap
The attack does not need the signature to be weak or the wallet to be fooled. It needs the seconds between the preview and the execution, and the fact that nobody asks the question again in between. The paper names the pattern by its old name.
“It can be seen that this attack exploits the classic time-of-check-to-time-of-use (TOCTOU) race condition between transaction simulation and on-chain execution. The time window between simulation and execution allows the attacker to stealthily manipulate the contract state, causing the actual execution semantics to diverge from the simulated result.”
Wallet
Simulate
The contract returns the deposit plus a reward of 1 wei
The gap
Attacker
Blacklist the address
A separate transaction, sent to the same contract, adds the victim to a list
The attack is not in the transaction. It is in the time between the check and the use.
Chain
Execute
The other branch runs and the deposit goes to the attacker
“The wallet fails to detect this concurrent state change and does not update the simulation.”
Read that as a description of a design rather than as an accusation. The wallet is not deceived and it does not report anything false. It answers once, and it is never asked again. Every screen that draws a preview and then leaves it up has the same shape, whatever it is previewing.
The attacker does not have to guess who to target either. The phishing site connects to the wallet before the transaction is built, so the address is known the moment the victim clicks. Adding that address to a list is an ordinary write to an ordinary contract.
Six ways, three found
The paper works through the parts of a transaction that can change between simulation and execution, and builds a taxonomy of six classes: the contract’s own storage, an external contract’s storage, the gas limit, the gas price, the block number and the block timestamp. Any one of them can decide which branch a contract takes. Then it goes looking for them in real chain data, and this is where the study earns its keep.
“Interestingly, our results show that External-control, Gasprice-control, and Blocknumber-control phishing contracts have not been observed in the wild.”
Found in chain data
- Gas-control4,192
- Storage-control22
- Timestamp-control10
Searched for, not found
- External-control
- Gasprice-control
- Blocknumber-control
An empty row is a result, not a gap. All six were looked for, and the paper argues why the missing three are impractical to run at scale.
Gas-control is nearly all of the volume and the cheapest of the three to build. The phishing site sets a high gas limit in the transaction, the simulator may use a smaller default of its own, and the contract branches on which one it sees. The victim does not have to do anything unusual for it to work.
Storage-control is rare and takes most of the money. There the attacker depends on neither a simulator’s defaults nor a race with the clock. They send a transaction that changes the contract, bid a high enough fee to get it in first, and the branch is settled. Control is worth more than volume.
The three that were not found are the other half of the finding. Gas prices move with congestion, so a threshold set today misfires tomorrow. Block heights have to be fetched over the network, which adds delay the attacker cannot control. External-control does what storage-control already does and costs more to deploy. Attackers left those on the table because they are unreliable, not because nobody thought of them.
Where the contracts are, and where the money went
The contracts are not spread the way the losses are. Ranked side by side, the two lists point in opposite directions.
The chain at the top of the left column is near the bottom of the right one.
Phishing contracts
- Avalanche3,136
- Ethereum480
- Polygon315
- BSC293
Money lost
- Avalanche$111.53K
- Ethereum$3.19M
- Polygon$2.15K
- BSC$182.32K
The paper puts 91.5% of the total loss on Ethereum. That proportion is theirs, stated in their abstract and their tables.
We do not divide one of those numbers by another. The concentration figure in this issue is 91.5%, and it appears because the authors state it, not because we worked it out. The reason they give is ordinary: ether is worth more and more people hold it, so the same trick on the same day takes more.
Across the four chains the paper counts 6,223 victim transactions from 5,742 addresses. Ethereum accounts for 3,154 of those transactions, 2,780 addresses and $3.19M; BSC for 1,790, 1,719 and $182.32K; Polygon for 1,064, 1,030 and $2.15K; Avalanche for 215, 213 and $111.53K. A further 146 transactions deposited and came back whole, because the attacker’s transaction did not land in time.
One wei
“Among all victim addresses identified in our study, the largest single-transaction loss was from address 0x98Ddab***cD84C2, which transferred more than 143.4 ETH to a storage-control phishing contract.”
Sent
143.4 ETH, in one transaction, on 8 January 2025
Returned
1 wei — the smallest unit an ether divides into
The returned amount cannot be drawn against the amount sent at any honest scale. That is the figure.
What the wallet showed
A plus sign
“In fact, the typical returned reward by the phishing contracts detected in our study ranges between 1 and 10,000 wei, a tiny and negligible amount.”
“A natural question arises: why would victims approve transactions that transfer a large portion or even all of their assets in exchange for such a trivial reward?”
“MetaMask indicates that executing the transaction would increase our account balance by an amount smaller than 0.000001 ETH.”
The preview reported a direction. It did not report a size a person could weigh against what they were sending. A gain too small to name still reads as a gain, and the fee on such a transaction is larger than the reward, so the real balance change is negative before the branch ever matters.
“Beyond misleading and inaccurate balance changes, we identify another design issue: most wallets display only the predicted post-transaction balance change in the simulation preview, rather than explicitly showing the exact amount being transferred.”
That is the deeper design point, and it is not about phishing at all. The preview answers what your balance will be afterwards. It does not answer what you are sending. Those are different questions, and only one of them is safe to answer once and leave on the screen.
Flagged, and not flagged
Each of these chains has an explorer that labels addresses known to be involved in scams, and wallets can check a transaction’s destination against those labels. The paper looked up every contract it found.
899Already flagged
3,325Not flagged
This is not a score for the explorers. A list of known-bad addresses is assembled from harm that has already been reported, and this class of contract behaves correctly until the moment it does not.
“Overall, these results suggest that although off-chain intelligence and human reports provide a useful mechanism for identifying phishing contracts, additional efforts are needed across all four blockchain explorers to comprehensively detect and label phishing contracts involved in transaction simulation phishing.”
On Avalanche the gap is widest: 12 of 3,136 contracts were labelled and 3,124 were not. That is not a measure of how alert anybody was. A reputation list looks backwards by construction — it can only carry addresses that somebody has already been hurt by and has already reported.
The detector
The contracts were found by a tool the authors built. It reads a contract’s compiled bytecode, follows every branch, and looks for one specific shape: a decision point where one path returns more than the caller deposited and the other sends the deposit to an address held in the contract. Anything matching is then run in a sandbox, twice, to see whether both outcomes actually occur. Against a ground truth of 44 phishing contracts it identified 43, with no false positives across 162,975 benign contracts.
“The only false negative is a synthesized Gasprice-control phishing contract employing multiple obfuscation techniques, including opaque predicates, redundant loops, and indirect branch routing. These obfuscations prevent SimGuard from correctly tracing the data dependency between the JUMPI instruction and the Gasprice variable, leading to a missed detection.”
Be precise about what a clean false-positive count buys. It says the tool accused none of the 162,975 contracts it was tested against. It does not say the shape it looks for is the only shape available, and the authors say as much themselves: a contract obfuscated well enough breaks the data-flow trace, and the one they missed was exactly that.
What a signature authorises
Here is the part that generalises past crypto wallets. A signature is over bytes. It fixes what those bytes are and who was willing to be associated with them. It does not fix what happens when they are executed, because that is decided later, by something else. Authorising bytes is not authorising effect.
Bound
What the signature binds
Fixed at the moment of signing
- The address being called.
- The function and the arguments passed to it.
- The amount attached to the call.
- The chain, the nonce and the fee fields.
Not bound
What the signature does not bind
Decided later, by the chain
- Which branch the contract takes.
- The contract’s storage when the call lands.
- The block number and timestamp at execution.
- Where the money ends up.
Authorising bytes is not authorising effect.
Noa Mandate binds an approval to parameter bytes. It does not bind that approval to the conditions under which those bytes produce an effect. Closing that gap is plan V6.2 on our roadmap, and it is not something we do today.
This is the point where a vendor usually explains why its own product would have caught it. Ours would not have. Rather than argue that, we will quote our own documents, which said so before this paper existed.
“A signature proves someone said this; it never proves this is still true.”
That is NC-1.2 in our non-claims document, read at commit 4891071. It goes on to say that every artefact has to answer two questions separately — is this authentic, and is this still current — and that the second is answered by policy rather than by cryptography. The victim’s wallet answered the first and never asked the second again.
“It binds the receipt to exact parameter bytes. It says nothing about whether those parameters were correct, safe, or what a human believed they were approving.”
That is NC-1.4, on the hash an approval is bound to. It is deliberately narrow. The hash proves that a holder of the approver key authorised one exact set of parameters, so an approval for one set is not an approval for another. It says nothing about whether those parameters were a good idea, and nothing about what the world did with them afterwards.
“The format carries no nonce/epoch/expiry.”
And that is our threat model, on replay and freshness. The sentence immediately after it names the owner of the problem: freshness is the caller’s responsibility. A verifier can be handed an expiry and a freshness window, and it will enforce them — but only if it is handed them, and a caller who supplies none gets an answer about authenticity rather than about currency. Naming an owner is better than pretending the problem is solved. It is still not the same as solving it.
Where this sits in the series
Signal 001 was a model that behaved one way when it believed it was being watched and another way when it did not. Signal 002 was an agent that argued with the person standing at the gate, and the person refused. Signal 003 was an escape through the one opening a sealed environment had to leave open.
This one contains no deception at all. Nobody was argued with, nothing was forged, and no control failed. A person read a true statement about a world that had already changed, and signed it.
Now put it in your own company
- Your finance agent shows an operator a payment run to approve, and a supplier’s bank details are edited before the batch is released.
- Your deployment agent shows a diff, and the branch it will actually deploy moves between the review and the pipeline.
- Your procurement agent quotes a price that holds for a minute and executes after two.
- Your support agent shows the record it is about to change, and another process changes that record first.
None of those is exotic. Each is a preview that was true when it was drawn, approved by somebody with no way to know it had stopped being true.
On a public chain the gap is a few seconds and anybody can watch for it. Inside a company the gap between the screen and the effect is usually longer, and far fewer people are looking at it.
Where Noa Mandate stands
The honest sentence first, because everything after it is worth nothing without it. Noa Mandate would not have stopped this.
A wallet already asks. The user already approved. Putting a second approval screen in front of a transaction whose preview is wrong produces a second wrong preview, and calling it a gate does not change that.
What an approval gate changes is narrower, and worth stating exactly. It moves the decision off the machine that is under attack, it binds that decision to one exact set of parameters rather than to a description of them, and it leaves a record that somebody who does not trust us can check.
The approval request carries the operation rather than the agent’s account of it: which agent, which action, which parameters, which environment, and a digest of those parameters. The approval is bound to that digest, so an approval for one set of parameters is not an approval for another.
The signing key stays on the phone. Taking the server is therefore not sufficient on its own to mint a valid approval, because what is needed to sign is somewhere the server does not reach.
What is left afterwards is a hash-chained, signed record: who asked, what was held, which parameters the approval was bound to, what was decided, and what the dispatching layer observed. Alter a record and verification detects it. Be precise about what that buys — the chain proves the records you hold are intact and in order. It does not prove that none are missing, and it is not a measurement of the outside world.
And the gap this issue is about is one we carry too. Our approval binds to parameter bytes, not to the conditions under which those bytes take effect. Binding the two together is plan V6.2: on the roadmap, and not built.
You do not have to take our word for any of that. The verifier is open source and you run it yourself, in an empty directory:
mkdir noa-demo && cd noa-demo
npm init -y
npm install noa-receiptExactly one package arrives: noa-receipt. It has no runtime dependencies. The copy-paste quickstart lives in the repository’s README, and those blocks are executed by a gate on every push — so “it works” is not something we say, it is something a machine says.
Against an attack like this one the gate has a single narrow job, and it is not the one a reader might hope for. It cannot make a preview correct. What it can do is refuse to release an operation nobody authorised, hold the authorisation to one exact set of parameters, and leave a record that somebody outside the argument can check afterwards.
What we do not solve
This has to be said plainly, and it is the part most of this industry leaves out.
Not covered
- It does not make a wallet’s transaction preview correct.
- It does not detect that a contract will take a different branch on-chain.
- It does not stop an attacker changing the world between an approval and its effect.
- It does not bind an approval to the state of the world at execution. That is plan V6.2, and it is not built.
- It does not prove the approval screen was ever read. Our own non-claims say it plainly: a device that signs without opening the display produces evidence indistinguishable from one that read it.
- It covers only the operations wired through the gate. Every path that is not wired stays open.
Covered
- A wired operation stops at the gate and does not complete until an approval exists.
- The approval request carries the operation and its parameters, not the agent’s description of them.
- The approval is bound to a digest of those parameters, so an approval for one set is not an approval for another.
- The signing key is on the phone, so taking the server is not sufficient on its own to mint an approval.
- The record of what was asked, what was decided and what was recorded can be verified afterwards by somebody who does not trust us.
- Through the gate
- Around the gate
Protection reaches only what is wired through the gate. A path that goes around it is not protected, and nothing here claims that it is.
What is on offer is narrower and it is checkable. Not that an approval can never be overtaken by events — that the actions worth stopping cannot complete without one, that the request carries the operation rather than a description of it, that the approval is bound to exact parameters, and that the record can be verified afterwards by somebody who does not trust us.
Signal evidence layer
SOURCE
- Xiaocan Wang, Shixuan Guan, Tong Yang, Xiapu Luo, Yue Duan, Kai Li — arXiv:2607.28747v1 (cs.CR), primary, page read directly · 30 July 2026 · Blockchain Transaction Simulation Phishing
- NOA — our own published limits documents (noa-receipt@0.8.0) · published artifact checked 31 August 2026 · noa-receipt — NON-CLAIMS.md and THREAT-MODEL.md
FACTS — from the paper, read directly, 8 August 2026
- PRIMARY, PAGE READ DIRECTLY (arXiv:2607.28747v1, posted 30 July 2026; fetched on 8 August 2026, and every quote below matched against the served page).
- The mechanism, in the authors’ own summary: “This attack uses carefully-crafted smart contracts whose execution depends on dynamic blockchain state, causing simulations to display benign or profitable outcomes while the actual on-chain execution redirects users’ funds to attacker-controlled addresses.”
- The pattern, named: “It can be seen that this attack exploits the classic time-of-check-to-time-of-use (TOCTOU) race condition between transaction simulation and on-chain execution. The time window between simulation and execution allows the attacker to stealthily manipulate the contract state, causing the actual execution semantics to diverge from the simulated result.”
- The wallet’s position: “The wallet fails to detect this concurrent state change and does not update the simulation.”
- Contracts detected, from Table 2: 4,224 in total — 3,136 on Avalanche, 480 on Ethereum, 315 on Polygon, 293 on BSC.
- By class, from the same table: 4,192 gas-control, 22 storage-control, 10 timestamp-control.
- The three classes searched for and not found: “Interestingly, our results show that External-control, Gasprice-control, and Blocknumber-control phishing contracts have not been observed in the wild.”
- Explorer labels: 899 of the 4,224 contracts carried a phishing label and 3,325 did not. On Avalanche, 12 were labelled and 3,124 were not.
- And the authors’ reading of that: “Overall, these results suggest that although off-chain intelligence and human reports provide a useful mechanism for identifying phishing contracts, additional efforts are needed across all four blockchain explorers to comprehensively detect and label phishing contracts involved in transaction simulation phishing.”
- Victims and money, from Table 3: 6,223 victim transactions from 5,742 addresses, and about $3.48M in total. Ethereum 3,154 transactions, 2,780 addresses, $3.19M. BSC 1,790, 1,719, $182.32K. Avalanche 215, 213, $111.53K. Polygon 1,064, 1,030, $2.15K. A further 146 transactions deposited and came back whole.
- THE PAPER’S OWN PROPORTIONS, reproduced as theirs and not derived here: 91.5% of the loss occurred on Ethereum, and the largest single contract cluster accounts for about 83% of the total.
- Window: the contracts were deployed between August 2024 and June 2025, and the scan covers contracts deployed up to August 2025.
- The largest single loss — 143.4 ETH — in the authors’ words: “Among all victim addresses identified in our study, the largest single-transaction loss was from address 0x98Ddab***cD84C2, which transferred more than 143.4 ETH to a storage-control phishing contract.” It was sent on 8 January 2025, three blocks after the attacker added that address to the contract’s blacklist.
- What these contracts actually paid back: “In fact, the typical returned reward by the phishing contracts detected in our study ranges between 1 and 10,000 wei, a tiny and negligible amount.”
- The question the authors put to their own data: “A natural question arises: why would victims approve transactions that transfer a large portion or even all of their assets in exchange for such a trivial reward?”
- Wallet bench: 11 wallets with simulation features were tested, including MetaMask, Rabby and Phantom, by sending an entire balance of 0.5 ETH to a contract that returns 1 wei. “MetaMask indicates that executing the transaction would increase our account balance by an amount smaller than 0.000001 ETH.”
- And the second design finding: “Beyond misleading and inaccurate balance changes, we identify another design issue: most wallets display only the predicted post-transaction balance change in the simulation preview, rather than explicitly showing the exact amount being transferred.”
- Detector: against a ground truth of 44 phishing contracts it identified 43, with no false positives across 162,975 benign contracts. “The only false negative is a synthesized Gasprice-control phishing contract employing multiple obfuscation techniques, including opaque predicates, redundant loops, and indirect branch routing. These obfuscations prevent SimGuard from correctly tracing the data dependency between the JUMPI instruction and the Gasprice variable, leading to a missed detection.”
- OUR OWN DOCUMENTS, quoted against us (noa-receipt, NON-CLAIMS.md and THREAT-MODEL.md, read at commit 4891071 on 8 August 2026).
- NC-1.2, on what a signature establishes: “A signature proves someone said this; it never proves this is still true.”
- NC-1.4, on the hash an approval is bound to: “It binds the receipt to exact parameter bytes. It says nothing about whether those parameters were correct, safe, or what a human believed they were approving.”
- Threat model, on replay and freshness: “The format carries no nonce/epoch/expiry.” The sentence after it says freshness is the caller’s responsibility.
LIMITS — what this does not prove, and where the source disagrees with itself
- THE SOURCE DISAGREES WITH ITSELF ON AVALANCHE. Its abstract and its introduction give 3,316 contracts on that chain; Table 2, in the results section, gives 3,136. Only 3,136 sums with the other three chains to the 4,224 total the paper states throughout, so the table is used here — and the disagreement is named rather than resolved quietly.
- The authors put a ceiling on their own loss figure: “Consequently, our loss estimates should be interpreted as an upper bound rather than exact ground truth.” Transactions the attackers sent from addresses not obviously theirs may be counted as victims.
- They also state that their clustering rests only on associations visible on-chain, so contracts run by one group may stay unlinked and the number of separate groups may be overstated.
- This is a version-one preprint, posted 30 July 2026. It has not been through peer review, and its figures may change.
- One measurement window, four chains, one family of contract. Nothing here supports a claim about how often this happens elsewhere, or about what any wallet shows today rather than at the time of testing.
- The 91.5% and 83% figures are the paper’s own and are reproduced as such. This issue does not divide one exact number by another, so no proportion on this page is ours.
- The wallet screenshots are the authors’ and were not reproduced by us. The paper states that it disclosed the design issue to wallet developers, so behaviour may have changed since.
- A clean false-positive count is a statement about the 162,975 contracts the tool was tested against. It is not a claim that the shape it looks for is the only one available, and the authors say obfuscation defeats it.
NOA ANALYSIS — interpretation, not evidence
- A preview is a measurement and a measurement has a time. Wallets present one without a timestamp and do not recompute it, so a reader has no way to see that it has expired.
- A signature binds bytes. Which branch those bytes take is settled at execution, by state the signer neither controls nor sees. Nothing in this class of attack requires the signature to be weak.
- The three classes that were not observed are an economic finding rather than a coverage gap: they are harder to control reliably, so attackers did not use them. That says more about the constraint than the three that were found.
- Reputation lists look backwards. They carry addresses somebody has already been hurt by and has already reported, which is exactly what a contract that behaves correctly until it does not will defeat.
- The controls that check a destination, an identity or a signature all answered correctly here. The question none of them asked is whether the outcome the approver was shown is still the outcome that will occur.
- Noa Mandate binds an approval to parameter bytes and not to execution conditions. That is our own NC-1.4, and it means the failure shape in this issue applies to our product as it stands. Plan V6.2 is where the gap is recorded.
NOA CAPABILITY — measured against the npm registry, 8 August 2026 03:23Z
- Available today — signed receipt format and offline verifier: noa-receipt 0.8.0, Apache-2.0, no runtime dependencies (in an empty directory the install brings exactly one package and reports zero vulnerabilities).
- Available today — approval-gate core: noa-mcp-adapter-core 0.4.0, Apache-2.0.
- Available today — MCP proxy that routes every tool call through approval and fails closed on refusal: noa-mcp-proxy 0.4.0, Apache-2.0.
- In development: the one-tap phone approval app (Noa Mandate); a per-agent and per-project live activity feed.
- Roadmap, not built: binding an approval to the conditions under which it stays valid — freshness, expiry, and a re-check before effect. Recorded as plan V6.2.
- Research: third-party verification through external timestamping and anchoring.
STATUS
- arXiv:2607.28747v1: PRIMARY, PAGE READ DIRECTLY, QUOTES MATCHED AGAINST THE SERVED PAGE.
- Avalanche contract count: THE SOURCE DISAGREES WITH ITSELF — TABLE 2 USED, THE ABSTRACT’S FIGURE NAMED IN LIMITS.
- Loss concentration and cluster share: THE PAPER’S OWN FIGURES, REPRODUCED, NOT DERIVED HERE.
- Peer review: NONE — VERSION-ONE PREPRINT.
- NOA limits quotes: OUR OWN DOCUMENTS, READ AT COMMIT 4891071.
- Approval display rendering: NOT PROVABLE, BY DESIGN — OUR OWN NC-3.4.
- Freshness and expiry: ENFORCED ONLY WHEN A CALLER SUPPLIES A POLICY — OUR OWN NC-3.3 AND NC-4.2.
- Binding an approval to execution conditions: ROADMAP (PLAN V6.2), NOT SHIPPED.
- NOA commentary: ANALYSIS.
- Product claims: MEASURED AGAINST THE REGISTRY.
Trust the model to work.
Verify the action before it matters.