Security scanner for NEAR smart contracts

Attack the contract before you trust it.

BitLens reads a contract's deployed WASM, tells you what it can do, then attacks the real bytecode in a local NEAR runtime and reports which defences held and which broke. No source code needed.

Read-only: BitLens only makes RPC view_code / view_access_key_list queries and never sends a transaction. Attacks run in a local simulator.

vulnerable-vault.bitlens-demo
built-in demo contract · 2 broken · 6 held
DANGEROUS
Unauthorised call to admin_drain
  • BROKEN Anyone can call admin_drain: the attacker walked away with +67.8015 NEAR.
  • HELD Non-owner set_owner was rejected: only the owner can call this.
Replay of a real run on one of the four built-in demo contracts. Run it yourself →
0transactions sent
6attack families
~1 sper full assessment
6MCP tools for agents

How it works

1

Read the bytecode

Paste any mainnet account. BitLens fetches the deployed WASM and reads its host imports, exported methods and token standards: can it send NEAR, add keys, redeploy itself, call other contracts?

2

Attack it in a local sim

The real bytecode runs in a local NEAR runtime (near-contract-sim) with an owner, a victim and an attacker: unauthorised admin calls, added keys, same-block double withdraws, failed-transfer refunds, callback out-of-gas, stale yield timeouts.

3

Get a verdict with evidence

Each defence comes back HELD, BROKEN or INCONCLUSIVE, with the receipt trail and who gained or lost NEAR, and you can replay the attack as an animation. If BitLens couldn't drive the contract, it says so instead of guessing.

Text-to-test: describe an attack, get a test

Type an attack in plain English. An LLM (NEAR AI Cloud, with OpenRouter as fallback) translates it into a scenario JSON for this contract. It never writes code. The JSON is validated (real methods only, fixed sim accounts, checks that must hold) and you can review or edit it before it runs on the same engine as the built-in attacks.

Try it in the app
You type

"the attacker calls admin_drain and keeps the money"

{ "steps": [ { "op": "call", "as": "attacker",
    "method": "admin_drain", "attack": true } ],
  "checks": [
    { "check": "net_at_most", "account": "attacker", "near": "0" },
    { "check": "unchanged", "what": "state" } ] }
BROKEN attacker +67.8015 NEAR

For AI agents

An MCP server: your agent checks before it signs

Before signing, the agent hands BitLens the transaction it is about to send. BitLens attacks the contract in a local simulator and answers allow, confirm or block, with the attack that proves it. BitLens never signs: the agent's wallet signs only on allow. MCP server over stdio (official SDK); every tool is read-only and validates its input.

check_transaction

Call it right before signing: allow / confirm / block, with the proof and a replay link.

scan_contract

Capability risk card from the bytecode. Instant.

list_attacks

The attack scenarios that apply, with their scenario JSON.

run_attacks

Runs them in the local sim: status, explanation, receipts, NEAR deltas.

assess_contract

Scan + all attacks → safe / caution / dangerous with reasons.

run_custom_attack

Your agent's own idea, in plain English or as scenario JSON.

Add it in one line

Claude Code
claude mcp add bitlens -- "$PWD/node_modules/.bin/tsx" "$PWD/mcp/server.ts"
Claude Desktop / any MCP client
{
  "mcpServers": {
    "bitlens": {
      "command": "/ABSOLUTE/PATH/TO/bitlens/node_modules/.bin/tsx",
      "args": ["/ABSOLUTE/PATH/TO/bitlens/mcp/server.ts"]
    }
  }
}

Run it from a clone of the repo after npm install and npm run build:runner. Plain-English attacks need NEAR_AI_API_KEY or OPEN_ROUTER_KEY.

YouDeposit 20 NEAR into vulnerable-vault.bitlens-demo.
→ check_transaction(receiver_id: "vulnerable-vault.bitlens-demo", method: "deposit", deposit_near: "20")
BLOCK 2 attacks succeeded in simulation · proof: admin_drain moved +67.8015 NEAR to the attacker
AgentI won't sign this. BitLens returned BLOCK: anyone can call admin_drain and take the whole vault (+67.8 NEAR in simulation), and two same-block withdraw calls both pay out. Your 20 NEAR would be at risk from both bugs.
▶ Replay the attack that blocked it

Condensed from a real agent run (headless Claude Code, only BitLens's tools allowed).

Check a contract now

Try a live mainnet contract (wrap.near, token.sweat, aurora) or one of the four demo contracts.

Open the app View on GitHub