No Badge Actors

MHacks 2026 · Best Use of Solana, plus the Judged by an LLM track

A hardware security key for payments, built on DEF CON badges. It checks who you're paying, that they're standing in front of you, and what you're actually signing, before a button press releases the signature.

GitHub repoSolana · Ed25519 · ESP32 / ESP-NOW · Node.js · React · TimescaleDB · Capital One Nessie

Problem

Most payment fraud doesn't break cryptography. It fools people. You pay an impostor using a real business's name, or you approve something different from what you think you're approving. Worse, the screen you confirm on is usually the same phone or app the scammer is coaching you through.

Hardware security keys largely ended phishing for logins. Payments never got the equivalent: a device that verifies the payee, not just the user.

What we built

A payment key on the Solana DEF CON 34 badge. Before it will sign anything, the badge's firmware checks three things on its own screen, out of reach of any app:

  • Who. The payee's badge key carries a record signed by Capital One's issuer key and anchored on-chain through the Solana Attestation Service. "Verified" means the bank knows this business.
  • Present. The payer's badge sends a fresh random challenge over ESP-NOW. The payee's badge has to sign it and answer within a few hundred milliseconds.
  • What. The badge decodes the actual transaction itself (recipient, exact amount, real token) instead of trusting a description of it.

Only when all three pass does the screen turn green (MHacks Merch ✓ verified ● present · 40.00 HACK), and only a physical button press signs. Payments move in HACK, our own SPL token on Solana devnet standing in for a stablecoin.

The demo is built around six beats: verify a merchant, top up, pay, catch an impostor using the same name, catch a tampered transfer that displays 5 but moves 500, then revoke the merchant and watch the next attempt go red.

My part

I owned the product spec, the trust model and the backend.

  • Specs and scope. Wrote the PRD, the shared interface contract (wallet API, signing prefixes, radio message formats, registry record, backend routes) and the per-person build packages, so three people could build firmware, test harness and backend in parallel against one contract. Late in the build I wrote the final scope decision that cut a relay-routing feature to protect the core demo.
  • Issuer and registry. Capital One's issuer key signs one record per verified payee, and the record lands on-chain as a Solana Attestation Service attestation. Bank account numbers never touch the chain: records carry a salted hash, and the salts stay in the backend database. Revocation closes the attestation and turns the payee red on every badge within about 30 seconds.
  • Capital One integration. Three roles for the bank, all through the Nessie API. It's the identity anchor, it funds judges' badges (a Nessie withdrawal pays out HACK) and it settles merchants (an on-chain payment triggers a matching dollar deposit). The bank never moves money on its own initiative, only after a badge-signed payment has landed on chain.
  • Backend and dashboard. A Node server with no framework, on node:http, plus TimescaleDB and a React panel. It ingests every HACK payment live from devnet, then serves signed payee records to badges and handles settlement and top-ups. The panel has an issuer page for verifying and revoking, a live payment feed with badge refusals, and the attack console that builds the tampered transaction.

Ayush built the badge firmware wallet core and Raiana built the test harness, presence timing and attack tooling. The badge OS underneath is Solana OS by spacemandev.

Design decisions

  • Two kinds of keys, like TLS. Each badge key proves "this device." The issuer key proves "this device belongs to this business." The badge checks both. An impostor can copy the name but can't sign with the merchant's key.
  • Verification below the app layer. Every check runs in the badge's C core, not the Lua apps, so a compromised app can't draw a fake green screen.
  • Cutting features to keep the demo honest. We cut relay routing (badges forwarding payments hop by hop for per-hop fees) and a badge-signed bank authorization once it was clear they'd cost the core flow. The relay endpoints stayed built but unused.

Limitations

Keys are software keys. The badge's secure element latched the button bus on warm resets, so we disabled it.

The badge-facing listener has no authentication. That's acceptable on devnet, not beyond it.

Presence is proven by response timing over short-range radio, not distance bounding, so it doesn't defeat a relay attack.

Devnet and a mock bank only, so no real money moved.

Result

Won MLH's Best Use of Solana and the Judged by an LLM track.