Guides

Verify a signed package verdict with your own code

Kenwea Protocol,

A verdict is only worth something if you can check it without trusting whoever issued it. Every record Kenwea's notary returns is signed with Ed25519, and the public key is published. This guide verifies a real record in Node.js and in Python, then ties it to the tarball on your disk.

Get a record

npx -y @kenwea/mcp check esbuild --json > record.json

This is the record we got for esbuild 0.28.2 on 30 September 2026, shortened. The part that matters is signedAttestation: payload is a JSON string with the signed facts, and signature is the Ed25519 signature over its exact bytes.

{
  "artifactRef": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
  "verdict": "manual_review",
  "ran": true,
  "exitCode": 1,
  "installScripts": ["postinstall"],
  "contentSha256": "e045f94c235c7adc50e77ba2a579c7bec41b496b6b47c3a7845f7c1e19959a88",
  "signedAttestation": {
    "algorithm": "ed25519",
    "keyId": "00f55dd04da212b3",
    "payload": "{\"issuer\":\"kenwea.com\",\"artifactRef\":\"https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz\",\"contentSha256\":\"e045f94c…\",\"verdict\":\"manual_review\",\"ran\":true,\"exitCode\":\"1\",…,\"constraints\":\"network=none; capabilities=all-dropped; rootfs=read-only\",\"issuedAt\":\"2026-09-30T09:02:51Z\"}",
    "signature": "xd6E15iqwBJ6kyo+LLiWudiou9foP3+nJT1g+Wj4jKZGHtsT61bUldmstwSAT5BdzO134HUgDXaoXjdFvliUCQ=="
  }
}

The public key

The key is published as PEM at https://www.kenwea.com/.well-known/kenwea-attestation-key. The notary's MCP server also returns it through the kenwea.notary.getPublicKey tool, with its keyId, so you can compare it with the keyId in a record.

Verify in Node.js

Node's built-in crypto module is enough. Save this as verify.mjs and run node verify.mjs record.json.

import { createPublicKey, verify } from "node:crypto";
import { readFileSync } from "node:fs";

const { payload, signature } = JSON.parse(readFileSync(process.argv[2], "utf8")).signedAttestation;

const pem = await fetch("https://www.kenwea.com/.well-known/kenwea-attestation-key").then((r) => r.text());
const key = createPublicKey(pem);

// Verify the payload exactly as received. Re-serialising it breaks the signature.
const valid = verify(null, Buffer.from(payload, "utf8"), key, Buffer.from(signature, "base64"));
if (!valid) {
  console.log("INVALID");
  process.exit(1);
}
const facts = JSON.parse(payload);
console.log("valid", facts.verdict, facts.contentSha256);

Verify in Python

With the cryptography package (pip install cryptography):

import base64, json, sys, urllib.request
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.serialization import load_pem_public_key

att = json.load(open(sys.argv[1]))["signedAttestation"]
pem = urllib.request.urlopen("https://www.kenwea.com/.well-known/kenwea-attestation-key").read()
key = load_pem_public_key(pem)

try:
    key.verify(base64.b64decode(att["signature"]), att["payload"].encode("utf-8"))
except InvalidSignature:
    sys.exit("INVALID")
facts = json.loads(att["payload"])
print("valid", facts["verdict"], facts["contentSha256"])

Both print valid manual_review e045f94c… for the esbuild record. We also changed verdict to approved inside the payload and ran both again; both reported INVALID. That is the property that makes a signature useful: nobody, including us, can change the facts after signing without it showing.

Tie the verdict to your tarball

A valid signature says those exact bytes produced that verdict. It says nothing about a URL, which can serve something else tomorrow. So hash what you hold and compare it with contentSha256:

npm pack esbuild@0.28.2
sha256sum esbuild-0.28.2.tgz
# e045f94c235c7adc50e77ba2a579c7bec41b496b6b47c3a7845f7c1e19959a88

npm pack downloads the same tarball npm install uses, so a matching hash means the record describes the bytes you are about to install.

What a valid record does not say

  • A signature is not an endorsement. It records what happened under stated constraints, which the payload names: network=none; capabilities=all-dropped; rootfs=read-only.
  • Records are checked against the key published now. If the key is ever rotated, an older record will fail against the new key; compare the record's keyId with the published one to tell a rotation apart from tampering.
  • If the notary could not fetch an artifact, there is no signature at all, rather than a signed statement that it could not read it.

If you would rather see it work before writing code, the verify page checks a record in your browser, and nothing you paste there is sent anywhere.

Try the notary with no account or key, or add it to your agent as an MCP server.

More guides