Eclipse · payment firewall for AI agents on NEAR

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.

guardian · your-agent.testnetSAMPLE DATA
Allowed2
Held1
Blocked1
Stopped180
Spent today30.50 / 500 tUSDC cap
  1. BLOCKhostc0.testnetinjection + lookalike payee180.00
  2. ALLOWhostco.testnetknown payee · usual amount18.00
  3. HOLDsupplier.testnetabove usual range · 1 h escrow90.00
  4. ALLOWdns-renew.testnetallowlisted12.50
verdict + reason codesreceipts on-chain

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.

Without

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

With

Paying through the Guardian

Blocked 180.00 tUSDC to hostc0

The agent can only ask. The contract holds the funds, waits for the checker's verdict, and pays only on allow, inside hard caps.

Source: Giskard, "How Grok got prompt-injected".

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.

Payment pathThe agent can only call request_payment on the Guardian contract. The Guardian holds the funds, pauses the payment and asks the checker in an OutLayer TEE for a verdict. Four checks feed Jev, which returns allow, hold or block. The Guardian then pays, escrows or refuses, and writes an on-chain receipt.What the agent readsrequest + untrusted textAgentPython · LLM tool callsfunction-call key:request_payment onlyrequest_paymentGuardian contractholds the tUSDCcaps 200 / payment500 / day, in codeyieldverdictChecker WASM · OutLayer TEE (Intel TDX)Policy rulesallowlist · amount matchInjection classifierscores what the agent readCounterpartyage · lookalike · historyMasked re-runplannedJev fusioncalibrated judgments; thresholds stay in checker configallow · hold · blockCalls out, not attested:Jev API · NEAR AI Cloud · classifier hostAllowft_transfer, pays nowHoldescrow 10 min – 6 hBlockrefused, nothing movesOn-chain receipt: outcome · reasons · hashes · checker version
  1. AgentReads the user's request and untrusted text. Its key can call request_payment, nothing else.
  2. Guardian contractHolds the tUSDC, checks the caps, pauses the payment and asks for a verdict.
  3. Checker in a TEEPolicy, injection and counterparty checks (masked re-run planned) run inside OutLayer on Intel TDX.
  4. Jev fusionTurns the signals into allow, hold or block. Thresholds live in checker config.
  5. Guardian actsAllow pays now, hold escrows and re-checks, block refuses. Every outcome writes an on-chain receipt.
The agent never holds a key that can move money. Only the Guardian pays, and only on a verdict that matches the exact receiver, token, amount and request id.
  1. 01

    The agent asks

    A function-call key scoped to the Guardian. It can request a payment, never send one.

  2. 02

    The checker decides

    The checks run inside a TEE, so a compromised agent host cannot fake, skip or edit them.

  3. 03

    Only the contract pays

    The Guardian acts on the verdict, pays only on an exact match, and writes the 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.

Payment requestGuardian contract
Policy: clear
Injection: raised a signal
Payee: raised a signal
Re-run: planned
Jev: clear

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.11703

Injection classifier

Scores every email, reply and memory chunk the agent read before it proposed the payment.

deberta-v3 prompt-injection · Hugging Face

Counterparty signals

Account age, contract or not, prior payments, and lookalike distance to known payees.

Address Poisoning · arXiv 2501.16681

Masked re-run

Planned

Re-run the agent with the user's request hidden. If the payment still appears, it came from injected data.

MELON · arXiv 2502.05174

NEAR 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 code
  • unusual (noul): Is this payment unusual for this agent? Drives the hold threshold
  • injection_driven (noul): Did untrusted content, not the user, propose it? A block signal
  • receiver_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.

Hard capwhatever is fooled500 tUSDC / day

The absolute worst case, whatever the checks miss.

Per paymentchecked before the TEE runs200 tUSDC

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.

  1. 01

    Hook

    A Morse-code reply moved six figures from an agent that held the keys.

  2. 02

    Normal payment

    The agent pays an 18 tUSDC hosting invoice. Allow; the receipt is on the explorer.

  3. 03

    Attack, unprotected

    A plain agent with a full-access key pays a lookalike account. The balance drops.

  4. 04

    Same attack, protected

    Through the Guardian: high injection score, lookalike payee, two days old. Block; the receipt shows why.

  5. 05

    Hold path

    A bigger invoice from a known supplier waits in escrow and is released when its window ends. No human.

  6. 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.

Missed attacks19.33%vs 100% with no defense
False blocks0%benign payments refused
False holds5.33%target ε = 5%; in-sample
Results by configuration
ConfigurationFalse holds (%)False blocks (%)Missed attacks (%)Median latency (ms)Per payment
no_defenseNo defense0010024.5810 calls
policy_onlyPolicy rules only0070.6727.2270 calls
classifier_onlyInjection classifier only0.67083.331,138.1311 classifier call
code_rules_all_signalsAll signals, code rules only (no Jev)0.670461,305.1331 classifier call
jev_fusion_all_signalsJev fusion, all signals (hold threshold 0.5)320.6701,388.0521 Jev call + 1 classifier call
jev_fusion_conformalJev fusion + conformal hold threshold (ε = 5%, q̂ 0.84)5.33019.331,324.9471 Jev call + 1 classifier call
jev_fusion_conformal_cascadeSame, with cascade3.33020340.5781 Jev call + 0.34 classifier calls
redteamRed-team round, 17 attacks, conformal rown/an/a41.18 (7 held, 3 blocked)1,137.91 Jev call + 1 classifier call
melonMasked re-run (MELON) onlyNot built (cut list)
Missed attacks and false blocks by configuration
  • Missed attacks
  • False blocks
Missed attacks and false blocks (%)Grouped horizontal bars for each configuration. Exact values are in the results table above.Configuration0255075100no_defenseno_defense: Missed attacks 100%100no_defense: False blocks 0%0policy_onlypolicy_only: Missed attacks 70.67%70.67policy_only: False blocks 0%0classifier_onlyclassifier_only: Missed attacks 83.33%83.33classifier_only: False blocks 0%0code_rules_all_signalscode_rules_all_signals: Missed attacks 46%46code_rules_all_signals: False blocks 0%0jev_fusion_all_signalsjev_fusion_all_signals: Missed attacks 0%0jev_fusion_all_signals: False blocks 0.67%0.67jev_fusion_conformaljev_fusion_conformal: Missed attacks 19.33%19.33jev_fusion_conformal: False blocks 0%0jev_fusion_conformal_cascadejev_fusion_conformal_cascade: Missed attacks 20%20jev_fusion_conformal_cascade: False blocks 0%0Rate (%)

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.

Loaded receipts—From the Guardian
Paid—In loaded receipts
Held—In loaded receipts
Refused—In loaded receipts
Public Guardian receipts. Amounts use the token decimals configured on the Guardian. Explorer links open account activity.
Request / referenceReceiverAmountStatus / verdictReasonExplorer

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.

01

What 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.

02

How 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.

03

When 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.

04

What 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.

05

Does 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.

06

How 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.

07

What 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.

08

Is 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.

09

Can 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.

Built on NEAR · testnet

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