npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sigilctl

v0.2.0

Published

Verifiable authorization receipts for AI agents. Prove what your agents were allowed to do — and what they were denied.

Readme

Sigil

Sigil produces verifiable authorization receipts for AI agents: prove what your agents were allowed to do, and what they were denied.

An authorization decision that cannot be checked outside the system that made it is an assertion, not evidence. Sigil records one allow or deny decision at a time, signs it, chains it to preceding decisions, and can anchor the chain with an independently trusted witness.

The problem

MCP's 2026-07-28 release candidate was published 2026-05-21 and schedules its final specification for 2026-07-28. Its six authorization-hardening SEPs strengthen OAuth/OIDC deployment, but do not define a portable, per-tool execution authorization model; servers and operators still decide what scopes permit. See the official release-candidate announcement and authorization draft. The final is not yet published as of this README's 2026-07-27 date.

This distinction matters in measured systems. A June 2026 benchmark (arXiv:2606.29073, published 2026-06-27) reports that its connection-layer mitigation baseline, including per-call approval, permitted 6 of 10 modelled attacks; its runtime that enforced scoped capability invocation as an execution invariant blocked all 10. That is a result about the authors' model and implementation, not a claim about every MCP deployment.

Credential practice is uneven. Astrix Research's October 2025 analysis of more than 5,200 open-source MCP server implementations reports that about 8.5% used OAuth; its methods and limitations are in the research report. The same study reports that about 53% used long-lived static API keys or access tokens. These are separate, cited survey findings—not a vulnerability count or a claim that static credentials are always exploitable.

Sigil is the missing evidence layer around the decision: an operator can later show an allowed call, a denied over-scope call, the signing key, and the chain state without giving an auditor the authority to modify the log.

60-second quickstart

Scan a checkout for MCP-facing risk indicators:

npx sigilctl scan .

No findings. is the expected output on a repository that configures no agents — it reports on agent configuration and credential surface, so there is nothing for it to say about a project that has neither. Point it at a checkout carrying .mcp.json, .claude.json, a .cursor/ or .vscode/ MCP config, or a committed .env.

Check a remote MCP endpoint's authorization posture against the 2026-07-28 changes, without installing anything or touching a receipt store:

npx sigilctl probe https://mcp.example.com

A probed server chooses the metadata URLs probe follows, so only the origin you typed is contacted by default. If an endpoint advertises its authorization server on another origin — ordinary in real deployments — probe reports the origin it claimed and stops there; name it to check it:

npx sigilctl probe https://mcp.example.com --allow-origin https://auth.example.com

A server you are diagnosing therefore cannot aim the tool at a network you did not choose. Two further limits apply to any origin, named or typed: a hostname that resolves into private space — loopback, RFC 1918, link-local, and the rest — is refused unless you pass --allow-private, while a typed literal address or localhost is taken as stated intent, so probing your own server needs no flag. And each origin is pinned to the address it first connected to, so a later request cannot be redirected mid-run. What remains is that an origin you explicitly named may reach somewhere private, which is the exposure of pointing any client at a host; see the threat model.

probe reports per-check pass, fail, and warn results across endpoint reachability, the unauthenticated WWW-Authenticate bearer challenge, RFC 9728 protected resource metadata and its advertisement, resource URI and scope advertisement, the stateless protocol version, and whether tools/list requires authorization. It sends no credentials: every bearer reference in it parses the server's own challenge, and it records the response rather than any token. It reads what an endpoint publishes and reports that, making no claim about what a token would actually be permitted to do.

docs/MIGRATION-2026-07-28.md is the operator guide for those changes — what the six authorization-hardening SEPs require of remote MCP servers, authorization servers, and clients, and which requirements were still draft at its 2026-07-27 cutoff. It assumes no knowledge of Sigil and is useful on its own.

Create a local chain, run an MCP proxy with policy enforcement, then inspect the resulting evidence:

sigilctl init
sigilctl guard --policy .sigil/policy.json --mode enforce -- node server.js
sigilctl verify

guard records allows and denies before dispatch, then appends a separate completion record for what it observed afterwards: a reply classification, a local block, a timeout, a closed transport, or uncorrelated output. Completion records never contain response content; an error records only its numeric JSON-RPC code. It commits to arguments and their shape, not argument values. Start with a policy that denies by default; review and deliberately add the minimum necessary capabilities.

--reply-timeout <milliseconds> is optional and has no default. When set, it measures from the request write to the child process and must be an integer from 1 through 2147483647; a late reply is recorded as a later completion rather than rewriting the timeout observation. The upper bound matches Node's 32-bit signed timer limit: node -e "const timer = setTimeout(() => {}, 2 ** 31); console.log(timer._idleTimeout); clearTimeout(timer)" emits TimeoutOverflowWarning and reports 1.

guard supports local stdio MCP servers only. It spawns the wrapped server as a child process and proxies its standard input and output, so it does not support remote MCP over HTTP or SSE.

Example verification result

$ sigilctl verify
CHAIN INTACT
UNANCHORED — this proves nobody but the key holder altered it, NOT non-repudiation.
Receipts: 3 | DENIES: 1 | Allows: 2 | Completions: 3
Assurance: unattested 3 (no external binding proof); claimed 0 (binding claimed or structurally inspectable); attested 0 (externally verified binding).
This chain contains completion records; reading it requires a verifier that understands sigil.completion/v1. An older verifier reports it broken.
Warnings:
  chain is internally intact but unanchored: this proves nobody other than the key holder altered it, NOT that the key holder did not rewrite it — publish a witnessed checkpoint to make history binding

INTACT and ANCHORED are deliberately separate. An intact local chain is useful evidence of consistency; it is not a claim that its own key holder could not recreate history.

Receipts counts authorization decisions. A completion record is a separate observation of what the proxy saw afterwards, so it is counted separately and never inflates the decision total: three guarded calls are three receipts, not six. Because completions are a distinct envelope version, a chain containing them requires a verifier that understands sigil.completion/v1; an older verifier refuses the chain and reports it broken rather than miscounting it. That refusal is a version gap, not evidence of tampering.

Anchoring a chain

ANCHORED requires an independent witness to sign what it saw and when. Two deliberate operator decisions, in this order:

$ sigilctl checkpoint                       # sign the current receipt-tree root
$ sigilctl witness trust witness-key.json --not-before 2026-01-01T00:00:00Z
$ sigilctl witness add statement.json       # a signed observation of that checkpoint
$ sigilctl verify
ANCHORED through entry 1

Trusting a key and storing an observation are separate steps so that a statement cannot earn trust merely by arriving signed. --not-before is the witness key's own validity start, not the moment you trusted it: a witness normally signs before you decide to trust it, and stamping the trust time would reject every observation it had already made.

A statement is refused unless its signature verifies over its own content, it names a checkpoint this store actually holds, and its key is already trusted. Your own signing key is refused outright — a log cannot witness itself, which is the one thing anchoring exists to rule out. Statements are appended, never merged into the stored checkpoint, so the log stays append-only.

Anchoring relocates trust; it does not eliminate it. A witness must be an independently operated append-only service, and its key security becomes part of what a verifier takes on by listing it. Sigil does not run one.

Rotating and revoking a signing key

sigilctl keys list                                   # kids, validity windows, revocations
sigilctl keys rotate                                 # retire the current key, start a new one
sigilctl keys revoke --reason compromised -- <kid>    # stop trusting signatures from a kid

Rotation is not revocation. Rotating closes a key's validity window so later receipts use the new key; historic receipts signed inside the old window still verify, which is the point — revoking every key on rotation would invalidate evidence that was sound when it was made.

Revocation records revokedAt, and verification then refuses signatures dated at or after it. It is an audit signal, not a time machine: because a producer chooses the timestamps on its own receipts, a stolen key can backdate a forgery into the window when it was still trusted. Revocation says "stop trusting this from here"; it cannot retract what was already forged. Anchoring is what bounds that, by putting an independent observation time on the history.

A thumbprint is base64url and may begin with -, so put options first and separate the kid with --, as shown. Without the marker a leading dash reads as an option — and the key most urgently needing revocation is as likely as any other to have an awkward name.

What Sigil does not do

Sigil is not a certificate authority, identity provider, secrets manager, or enterprise gateway.

It does not mint organizational identity, issue credentials, hold application secrets, or replace a network enforcement point. It consumes trust roots that you already operate or trust—such as OIDC, X.509, SPIFFE, and Sigstore—and produces portable evidence about authorization decisions. Existing tools should keep doing their jobs.

Assurance ladder

| Level | What it proves | What it does not prove | | --- | --- | --- | | unattested | The receipt signature verifies under its included Ed25519 key; a self-generated key proves key possession and local-log integrity. | It does not prove the agent, human, issuer, or organization behind the key. A self-signed local log proves integrity, not identity. | | claimed | Evidence is structurally coherent and commits to the receipt signing key: for example cnf.jkt, a matching nonce, or an X.509 leaf key. | Sigil has not cryptographically verified that evidence against an operator-configured trust root. A JWT payload or PEM block alone is not attestation. | | attested | A verifier cryptographically validated the issuer signature or certificate chain against an explicitly configured trust root and an explicit trust rule accepted the verified identity. | It does not make the identity infallible, authorize every action by that identity, or make an unwitnessed history immutable. |

attested is reachable only for x509 bindings, and only when you supply trust material:

$ sigilctl verify --trust trust.json
Assurance: unattested 0 (...); claimed 0 (...); attested 1 (externally verified binding).
{
  "version": "sigil.trust/v1",
  "roots": ["-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"],
  "rules": [{ "mode": "x509", "issuer": "CN=Acme Root", "subject": "CN=agent.acme.com" }]
}

Without --trust, the count reads attested 0 (not measured: no --trust was supplied) — a zero nobody looked for is not a finding.

Four things worth knowing before relying on it:

  • Only x509. oidc-cnf and oidc-nonce cannot be attested offline because a raw token never enters a durable receipt, so the evidence a verifier would check is not there. spiffe and sigstore are refused because a validated certificate path establishes neither trust-domain semantics nor Fulcio identity and transparency-log inclusion. Trust rules for those modes are rejected rather than silently ignored.
  • Path validation is delegated to OpenSSL 3.x, which must be on PATH when --trust is used and is not needed otherwise. The confinement flags include -no-CAstore, which arrived in OpenSSL 3.0; an older build is refused rather than silently run without it. A signature walk is not path validation: a sub-CA constrained to .dev.acme.com can sign a leaf for prod.acme.com, every signature verifies, and only real path validation refuses it. If OpenSSL cannot run, verify fails loudly rather than reporting attested 0.
  • Validation is strict. A root without a keyUsage extension is refused (error 92: CA cert does not include key usage extension) even though default OpenSSL tolerates it. The exact reason is printed, so a refusal tells you whether the problem is your CA's extensions or your trust rules.
  • Revocation is not checked. No CRL, no OCSP. A certificate revoked after issuance still validates.

An unanchored chain does not prevent its own key holder from rewriting it. A witnessed checkpoint binds history against the log holder only when an operator-configured, independent witness records its own observation; it does not protect against a compromised or colluding witness.

How it fits

| Tool or approach | What it does well | Why Sigil is complementary | | --- | --- | --- | | SPIRE | Workload identity, SVID issuance, and attestation in SPIFFE environments. | Sigil can bind receipts to SPIFFE evidence; it records the per-action allow or deny decision rather than replacing workload identity. | | step-ca | Private CA operations, certificate issuance, renewal, and policy. | Sigil can retain and verify certificate-binding evidence; it does not issue or manage certificates. | | HashiCorp Vault | Secrets storage, dynamic credentials, encryption, and access controls. | Vault remains the secret and credential system. Sigil records independently verifiable evidence of authorization decisions without logging secret values. | | mcp-scan | Static and configuration analysis of MCP servers and clients. | Scan before deployment; use Sigil at decision time to record actual allows and denials. Neither replaces the other. | | Cloud-native agent identity (for example Google Cloud workload identity federation) | Issuing and binding cloud workload identity to cloud permissions. | Sigil consumes such identity assertions as trust evidence and produces a portable receipt across tool calls and environments. |

Verification model

Receipts use RFC 8785 canonical JSON and Ed25519 signatures. Each prev field hashes the complete preceding signed envelope. Checkpoints use the RFC 6962 Merkle construction. An anchor requires an independent, configured witness to sign its own statement—containing the checkpoint digest and the witness-chosen observation time—not a countersignature over a producer timestamp. Witnessing relocates trust from the log holder to the witness; it does not make anchoring unforgeable. The normative formats and independent-verifier rules are in docs/SPEC.md; limits and residual risk are in docs/THREAT-MODEL.md.

Contributing

Contributions are welcome when they preserve the core properties: no runtime dependency graph, strict and independently reproducible verification, and honest assurance labels. Open an issue or pull request with a focused change and tests for changed behavior. Do not add credentials, private receipts, or customer data to issues, commits, or fixtures.

Security disclosure

Please do not file a public issue for a suspected vulnerability. Report privately through GitHub Security Advisories. Include a minimal reproduction, affected version or commit, impact, and a secure reply channel. Do not include live credentials or sensitive production evidence. See SECURITY.md for scope, out-of-scope items, and known limitations.

License

Apache-2.0. See LICENSE.