Skip to content

VMGuardian ​

VMGuardian audits WebAssembly bytecode. It runs in three places with the same code, so a contract gets the same score everywhere:

WhereWhen
The browser (WASM module)Instantly, before you send a deploy
Every validator, in consensusOn every deploy transaction — the gate
Every node, in the backgroundContinuously, on every deployed contract

How a score is made ​

1. Rules (heuristics) ​

The analyzer decodes the code section instruction by instruction (one linear pass, so even a 512 KiB contract is analyzed quickly) and checks five patterns. Each match adds risk; the total is capped at 1.0.

RuleSeverityAddsTriggers on
reentrancycritical0.40A dynamic call_indirect followed by a storage write
uncapped_loopcritical0.35A loop with no conditional branch out of it
unbounded_memorywarning0.20More than 8 memory.grow instructions
unchecked_callwarning0.15A call whose result is dropped
large_import_surfaceinfo0.10More than 20 imported host functions

A score below 0.5 is reported as safe.

2. Neural network ​

A small embedded network (10 inputs → 32 → 16 → 1, 897 parameters) scores the same bytecode from ten features: share of uncapped loops, reentrancy pattern, dropped calls, density of memory.grow, imports, indirect calls, stores, loops and arithmetic, and code size. It runs inside the node without any ML runtime.

3. Blend ​

if |network − rules| > 0.25:   risk = rules                 (model: "heuristic")
else:                          risk = 0.3 × network + 0.7 × rules   (model: "ml+heuristic")

The network gets the smaller weight and is ignored when it disagrees strongly — it is trained mostly on synthetic data plus real, safe contracts from a public CosmWasm chain, and needs real exploit data before it can be trusted more.

The security score shown everywhere is 100 − risk × 100.

The deploy gate ​

Every validator runs the gate on each deploy transaction — see Deploy contracts:

CaseResult
Bytecode hash on the trusted list (official templates such as NRC-20)Score 100, no analysis
Gate switched off by governance (deploy_security_enabled = 0)Neutral score 70
risk ≥ deploy_risk_threshold (default 0.80)Deploy fails, no fee; logged with its violations; counted in nc_deploy_rejected_total
OtherwiseContract created with its score

Check a contract yourself ​

bash
curl -s -X POST "$NODE_RPC/api/v1/contracts/analyze" \
  -H 'Content-Type: application/json' -d "{\"bytecode_hex\":\"$HEX\"}"
json
{
  "risk_score": 0,
  "security_score": 100,
  "safe": true,
  "ml_score": 0.439,
  "model": "heuristic",
  "violations": [],
  "gas_estimate": 34550
}

(Here the network said 0.44 while the rules said 0, so the rules alone decided.)

Through the gateway, use POST /api/v1/contracts/audit with the same body. The gateway never scores contracts itself; it only forwards to the node.

Signed attestation ​

POST /api/v1/contracts/attest runs the same analysis and signs the result with the node's ML-DSA-65 key:

json
{
  "score": 100,
  "risk_score": 0,
  "bytecode_hash": "18642df0…",
  "timestamp": 1791200887,
  "signature": "665a7ab2…",
  "pubkey": "6e80bab8…",
  "model": "heuristic",
  "ml_score": 0.439,
  "violations": []
}

The signed message is "nc-attest|" ‖ score (4 bytes, big-endian) ‖ SHA3-256(bytecode) (32 bytes) ‖ timestamp (8 bytes, big-endian). The browser verifies it with the same WASM module the wallet uses, and the deploy page then shows the attested score.

An attestation proves which node computed the score. Proving that the score was computed correctly, without trusting the node, is the goal of the ZKML work below.

Certificates ​

Contracts receive an on-chain security certificate by score:

TierScore
Gold90 and above
Silver75 – 89
Bronzebelow 75

Certificates are records of the ncert.app system contract, deployed at genesis, and indexed for the API: GET /api/v1/certificates, /certificates/:id, /certificates/contract/:address.

Continuous monitoring ​

Each node re-analyzes deployed contracts every MONITOR_INTERVAL_SECS (20 s). When a score moves by MONITOR_SCORE_THRESHOLD (10) points or more — typically after a new model version is activated — the node issues a certificate update through consensus, and the oracle log records score_degraded or score_improved.

The gateway adds activity alerts on top (contract_alert over WebSocket): unusual call spikes, and low-score contracts that start being called.

Model versions ​

Model weights are versioned on chain, so all validators run the same model:

  1. A validator registers a new version (POST /api/v1/models/register, validators only) — it enters voting for 2 000 blocks.
  2. Other validators fetch the weights over P2P, check their hash against the registration, and confirm.
  3. With confirmations from 2f + 1 validators the version becomes active and replaces the previous one; without them it is rejected at the deadline.

Registry: GET /api/v1/models/registry. Prometheus: nc_model_active_count, nc_model_voting_count, nc_model_version{…}.

Verifiable AI experimental ​

The plan is to prove VMGuardian's result with a zero-knowledge virtual machine (RISC Zero / SP1): a proof that this score is analyze_v2(bytecode) under the weights the chain approved, checkable by anyone — including another chain — without trusting any node. The models are small enough for this to be practical.

How it is tested: the design and a prover scaffold are in the repository (docs/zkml-poc.md, neurochain/zkml/). Building the prover needs the RISC Zero / SP1 toolchain, which has not yet been run in the project's build environment; there is no on-chain verification yet.

Limits ​

  • Trained on synthetic data and real safe contracts only — it has not yet seen real exploits in WASM.
  • Byte offsets of findings and custom rule sets are not available yet.
  • A clean score means no known risky pattern was found, not that the contract is correct.