
Security News
Agent Baseline Publishes Security Reference Architecture for Software Factories
Agent Baseline’s new reference architecture shows how to secure software factories with four boundaries enforced outside the AI agent.
@fairseal/verify
Advanced tools
Independent verification for FairSeal anchor receipts and VEO-2 objects — structure, integrity, Ed25519 signatures, and on-chain Merkle anchors. ESM + CJS, Node >= 18.
Independent, fail-closed verification for FairSeal receipts (VEO objects).
Every check runs from public inputs. You do not need to trust FairSeal — or this package's authors — to re-verify a receipt: signatures verify against the keys embedded or supplied, and anchors verify against Base mainnet through any RPC you choose.
npm install @fairseal/verify
Requires Node >= 18. Both ESM (
import) and CJS (require) are supported on all Node versions from 18 onward.@noblev2 cryptography is bundled into the dist so CJS consumers do not need--experimental-require-module.
import { verifyVEO } from '@fairseal/verify';
// v0.5.0+: Pass trustedKeys to verify signer identity.
// Without trustedKeys, signed VEOs return valid:false (fail-closed).
// trustedKeys[0] = Ed25519 public key hex (VEO-2) or Ethereum address (VEO-1).
const result = await verifyVEO(receipt, {
trustedKeys: ['<your-provider-public-key-hex>']
});
if (result.valid) {
// ALL checks passed: structure + integrity + trusted-signer
// + on-chain anchor (if present).
} else {
console.log(result.checks); // structure / integrity / signature / anchor
console.log(result.errors); // machine-readable failure reasons
console.log(result.checks.signature?.detail); // e.g. "no_trusted_keys"
}
Breaking change: verifyVEO(veo) without trustedKeys now returns
valid: false with reason: "no_trusted_keys" for signed objects.
In 0.4.x, a signature was verified against the public key embedded in the
object itself — so an attacker could self-sign a forged object and get
valid: true. 0.5.0 closes this: signer identity must come from the caller.
- const result = await verifyVEO(receipt);
+ const result = await verifyVEO(receipt, { trustedKeys: ['<pubkey-hex>'] });
If you need 0.4.x behavior temporarily during migration, use the explicit opt-in:
const result = await verifyVEO(receipt, { allowUnverifiedSigner: true });
// ⚠️ WARNING: this accepts any self-signed VEO — only use when you verify
// signer identity through an out-of-band channel.
| Field | Meaning |
|---|---|
valid | true only when all applicable checks pass and, if an anchor is present, it verified on-chain. Never true for an anchored object whose chain check was skipped or failed. |
structural | Structure + integrity + signature only. Can be true while valid is false (anchor pending/failed). |
anchored | true (verified on-chain) / false (check ran and failed) / "unknown" (chain unreachable) / "not_present" (no anchor on this object) / "not_checked" (structuralOnly mode) |
checks.* | Each check is pass, fail, or skipped with a detail string. |
"We could not verify" and "we verified it is wrong" are different states — this package never collapses them.
const result = await verifyVEO(receipt, { structuralOnly: true });
// result.anchored === 'not_checked'
// result.valid will be false when an anchor is present:
// structurally-valid-but-not-chain-verified is NOT called "valid".
FairSeal API receipts (VEO-1) are signed with personal_sign (EIP-191) over a
canonical serialization:
import { verifyEIP191Signature, canonicalizeVEO1 } from '@fairseal/verify';
const check = verifyEIP191Signature(veo1Object);
// recovers the secp256k1 signer address and compares to the declared signer
import { verifyMerklePath, verifyAnchor, DEFAULT_CONTRACT_ADDRESSES } from '@fairseal/verify';
// Pure sha256 fold — no network needed:
const ok = verifyMerklePath(leafHash, merklePath, expectedRoot);
// Confirm the batch root on Base mainnet via any RPC you trust:
const anchor = await verifyAnchor(anchorInfo, { rpcUrl: 'https://mainnet.base.org' });
verifyMerklePath alone proves inclusion against a root offline; it does
not prove the root is on-chain. Use verifyAnchor (or call
MerkleAnchor.getBatchRoot on any Base RPC yourself) for chain confirmation.
From v0.4.0, verifyAnchor accepts the raw response from
GET /v1/notarize/:receipt_id — no manual field remapping needed:
import { verifyAnchor } from '@fairseal/verify';
// Fetch the receipt directly from the API
const receipt = await fetch('https://api.fairseal.io/v1/notarize/nr_<id>').then(r => r.json());
// Pass it straight to verifyAnchor — adapter auto-detects 'agent_decision' schema
const result = await verifyAnchor(receipt, { rpcUrl: 'https://mainnet.base.org' });
if (result.valid) {
// Receipt is anchored and verified on Base mainnet
console.log('✓ Anchored at block', result.onChain?.blockNumber);
} else {
console.log('✗', result.errors);
}
The adapter maps proof.anchor_tx → tx_hash, proof.anchor_chain → chain,
proof.merkle_root → merkle_root, and the other proof.* fields automatically.
The three accepted schemas and their field sources:
| Schema | Source | Chain field | Tx field | Merkle root field |
|---|---|---|---|---|
agent_decision | /v1/notarize/:id | proof.anchor_chain | proof.anchor_tx | proof.merkle_root |
fairseal-anchor-receipt-v1 | /v2/anchor/:id/receipt | chain | tx_hash | merkle_root |
| VEO-2 | /v1/rng/latest etc. | anchor.chain | anchor.tx_hash | anchor.merkle_root |
Note on Merkle path (multi-leaf batches): notarize receipts encode
proof.merkle_path as a pair-sorted string[]. For single-receipt batches
(the common case) this is always [] and verification runs normally. For
multi-leaf batches the path check is skipped (surfaced as a warnings[] entry)
but the on-chain transaction and contract-state checks still apply — the
anchor is confirmed via the chain, not just the path.
Proves:
Does not prove:
A fully receipted agent can still be wrong. Audit reasoning separately.
verifyVEO(veo, options) / verifyVEOSync(veo, options) — top-level VEO-2 verificationverifyStructure, verifyIntegrity, verifySignature, isSigned — individual VEO-2 checksverifyEIP191Signature, canonicalizeVEO1, eip191Hash, pubKeyToAddress — VEO-1computeMerkleRoot, verifyMerklePath, normalizeHex, toBytes32Hex — MerkleverifyAnchor, DEFAULT_CONTRACT_ADDRESSES, DEFAULT_RPC_URLS — on-chain anchorTOPIC_BATCH_ANCHORED, SELECTOR_GET_BATCH_ROOT, SELECTOR_BATCH_EXISTSMIT
FAQs
Independent verification for FairSeal anchor receipts and VEO-2 objects — structure, integrity, Ed25519 signatures, and on-chain Merkle anchors. ESM + CJS, Node >= 18.
The npm package @fairseal/verify receives a total of 253 weekly downloads. As such, @fairseal/verify popularity was classified as not popular.
We found that @fairseal/verify demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Agent Baseline’s new reference architecture shows how to secure software factories with four boundaries enforced outside the AI agent.

Security News
arXiv now limits authors to two submissions a month as AI slop overwhelms moderators, delays good papers, and sparks debate over applying the limit to everyone.

Research
/Security News
A new GhostAction wave hits hundreds of GitHub repos, expanding CI/CD secret theft to cloud and AI credentials in source code and git history.