i built https://t.co/f63l3iumGB for @NEARProtocol#NEARHackathon
stablecoin payments for businesses, freelancers and soon ai agents
clients don't need to know what a stablecoin is, they just wanna pay
NEAR Intents lets them pay with anything, you still get paid in stablecoins
everyone says “give your ai agent a wallet” like it’s a feature. nobody says what happens the day a webpage tells that agent to pay a stranger.
i kept thinking about that, and it led me to build Ward at NEARHackathon.
the problem
an agent that pays has two options, and both are bad.
give it a full access key, and one prompt injection can drain the account. a hidden line on a webpage, a poisoned tool result, and it signs. the key doesn’t know who’s asking.
or put a human click on every payment. now it’s safe, but you’ve removed the reason to use an agent in the first place.
i wanted a third mode.
the idea
before an agent sends money, it asks Ward first. Ward answers one of three things, and gives its reasons:
allow: the agent pays
warn: a person decides
block: nothing gets signed. the signer is never even called.
and the decision isn’t made by another model. it’s a deterministic score, so nobody can sweet talk it.
how it decides
an account that this agent has paid before, with stable code and no reports against it, is allow.
an account that’s only two hours old is warn. so is one that deployed new contract code in the last 48 hours, or one with a full-access key sitting on a contract. a human looks at it before anything moves.
a missing account is block. so is anything over the treasury cap. so is anything a community report has confirmed as bad.
and if the data isn’t there, the answer is never allow. if the RPC is down, the wrapper doesn’t sign. it fails closed.
the key is the real defense
this is the part i care about most. the agent holds a NEAR function-call key that can do exactly one thing: call pay on one treasury contract.
it can’t transfer NEAR. it can’t attach a deposit. it can’t add keys, deploy code, or delete the account. it can’t call the owner methods. it can’t call any other contract at all.
NEAR enforces that at the protocol level. it isn’t my code promising to behave. even a fully hijacked agent is stuck inside that box.
the shared blocklist
one contract holds both the treasury and a blocklist that gets smarter with use.
anyone can file a report on a bad address, but it costs a 0.05 NEAR bond and needs real evidence, so spam isn’t free. three separate reports block an address on chain, even before the owner reviews them. the owner can confirm or dismiss each one.
and the agent can never file or confirm a report. a function-call key can’t attach the bond, so it can’t write about its own targets. that was on purpose.
what the demo shows
i built an attack that plays out in six scenes, all with one scoped key:
1. a prompt-injected agent tries to pay a known-bad account. Ward says block. signer.called: false. it never reached a signature.
2. the same prompt tries a direct NEAR transfer to that address. the key isn’t allowed to, so it dies before the check even runs.
3. a shop that’s two hours old. Ward warns. the human says no. nothing signed.
4. same warning, human says yes. it signs.
5. an old, active merchant the agent has paid before. allow. signed.
6. a contract that deployed code an hour ago. warn. the human says no.
the attack is 1 NEAR and the cap is 5, so what stops it is the blocklist, not the cap. i wanted it to show the real reason.
one honest note: the known-bad account in the demo is a fixture, and its evidence is synthetic. it isn’t a real victim. everything runs on testnet, and this is a prototype.
try it
you can run the whole attack without keys, accounts, or a database. open the dashboard and press “run the attack”: https://t.co/Y7i0KwJh3x
code: https://t.co/twABqv1LRV
where i landed
agents shouldn’t be trusted because their instructions say so. they should be limited by something they can’t talk their way past: a key that can only do one thing, and a check that never asks a model for permission.
agents get a budget. humans keep the keys. and the rules live where nobody can argue with them.
if you ran an agent you didn’t write yourself, what would you make its default? block anything new, or warn and let you decide?
@NEARProtocol@NearLegion@NearBuilders
NEAR HACKATHON is now live with $250K+ in prizes.
No signup. Just ship a public repo + public demo post between November 1st & Nov 14, 23:59 UTC.
Build on NEAR Intents, chain signatures, chain abstraction, NEAR AI Cloud, & more.
Full details: https://t.co/mkP9hKatU4