Skip to content

feat: add skill signature verification#643

Open
elliotllliu wants to merge 1 commit intovercel-labs:mainfrom
elliotllliu:feat/signature-verification
Open

feat: add skill signature verification#643
elliotllliu wants to merge 1 commit intovercel-labs:mainfrom
elliotllliu:feat/signature-verification

Conversation

@elliotllliu
Copy link
Contributor

Summary

Implements #617

Adds optional signature verification for installed skills, protecting users from tampered or malicious SKILL.md content.

New Command

# Verify all installed skills
npx skills verify

# Verify specific skills
npx skills verify web-design

# Output example
  ✓ web-design (Verified, signed by skills.sh, 2026-03-14T10:00:00Z)
  ○ my-custom-skill (No signature)
  ✗ suspicious-skill (Content tampered — hash mismatch)

Results: 1 verified, 1 unsigned, 1 failed

Architecture

Signature Block (in SKILL.md frontmatter)

signature:
  algorithm: ed25519-sha256
  signer: skills.sh
  content_hash: sha256:a1b2c3d4...
  signed_at: 2026-03-14T10:00:00Z
  sig: <base64-encoded-signature>
  kid: key-2026-01  # optional, for key rotation

Verification Pipeline

  1. Parse signature block from YAML frontmatter
  2. Hash content below frontmatter (SHA-256)
  3. Compare computed hash against content_hash
  4. Fetch signer's public key from https://{signer}/.well-known/skills-pubkey
  5. Verify ed25519 signature

Key Management

  • Public keys fetched from .well-known/skills-pubkey endpoint (federated trust model)
  • Local key cache with 1-hour TTL (~/.agents/.key-cache/)
  • Key rotation via kid field matching
  • Expired keys automatically skipped

Design Decisions

  • Backward compatible — skills without signatures work normally
  • Federated trust — any domain can be a signer (skills.sh, skills.mycompany.io, etc.)
  • Content-only signing — only content below frontmatter is signed (metadata changes don't break signatures)
  • ed25519 — modern, fast, small keys/signatures

Changes

  • src/signature.ts — Core verification module (parsing, hashing, key management, verification)
  • src/cli.tsskills verify command with filtering and result display
  • tests/signature.test.ts — 13 tests covering parsing, hashing, and formatting

Testing

  • pnpm build
  • pnpm test ✅ (388/388 tests pass, +13 new)

Implement the signature verification RFC (vercel-labs#617):

- New `src/signature.ts` module with:
  - ed25519-sha256 signature parsing from SKILL.md frontmatter
  - Content hash computation (SHA-256 of content below frontmatter)
  - Public key fetching from `.well-known/skills-pubkey` endpoints
  - Local key caching with configurable TTL (1 hour default)
  - Key rotation support via `kid` field
  - Full verification pipeline with detailed result types

- New `skills verify` CLI command:
  - Verify all installed skills: `npx skills verify`
  - Verify specific skills: `npx skills verify <name>`
  - Shows verified/unsigned/failed counts

- 13 new tests covering parsing, hashing, and formatting

Implements vercel-labs#617
@fanqi1909
Copy link

Thanks for implementing #617 so quickly, @elliotllliu ! 🎉

Great to see the design translated into working code. Skimmed through the PR and the implementation looks solid:

✅ Federated trust model with .well-known/skills-pubkey
kid field for key rotation (good catch from your earlier comment)
✅ Local key cache with TTL
✅ Content-only signing (metadata changes don't break signatures)

A few thoughts for future iterations (not blocking this PR):

  1. Revocation endpoint — As you mentioned earlier, a companion .well-known/skills-revoked endpoint would be useful for compromised keys/skills
  2. Strict modenpx skills add --require-signature to reject unsigned skills entirely (for security-conscious users)

Happy to help review or iterate. Let's see what the maintainers think!

@elliotllliu
Copy link
Contributor Author

Thanks for the thorough review @fanqi1909! Glad the implementation aligns with your RFC vision. The federated model is designed to be extensible — once this lands, adding new registry endpoints should be straightforward.

Looking forward to seeing this move forward!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants