Skip to main content

Infrastructure

Scan Attestations

Every scan produced by Sigil Bot is cryptographically signed. Transparency-log submission is optional and not currently enabled. This page explains how attestations work, how to verify them, and how to consume them programmatically.

How it works

When Sigil Bot completes a scan, it produces a signed attestation before publishing the result. The attestation chain follows two established standards, with an optional third:

1

in-toto Statement

The scan result is encoded as an in-toto Statement v1 with predicate type https://sigilsec.ai/attestation/scan/v1. The subject is the package being scanned, identified by its SHA-256 content hash.

2

DSSE Envelope

The statement is wrapped in a DSSE (Dead Simple Signing Envelope) with payload type application/vnd.in-toto+json and signed with Ed25519.

3

Transparency Log (optional)

The signed envelope can be submitted to the Sigstore Rekor transparency log. Submission is off by default (SIGIL_BOT_REKOR_ENABLED) and is not currently enabled for live scans, so attestations carry no log_entry_id.

Attestation predicate

The in-toto predicate contains the complete scan result. Nothing is omitted — the attestation is a tamper-evident record of exactly what Sigil found.

Predicate structure
{
  "scanner": {
    "uri": "https://github.com/NOMARJ/sigil",
    "version": "1.3.6",
    "phases": ["install_hooks", "code_patterns", "network_exfil", ...]
  },
  "scan": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "ecosystem": "npm",
    "package_name": "express",
    "package_version": "4.18.2",
    "verdict": "LOW_RISK",
    "risk_score": 0,
    "findings_count": 0,
    "files_scanned": 187,
    "duration_ms": 2340
  },
  "findings": [],
  "metadata": {
    "source": "npm-watcher",
    "bot_scan": true,
    "scanned_at": "2026-03-01T12:00:00Z",
    "content_hash_algorithm": "sha256",
    "content_hash": "a1b2c3d4..."
  }
}

Signing key

Sigil Bot signs attestations with an Ed25519 key. The public key and verification metadata are published as a well-known file:

bash
curl https://sigilsec.ai/.well-known/sigil-verify.json
AlgorithmEd25519
Encodingbase64-der
Key IDsha256:sigil-bot-signing-key-2026
Endpoint/.well-known/sigil-verify.json
Key rotation
When a signing key is rotated, the previous key is marked as revoked in the verify file and a new key is added. Old attestations remain verifiable against the key that signed them.

Verification steps

To verify a scan attestation manually:

1

Fetch the attestation from GET /api/v1/attestation/{scan_id}

2

Decode the DSSE envelope payload from base64url to JSON

3

Verify the in-toto Statement _type is https://in-toto.io/Statement/v1

4

Verify the predicateType is https://sigilsec.ai/attestation/scan/v1

5

Verify the subject digest matches the package archive SHA-256 from the registry

6

Verify the DSSE signature against the public key using Ed25519

7

If the attestation carries a log_entry_id (only when Rekor submission is enabled), verify the transparency log entry at Rekor

API endpoints

Fetch attestation

bash
curl https://sigilsec.ai/api/v1/attestation/{scan_id}

Returns the DSSE envelope as application/vnd.in-toto+json. Responds 404 if the scan has no attestation.

Verify attestation

bash
curl -X POST https://sigilsec.ai/api/v1/verify \
  -H 'Content-Type: application/json' \
  -d '{"scan_id": "{scan_id}"}'

Server-side verification. POST a JSON body with either scan_id or content_digest. Returns whether the attestation signature is valid, the signing key ID, and the timestamp. log_entry is null unless Rekor submission is enabled.

Verify response
{
  "verified": true,
  "scan_id": "550e8400-e29b-41d4-a716-446655440000",
  "signed_at": "2026-03-01T12:00:00Z",
  "key_id": "sha256:sigil-bot-signing-key-2026",
  "log_entry": null
}

On scan reports

When a scan has a signed attestation, the report page shows a green SIGNED badge next to the scan date. If the attestation has a transparency log entry, a “(log)” link takes you to the Sigstore Rekor search page.

The attestation is also included in the page's JSON-LD structured data as a DigitalDocument schema, making it discoverable by AI agents and search engines.

See also

Need help?

Ask a question in GitHub Discussions or check the troubleshooting guide.