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 keys are 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.jsonThis is the record we got for esbuild 0.28.2 on 8 October 2026, shortened. The part that matters is signedAttestation: payload is a JSON string with the signed facts, keyId inside it names the key that signed it, and signature is the Ed25519 signature over the payload's exact bytes.
{
"artifactRef": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
"verdict": "manual_review",
"reasonCode": "step_timed_out",
"ran": true,
"exitCode": 124,
"installSteps": ["postinstall"],
"observed": { "network": [], "dns": [], "programs": ["node", "npm"], "missing": [], "truncated": false },
"contentSha256": "e045f94c235c7adc50e77ba2a579c7bec41b496b6b47c3a7845f7c1e19959a88",
"signedAttestation": {
"algorithm": "ed25519",
"keyId": "322a2536e0d5ec8e",
"keysUrl": "https://www.kenwea.com/.well-known/kenwea-attestation-keys.json",
"payload": "{\"issuer\":\"kenwea.com\",\"format\":2,\"checker\":\"2026-10-08.2\",\"keyId\":\"322a2536e0d5ec8e\",\"artifactRef\":\"https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz\",\"contentSha256\":\"e045f94c…\",\"verdict\":\"manual_review\",\"reasonCode\":\"step_timed_out\",…,\"constraints\":\"network=none; capabilities=all-dropped; rootfs=read-only; user=nobody\",\"issuedAt\":\"2026-10-08T10:17:08Z\"}",
"signature": "bokdmQd987lbvsGxSkVnsZ2ZPSGEqfTRcbz4NQlPE6x8lMl+H86K2bI3O6wL+AFC47sEJaLYSmWWpZPGSbYiCg=="
}
}The public keys
Every key Kenwea has signed with is listed, with its status, at https://www.kenwea.com/.well-known/kenwea-attestation-keys.json. A key is active, retired or revoked, and a record signed with a revoked key is worth nothing, because whoever held that key could have made it. The first key was revoked on 8 October 2026, when it turned out its private half had been kept in a cloud-synced folder; every record from before that date names no key and was signed with it. The active key alone is also published as PEM at https://www.kenwea.com/.well-known/kenwea-attestation-key, and the notary's MCP server returns the list through kenwea.notary.getPublicKey.
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 { createHash, createPublicKey, verify } from "node:crypto";
import { readFileSync } from "node:fs";
async function check(file) {
const { payload, signature } = JSON.parse(readFileSync(file, "utf8")).signedAttestation;
const facts = JSON.parse(payload);
// Every key Kenwea has signed with, and its status. A record names its key.
const { keys } = await fetch("https://www.kenwea.com/.well-known/kenwea-attestation-keys.json").then((r) => r.json());
const entry = keys.find((k) => k.keyId === facts.keyId);
if (!entry || entry.status === "revoked") {
return "NOT TRUSTED " + (facts.keyId ?? "(no keyId)") + " " + (entry ? entry.status : "not a published key");
}
// The keyId is derived from the key; recompute it rather than trust the list.
if (createHash("sha256").update(entry.publicKeyBase64).digest("hex").slice(0, 16) !== entry.keyId) {
return "the key list entry does not match its keyId";
}
// 32 raw bytes, wrapped as SPKI so node:crypto can read them.
const der = Buffer.concat([Buffer.from("302a300506032b6570032100", "hex"), Buffer.from(entry.publicKeyBase64, "base64")]);
const key = createPublicKey({ key: der, format: "der", type: "spki" });
// Verify the payload exactly as received. Re-serialising it breaks the signature.
if (!verify(null, Buffer.from(payload, "utf8"), key, Buffer.from(signature, "base64"))) return "INVALID";
return "valid " + facts.verdict + " " + facts.reasonCode + " " + facts.contentSha256;
}
const answer = await check(process.argv[2]);
console.log(answer);
process.exitCode = answer.startsWith("valid ") ? 0 : 1;Verify in Python
With the cryptography package (pip install cryptography):
import base64, hashlib, json, sys, urllib.request
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
att = json.load(open(sys.argv[1]))["signedAttestation"]
facts = json.loads(att["payload"])
# Every key Kenwea has signed with, and its status. A record names its key.
keys = json.load(urllib.request.urlopen("https://www.kenwea.com/.well-known/kenwea-attestation-keys.json"))["keys"]
entry = next((k for k in keys if k["keyId"] == facts.get("keyId")), None)
if entry is None or entry["status"] == "revoked":
sys.exit("NOT TRUSTED %s %s" % (facts.get("keyId", "(no keyId)"), entry["status"] if entry else "not a published key"))
# The keyId is derived from the key; recompute it rather than trust the list.
if hashlib.sha256(entry["publicKeyBase64"].encode()).hexdigest()[:16] != entry["keyId"]:
sys.exit("the key list entry does not match its keyId")
key = Ed25519PublicKey.from_public_bytes(base64.b64decode(entry["publicKeyBase64"]))
try:
key.verify(base64.b64decode(att["signature"]), att["payload"].encode("utf-8"))
except InvalidSignature:
sys.exit("INVALID")
print("valid", facts["verdict"], facts["reasonCode"], facts["contentSha256"])Both print valid manual_review step_timed_out e045f94c… for the esbuild record (run on 8 October 2026 with Node.js 24 and Python 3.11 with cryptography 44). 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. A record from before 8 October, signed with the revoked key, prints NOT TRUSTED in both.
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
# e045f94c235c7adc50e77ba2a579c7bec41b496b6b47c3a7845f7c1e19959a88npm 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; user=nobody.
- A rotation does not break old records: a retired key stays in the list, so its records still verify. A revoked key stays in the list too, so its records can be recognised and refused rather than mistaken for 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.