Skip to content

Security

Sill’s security posture rests on a small number of load-bearing primitives: every governed surface is signed with ed25519 and verifiable against a public JWKS; every governed decision is written into an append-only, Merkle-chained audit envelope; the architecture handles only opaque processor tokens so raw cardholder data never enters any Sill system; tenants are isolated by account_id / site_id at every boundary; and the only credential a human ever presents to Sill is a magic-link sign-in token. The full marketing overview lives at sill.so/security; this page is the technical reference.

Signing — ed25519, JWS-detached, public JWKS

Section titled “Signing — ed25519, JWS-detached, public JWKS”

Every governed surface Sill publishes — the per-site agent card, the ARD ai-catalog.json trust manifest, every audit record, every exported audit bundle — is signed with an ed25519 key per RFC 8032. The signed payload is a JWS in compact, detached serialization with alg: EdDSA per RFC 7515 and RFC 8037. Canonicalization is RFC 8785 (JCS) — without a deterministic canonicalizer two semantically equal JSON objects could produce different signed bytes, and verification would not survive round-trips across implementations.

The public half of each signing key is published at a standard JWKS endpoint:

GET https://edge.sill.so/.well-known/jwks.json

A third party can verify any Sill signature end-to-end using only:

  1. The JWKS above.
  2. An RFC 8785 JCS canonicalizer.
  3. An off-the-shelf ed25519 library (@noble/ed25519, pynacl, tweetnacl, OpenSSL).

No Sill SDK, no Sill code, no Sill account is in the verifier path. The full recipe — including a minimal JavaScript sketch and a tampering smoke test — is at Verify a signature. The endpoint, headers, and key shape are documented at Public JWKS.

SurfaceSigned scopeWhat the signature does NOT cover
Agent cardThe canonical card payload — protocol_version, skills[], capabilities.Skill availability at the wire — the card is a discovery surface.
ARD ai-catalog.jsonThe trust manifest (host identity + provenance).Per-entry url / capabilities / description — those rest on did:web + TLS per the ARD spec.
Audit recordThe record with envelope_signature and merkle_root stripped, JCS-canonicalized.The merkle_root written back at end-of-day batch close (excluded from the signing input by construction).
Audit bundle exportA SHA-256 over a domain-separated prefix concatenated with the JCS-canonical body.The chain and Merkle structure of the contained records — a complete verifier rechecks per-record signatures + recomputes batch roots.

Every governed interaction Sill observes is written into the audit envelope: append-only, signed per record, chain-linked to its predecessor, and folded into a per-(site, decision-class, UTC-day) Merkle batch.

flowchart LR
  WRITE[Edge / origin writer] --> SIGN[Sign + chain-link<br/>ed25519 over JCS]
  SIGN --> ROW[(Immutable audit_record row)]
  ROW --> BATCH[End-of-UTC-day batch closer]
  BATCH --> ROOT[Merkle root written back<br/>per site, decision-class, day]
  ROOT --> EXPORT[Signed bundle export]

The append-only property is structural, not a permission setting: any byte-level change to a stored record breaks the per-record envelope signature, breaks the prev_record_hash of the next record, and breaks the Merkle root that contains it. Each chain is domain-separated at genesis by site_id and decision class, so a discovery record can never be substituted for a transactional record on the same site, and two sites’ chains cannot collide. The full record shape, chain construction, batch math, and end-to-end verifier walkthrough are at Audit envelope.

No fund custody — Sill never holds money

Section titled “No fund custody — Sill never holds money”

Sill issues signed authorizations and signed audit records. The merchant’s existing payments processor (Stripe today) holds the card, authorizes the charge, settles, and pays out. No funds enter a Sill-controlled account at any step of the flow.

sequenceDiagram
  autonumber
  participant A as Agent
  participant E as Sill edge<br/>(mandate + policy)
  participant O as Sill origin<br/>(audit + connectors)
  participant S as Stripe
  participant M as Merchant payout

  A->>E: Signed mandate
  E->>E: Policy evaluation
  E->>O: authorize(mandate, opaque token)
  O->>S: Charge against merchant-saved pm_*
  S-->>O: Charge id + status
  O->>O: Append signed, chain-linked audit record
  S->>M: Settlement + payout (no Sill leg)

The architecture is intentional: Sill is the identity / intent / proof + payment-authorization layer in front of the merchant’s processor, not a replacement for it. See Payments for the Stripe rail.

PCI-minimal architecture — opaque tokens only

Section titled “PCI-minimal architecture — opaque tokens only”

Sill handles only opaque processor tokens — Stripe pm_* / tok_* / Shared Payment Token references. Raw Primary Account Numbers (PANs), expiry dates, CVCs, and full track data never enter any Sill system. The card data and the funds flow remain inside Stripe, whose PCI scope already covers them.

This architectural minimization is enforced at two levels:

  1. Architecture. The mandate engine takes an opaque token reference as input, never raw card material. The Stripe connector calls Stripe with that reference; Stripe charges and returns a charge id.
  2. CI grep gate. A repository-level CI check fails any commit whose source or test payloads match PAN-shaped digit patterns or the field names card_number, cvc, cvv, pan, card_expiry, so the “opaque tokens only” property cannot regress silently.

Sill is multi-tenant. Every tenant boundary in the data model and the request path is scoped by account_id (the merchant org) and site_id (the registered domain). Both are ULIDs; domain objects carry prefixed string IDs (mnd_…, agent_…, rec_…).

Isolation enforcement points:

  • Routes. Per-site endpoints (/v1/agent-card/{site_key}.json, /v1/catalog/{site_key}.json, /v1/mcp/{site_key}) include the site key in the URL; the edge resolves it to a site_id before any data access.
  • Session. Magic-link sessions carry the account_id. Every API route asserts the session’s account against the row’s account_id before returning data.
  • Audit chains. Each site keeps two independent audit chains, domain-separated at genesis by site_id and decision class. A record from one site cannot be substituted into another site’s chain — the chain link or the genesis hash will fail.
  • Connector credentials. Stripe Connect account ids and Shopify OAuth tokens are stored per account_id; the connector resolves credentials by the request’s account, never by client-supplied input.

The only credential a human ever presents to Sill is a magic-link sign-in token, mailed to a verified email address. There are no passwords to phish, no password databases to leak, and no password reset flow to social-engineer. Sessions are scoped to *.sill.so so the dashboard at app.sill.so and the marketing surfaces at sill.so share a single login.

  • Auth path: magic link only in production today.
  • Session cookie: .sill.so cross-subdomain, with Secure + HttpOnly + SameSite=Lax.
  • SSO: on the roadmap. Not available today.

A small set of operational properties round out the posture:

  • Region (Phase 1). US-East only. Merchant-controlled data residency is not a current capability.
  • Edge vs origin separation. Mandate engine + signing surfaces at the edge. Audit storage, registry, connectors, billing webhooks at the origin. The split bounds blast radius — an edge issue cannot mutate audit history; an origin issue cannot forge an edge-signed surface (the signing key lives at the edge).
  • Key management. Signing keys live in KMS aliases (a public-verifiable edge key for the agent card + ARD catalog; separate origin aliases for the audit envelope and bundle keys). The JWKS lets verifiers pick a key by kid.

Compliance posture (mappings, not certifications)

Section titled “Compliance posture (mappings, not certifications)”

Sill publishes framework mappings, not certifications. The control-by-control mappings — OWASP LLM Top 10 (2025), OWASP Top 10 for Agentic Applications (2025), MITRE ATLAS (2026.05), NIST AI RMF 1.0 — describe where named Sill controls address the named framework risks. They are not third-party attestations.

For the canonical control-by-control mapping table, see Compliance and the marketing-site standards page at sill.so/standards.

External frameworks Sill’s controls are designed against:

  • OWASP LLM Top 10 (2025) — LLM01 Prompt Injection, LLM06 Excessive Agency, LLM10 Unbounded Consumption, LLM02 Sensitive Information Disclosure (partial).
  • OWASP Top 10 for Agentic Applications — covered for ASI03 + ASI10; partial for ASI01, ASI02, ASI04, ASI06, ASI08, ASI09; ASI07 covered for registered-agent delegation; ASI05 out of scope.
  • MITRE ATLAS — tactic-level evasion / exfiltration / impact; AML.T0096 covered; AML.T0011.002 + AML.T0098 partial; AML.T0100 not covered.
  • NIST AI RMF 1.0 — audit envelope + bundle export support the Measure and Manage functions.

These mappings are the work product, not certifications. See Compliance.

Security reports go to the address listed at sill.so/security. Please include reproduction steps and the affected surface (edge endpoint, dashboard route, audit format, etc.). Sill is a trust product; security reports are taken seriously and acknowledged.

How do I verify a Sill signature without trusting Sill? Fetch the JWKS at https://edge.sill.so/.well-known/jwks.json, canonicalize the payload with RFC 8785 (JCS), and verify the detached JWS with an off-the-shelf ed25519 library. The step-by-step recipe + a minimal JavaScript sketch + a tampering smoke test are at Verify a signature.

Can a Sill audit record be edited or deleted? No. The record is signed with ed25519 over the JCS-canonical form, chain-linked to the previous record by prev_record_hash, and folded into a per-day Merkle batch. Any byte-level change breaks all three. The only post-write change is the end-of-day write-back of merkle_root, which is excluded from both the signing input and the chain-hash input by construction.

Does Sill ever see raw card numbers? No. The mandate engine and the connector layer accept only opaque processor tokens (Stripe pm_* / tok_* / SPT references). Raw PANs never enter any Sill system. The “opaque tokens only” property is enforced by both architecture and a CI grep gate.

Is Sill PCI-certified? No. Sill holds no PCI attestation, ROC, or SAQ. The architectural minimization above keeps cardholder data and the funds flow inside the merchant’s processor (Stripe). PCI certification is future work and is not claimed today.

Is Sill SOC 2 / ISO 27001 certified? No. Sill publishes framework mappings and will not claim any third-party certification until accredited audits complete. See Compliance.

What stops one tenant from reading another tenant’s data? Every tenant boundary is scoped by account_id + site_id. Per-site routes carry the site key in the URL and resolve it before data access. Dashboard sessions assert the account on every row. Audit chains are domain-separated at genesis — a record from one site cannot be inserted into another site’s chain because the chain link or the genesis hash will fail.

What auth does Sill support? Magic link only today, scoped to *.sill.so. SSO is on the roadmap.

What region does Sill run in? US-East only in Phase 1. Merchant-controlled data residency is not a current capability.

External references: