Evidence that a server runs the code that was published.

Attestium is a Node.js library for remote attestation. It collects evidence of what a machine runs and verifies it against references the verifier obtains itself.

Publishing source code proves nothing about production. Attestation makes that claim checkable by anyone.

npm install attestium
Format
JSON evidence, version 2
Binding
Nonce and SHA-256 digest
Hardware
TPM 2.0, IMA, SEV-SNP, TDX
Runtime
Node.js 18+ on Linux
License
MIT

How it works

Following the IETF remote attestation architecture (RATS), the attester reports facts and never decides. The verifier trusts nothing from the machine that it cannot check against an outside reference or a hardware signature.

The verifier sends a nonce, the attester answers with evidence, the verifier compares it with references it fetched itself and publishes a result. Attesteron the server Verifierin CI Referencesregistries, git, archives Relying partystatus page 1 nonce16–64 random bytes 2 collect factscompute evidenceDigesthardware signs both 3 evidencenonce, digest, files, processes 4 fetch by digest 5 referencescommits, tarballs, layers, .debs 6 check nonce, digest, signaturecompare every fact 7 result
  1. Verifier to attesternonce Sends a nonce: 16 to 64 random bytes, hex encoded.
  2. Attestercollect Collects facts about files, packages, processes and containers, computes evidenceDigest, and asks the TPM or CPU to sign both values.
  3. Attester to verifierevidence Returns the evidence: nonce, digest, files, processes and any hardware statement.
  4. Verifier to referencesfetch Fetches references itself, by digest: the commit, lockfile-pinned tarballs, image layers, signed archives.
  5. References to verifierreferences Each reference is checked against the digest that names it.
  6. Verifiercompare Checks the nonce, the digest and the hardware signature, then compares every fact with its reference.
  7. Verifier to relying partyresult Publishes the result, pass, fail or inconclusive, with its evidence level.
A replayed answer fails the nonce check, changed evidence fails the digest check, and evidence produced elsewhere fails the hardware check. Without hardware, a server that controls its attester can forge the whole answer. Nonce and digest binding Forged answers

What it verifies

Every running file must be explained by a reference: a verified package, an image layer, an official release, a signed archive or a hardware measurement. Hover, focus or tap an element to see what is compared with what.

  1. 1Npnpmnpm. Every file under node_modules, compared with the registry tarball that pnpm-lock.yaml or package-lock.json pins.
  2. 2PyPyPIPyPI. Virtual environments, compared with the wheels that uv.lock, pylock.toml, poetry.lock, Pipfile.lock or hashed requirements pin.
  3. 3RbRubyGemsRubyGems. Bundler's vendor/bundle, compared with the .gem files pinned by the CHECKSUMS section of Gemfile.lock.
  4. 4HxHexHex. Mix's deps/, compared with the tarballs pinned by the outer checksums of mix.lock.
  5. 5CpComposerComposer. vendor/, compared with the git tree of the commit that composer.lock pins.
  6. 6MvMavenMaven. Directories of jars, compared with the hashes in Gradle verification metadata or a Maven lockfile.
  7. 7NgNuGetNuGet. A published .NET application, compared file by file with the packages whose content hashes packages.lock.json pins.
  8. 8GoGoGo. The build information inside a Go binary, compared with go.sum and the commit. The binary's own hash proves the rest.
  9. 9RsRustRust. The cargo-auditable crate list inside a binary, compared with Cargo.lock at the commit.
  10. 10NbNativeNative. The hash of a running binary, compared with a signed checksum list, an artifact attestation, a release manifest or a pinned hash.
  11. 11NdNode.jsNode.js. The node executable, compared with bin/node inside the official release archive listed in SHASUMS256.txt.
  12. 12OcOCIOCI. A container's root filesystem, compared with the image layers fetched by digest from the registry and applied in order.
  13. 13DbDebianDebian. Each running file's owning Debian or Ubuntu package, compared with the .deb reached from the signed InRelease file.
  14. 14TpTPMTPM. A TPM 2.0 quote over SHA-256(nonce ‖ digest), checked with the attestation key pinned at enrollment and expected PCR values.
  15. 15ImIMAIMA. The kernel's measurement log, replayed to the quoted PCR 10. Each running file's hash is compared with its measurement.
  16. 16SnSEV-SNPSEV-SNP. An AMD SEV-SNP report over SHA-512(nonce ‖ digest), chained through the VCEK to AMD's root, with debugging off.
  17. 17TdTDXTDX. An Intel TDX quote over SHA-512(nonce ‖ digest), chained to Intel's root. The MRTD is compared with the expected image.
  18. 18SgSigstoreSigstore. A Sigstore bundle: the Fulcio certificate chain, the Rekor log entry, and the signer identity the verifier requires.
  19. 19GaGitHubGitHub. A GitHub artifact attestation for a file's SHA-256, signed for the expected repository, workflow and ref.
  20. 20CsChecksumsChecksums. A published checksum list signed with gpg, minisign or Sigstore. The file's hash must be in the list.
  • Packages
  • Binaries and runtimes
  • System
  • Hardware
  • Signatures

Ecosystems and referencesHardware-backed evidenceSignatures and trust

Evidence levels

The strength of a result depends on what backs it. Report the level with every result. Security model and limits

  1. 1Software evidence

    Backed by
    The attester's report, bound to the nonce by the digest.
    Proves
    Drift, failed deploys, modified files and packages, injected libraries, attached debuggers, unexplained programs.
    Does not prove
    Anything against root that anticipates the check: root can run a modified attester.
  2. 2TPM-bound

    Backed by
    A TPM 2.0 quote over the nonce and digest, signed by an attestation key pinned at enrollment.
    Proves
    The report came from the enrolled machine, now; with pinned PCRs, that it booted the expected firmware and kernel.
    Does not prove
    That root did not misreport files and processes after boot.
  3. 3TPM and IMA

    Backed by
    The quote, plus the kernel's IMA log replayed to the quoted PCR 10.
    Proves
    The logged hashes are the files the kernel loaded, even against a hostile root user.
    Does not prove
    Files outside the IMA policy, or a compromised kernel or firmware.
  4. 4Confidential VM

    Backed by
    An AMD SEV-SNP or Intel TDX report over the nonce and digest, chained to the vendor's root.
    Proves
    The VM's launch measurement, with debugging off, in memory the host cannot read.
    Does not prove
    Software loaded after launch, unless the launch measurement covers it.

Example

An attester answers a nonce with evidence about a deployed directory. The verifier checks shape, nonce and digest, then compares every file with a checkout of the expected commit.

On its own this is software evidence: whoever controls the attester can forge it. A TPM quote with a pinned key and IMA, or a confidential VM, makes a forgery fail.

Build an attester and a verifier Forged answers

example.js
const fs = require('node:fs');
const os = require('node:os');
const {evidence, fileTree, util} = require('attestium');

(async () => {
  // Verifier: a fresh nonce.
  const nonce = util.generateNonce();

  // Attester: hash the deployed files and answer the nonce.
  const {entries, errors} = await fileTree.walkTree('./app');
  const files = {};
  for (const entry of entries) {
    util.setOwn(files, entry.path, [entry.type === 'symlink' ? `symlink:${entry.target}` : entry.sha256, entry.mode]);
  }

  const document = {
    type: evidence.TYPE,
    version: evidence.VERSION,
    nonce,
    collectedAt: new Date().toISOString(),
    attester: {name: 'example-attester', version: '1.0.0'},
    host: {hostname: os.hostname(), kernel: os.release()},
    services: [{
      name: 'app', kind: 'directory', root: './app', realRoot: fs.realpathSync('./app'), git: {commit: null}, files, fileCount: entries.length, errors, installs: [], processes: [], userProcesses: [],
    }],
    executables: [],
    libraries: [],
  };
  document.evidenceDigest = evidence.evidenceDigest(document);

  // Verifier: shape, nonce and digest first; then every file against the reference.
  const {valid} = evidence.validateEvidence(document);
  const bound = document.nonce === nonce && evidence.evidenceDigest(document) === document.evidenceDigest;
  const reference = await evidence.createManifest('./reference', {repository: 'example/app', commit: 'a'.repeat(40)});
  const service = document.services[0];
  const differ = [...new Set([...Object.keys(reference.files), ...Object.keys(service.files)])]
    .filter(file => String(reference.files[file]) !== String(service.files[file]));

  console.log(valid && bound && differ.length === 0 && service.errors.length === 0 ? 'pass' : `fail: ${differ.join(', ')}`);
})();

Two projects with different purposes.

Attestium

The library and the format: collecting facts on a machine, the evidence schema, and the checks against each kind of reference. Use it to build an attester or a verifier, to verify one thing, or to implement the format in another language.

Implement it in another language

Audit Status

A ready-made tool built on Attestium: one binary with an attester, invoked over a restricted SSH key, and a verifier that runs in CI and publishes reports and a status badge.

auditstatus.com

A project by Forward Email, the open-source, privacy-focused email service, which publishes verification results for its own production servers on status.forwardemail.net.