Give your agent a wallet, not the keys.
Funds sit in a contract on NEAR that the agent can't control. Every payment is checked off the agent's host, and every verdict leaves a receipt anyone can read.
- BLOCKhostc0.testnetinjection + lookalike payee180.00
- ALLOWhostco.testnetknown payee · usual amount18.00
- HOLDsupplier.testnetabove usual range · 1 h escrow90.00
- ALLOWdns-renew.testnetallowlisted12.50
Agent wallets get drained by text
Prompt injection turns an agent's own tools against its wallet. Guardrails that run on the agent's host can be skipped by the agent they are meant to stop.
Guardrails on the agent's own host
May 2026About $150,000 drainedA Morse-code reply on X made Grok's linked wallet pay out DRB
KeysFull-access key on the agent hostThe agent can move every token it holds
ChecksSkippedThe guardrail ran on the compromised host
PayeeLookalike accounthostc0 instead of hostco, two days old
Paying through the Guardian
Blocked 180.00 tUSDC to hostc0The agent can only ask. The contract holds the funds, waits for the checker's verdict, and pays only on allow, inside hard caps.
The agent asks, the checker decides, only the contract pays
Four checks run on every payment. Jev fuses their signals into one verdict: allow, hold or block.
- AgentReads the user's request and untrusted text. Its key can call request_payment, nothing else.
- Guardian contractHolds the tUSDC, checks the caps, pauses the payment and asks for a verdict.
- Checker in a TEEPolicy, injection and counterparty checks (masked re-run planned) run inside OutLayer on Intel TDX.
- Jev fusionTurns the signals into allow, hold or block. Thresholds live in checker config.
- Guardian actsAllow pays now, hold escrows and re-checks, block refuses. Every outcome writes an on-chain receipt.
Nothing moves
The injection classifier flags the reply the agent read, and the payee is a two-day-old lookalike of a known one. Two detectors agree, so the Guardian refuses.
Same checks on every payment. Only the verdict changes.
- Example
- 180 tUSDC to hostc0 after a Morse-code reply
- Wait
- none
- Moves
- 0 tUSDC
- Receipt
- refused, with reason codes
- Whatever is fooled
- 200 tUSDC per payment, 500 per day, in contract code
Policy rules
Allowlist, memo and amount sanity; the amount must match the user's request or invoice.
Progent · arXiv 2504.11703Injection classifier
Scores every email, reply and memory chunk the agent read before it proposed the payment.
deberta-v3 prompt-injection · Hugging FaceCounterparty signals
Account age, contract or not, prior payments, and lookalike distance to known payees.
Address Poisoning · arXiv 2501.16681Masked re-run
PlannedRe-run the agent with the user's request hidden. If the payment still appears, it came from injected data.
MELON · arXiv 2502.05174NEAR holds the money and the rules
Custody, key scope, caps, settlement and the audit log all live on-chain. The AI never touches funds.
Contract custody
The Guardian contract holds the tUSDC. The agent cannot move it directly.
Scoped access key
The agent account has only a function-call key limited to request_payment. It cannot transfer, add keys or touch NEAR.
Yield and resume
request_payment pauses the contract; the checker's verdict resumes it. Pay only on an exact receiver, token, amount and request_id match.
NEP-141 settlement
Payments are ft_transfer calls on a mock tUSDC token (6 decimals) on testnet.
On-chain receipts
Outcome, reason codes, input and record hashes, and the checker version, written per payment.
Checker in a TEE
OutLayer runs the checker WASM inside Intel TDX and publishes the attestation for each run.
Jev makes the judgment calls
Jev (TypeSafe) turns the raw signals and the agent's payment history into calibrated judgments. Caps, sums and dates stay in code.
Four typed questions, one request
verdict(choice): Neutral labels A / B / C, mapped to allow / hold / block in codeunusual(noul): Is this payment unusual for this agent? Drives the hold thresholdinjection_driven(noul): Did untrusted content, not the user, propose it? A block signalreceiver_risk(score): Known payee, new but plausible, or suspicious? A block signal
Hold when it's unusual
A payment is held when Jev's unusual score passes a conformal threshold set at ε = 5% on a pooled set of normal payments. An agent gets its own threshold after 99 normal payments.
Block only when two detectors agree
Above the threshold and two attack signals from different detectors, at most one of them from Jev.
Hardened against the gate itself
- Neutral option labels, so names can't steer the answer
- Untrusted text goes in as data only
- Probabilities never reach the agent or the chain
- If Jev fails or times out, a NEAR AI Cloud LLM decides and the record says so
No AI ever decides an amount
A Jev gate alone is not a security boundary. The limits that bound the loss are in contract code.
The absolute worst case, whatever the checks miss.
Larger requests are refused outright.
- Contract code
Verdict bound to the request
Receiver, token, exact amount and a one-time request_id; any mismatch is refused
- Contract code
Hard caps
200 tUSDC per payment, 500 tUSDC per day
- Contract escrow
Hold windows
10 min under 20 tUSDC, 1 h up to 100, 6 h above
- Checker code
Whole units only
Amounts in the token's smallest unit, compared with the request or invoice
- Contract code
Per-payee budgets
A new payee starts at 20 tUSDC; an allow above the budget waits in escrow like a hold; each paid transfer raises the budget to twice that amount, up to the per-payment cap
Same agent. Same attack. Different outcome.
About two minutes, recorded on testnet with real transactions.
- Demo video goes here once recorded
- 01
Hook
A Morse-code reply moved six figures from an agent that held the keys.
- 02
Normal payment
The agent pays an 18 tUSDC hosting invoice. Allow; the receipt is on the explorer.
- 03
Attack, unprotected
A plain agent with a full-access key pays a lookalike account. The balance drops.
- 04
Same attack, protected
Through the Guardian: high injection score, lookalike payee, two days old. Block; the receipt shows why.
- 05
Hold path
A bigger invoice from a known supplier waits in escrow and is released when its window ends. No human.
- 06
Numbers
Missed attacks, false blocks and false holds from the evaluation, with latency and calls per payment.
Measured, not promised
Every check on and off over 150 benign and 150 attack payments (six attack families), decided by live Jev calls with the injection classifier on. Read from docs/results/results.json.
| Configuration | False holds (%) | False blocks (%) | Missed attacks (%) | Median latency (ms) | Per payment |
|---|---|---|---|---|---|
| no_defenseNo defense | 0 | 0 | 100 | 24.581 | 0 calls |
| policy_onlyPolicy rules only | 0 | 0 | 70.67 | 27.227 | 0 calls |
| classifier_onlyInjection classifier only | 0.67 | 0 | 83.33 | 1,138.131 | 1 classifier call |
| code_rules_all_signalsAll signals, code rules only (no Jev) | 0.67 | 0 | 46 | 1,305.133 | 1 classifier call |
| jev_fusion_all_signalsJev fusion, all signals (hold threshold 0.5) | 32 | 0.67 | 0 | 1,388.052 | 1 Jev call + 1 classifier call |
| jev_fusion_conformalJev fusion + conformal hold threshold (ε = 5%, q̂ 0.84) | 5.33 | 0 | 19.33 | 1,324.947 | 1 Jev call + 1 classifier call |
| jev_fusion_conformal_cascadeSame, with cascade | 3.33 | 0 | 20 | 340.578 | 1 Jev call + 0.34 classifier calls |
| redteamRed-team round, 17 attacks, conformal row | n/a | n/a | 41.18 (7 held, 3 blocked) | 1,137.9 | 1 Jev call + 1 classifier call |
| melonMasked re-run (MELON) only | Not built (cut list) | ||||
- Missed attacks
- False blocks
Attacks caught, by family cascade row, q̂ 0.84
- Direct injection24/25
- Encoded injection23/25
- Fake invoice13/25
- Indirect injection24/25
- Lookalike receiver23/25
- Memory poisoning13/25
- The false-hold bound assumes live payments look like the calibration set (exchangeability). The 5.33% is measured on the same benign set used to calibrate (in-sample) and is above the 5% target.
- Detection covers the six evaluated attack families. Against new or adaptive attacks, the loss is bounded by the hard caps in contract code: 200 tUSDC per payment, and 500 tUSDC committed per UTC request day. Payouts on one day can also include holds committed the day before.
- Latency includes the injection classifier running on a local CPU. Cost is unpriced, so the table shows calls per payment. More sets (external held-out, PaySim, BEC) are in the README Results section.
Don't trust us. Read the receipt.
The receipt proves which checker version ran on which inputs. It does not prove Jev or the LLM answered correctly; those run outside.
Payment receipts
NEAR testnet · Read only · No wallet needed
Guardian: guardian-v2.jimuelle-firewall.testnet (opens in a new tab)
stub_allow (Scaffold decision) is a hard-coded allow.
| Request / reference | Receiver | Amount | Status / verdict | Reason | Explorer |
|---|
Reading the Guardian…
Fetching public payment receipts from testnet.
Run the dry-run, no keys needed
From the repo root. Needs Rust and uv. Full steps, including testnet, are in the README.
# 1. build the checker cargo build -p checker --release # 2. a benign payment cd agent && uv sync uv run firewall-demo --scenario benign-hosting # 3. the Morse-code attack uv run firewall-demo --scenario attack-morse-lookalike
Questions, answered plainly
Short answers about what Eclipse is, how it decides, and what it does not cover.
01What is Eclipse?
Eclipse is a payment firewall for AI agents on NEAR. The agent holds only a function-call key that can ask a Guardian contract for a payment. The contract holds the funds, pauses each request, and pays only after a checker running off the agent's host returns allow.
02How does it stop prompt-injection payments?
Each payment request runs a checker: policy rules (the amount must match the request or invoice), an injection classifier on everything the agent read, and counterparty signals such as account age and lookalike distance to known payees. TypeSafe Jev fuses these signals into allow, hold or block.
03When is a payment held or blocked?
A payment is held when Jev's "unusual" score is above the conformal threshold (q̂ 0.84, ε = 5%) or when a non-Jev detector raises an attack flag. It is blocked only when the score is above the threshold and two attack signals from different detectors agree, at most one of them from Jev. Thresholds live in the checker's configuration, not in prompts.
04What does NEAR do in this design?
NEAR holds the funds in the Guardian contract, limits the agent's key to one method, pauses each request with yield and resume, pays only on an exact match of receiver, token, amount and request id, enforces hard caps (200 tUSDC per payment, 500 tUSDC per UTC day) and writes an on-chain receipt for every payment.
05Does a human approve payments?
No. Allowed payments are paid at once, unless the amount is above the payee's budget (a new payee starts at 20 tUSDC), in which case they wait like a hold. Held payments wait in escrow for a window set by the amount (10 minutes under 20 tUSDC, 1 hour up to 100, 6 hours above) and are then released by a release_held call, which any account can send. The owner can cancel a hold. No AI decides an amount.
06How well does it work?
On 150 benign and 150 attack payments across six attack families, Jev fusion with the conformal threshold missed 19.33% of attacks (100% with no defense), with 0% false blocks and 5.33% false holds. The false-hold figure is in-sample and above the 5% target. Fake-invoice and memory-poisoning attacks are the weakest families.
07What are the limits?
Detection covers the six evaluated attack families; new or adaptive attacks are bounded only by the hard caps in contract code. The masked re-run (MELON) and a re-check during the hold window are not built. The false-hold bound assumes live payments look like the calibration set.
08Is it live on mainnet?
No. It is a NEAR HACKATHON 2026 build that runs on NEAR testnet with a mock tUSDC token (6 decimals). The receipts panel on this page reads the testnet Guardian live.
09Can I try it without keys?
Yes. From the repository, build the checker with cargo build -p checker --release, then in agent/ run uv sync and uv run firewall-demo --scenario benign-hosting, then the attack-morse-lookalike scenario. The dry-run needs no keys and no funds.
Every payment leaves a receipt.
Deploy a Guardian, scope the agent's key to one method, and every payment from then on is checked and recorded.
- Hard caps: 200 tUSDC per payment, 500 tUSDC per day, in contract code
- Scoped access key
- Checker in a TEE
- On-chain receipts
- Verdict bound to the request
- No AI ever decides an amount