Security posture
Obelisk is a security product, and we hold ourselves to the bar we sell. The Gate's own live Obelisk Rating is shown publicly on the homepage, recomputed at most once a minute. Every served page carries a strict, nonce-based Content-Security-Policy, HTTP Strict Transport Security, and modern TLS, with no inline styles or scripts.
This page is the implementation detail. For the plain-language case — why you can trust Obelisk, end to end — see the full trust case →.
Authentication
- Passkey-first / WebAuthn. Credentials are public-key based and the private key is never transmitted to Obelisk or any site: a device-bound passkey stays on its authenticator, and a synced passkey is carried end-to-end encrypted by the platform's password manager. There is no password to phish, reuse, or leak.
- Discoverable (usernameless) sign-in — one tap, no username to type, phishing-resistant by origin binding: the browser offers a passkey only to the site it was made for. The fallbacks — an emailed sign-in link or an authenticator code — are not phishing-resistant, which is why they get a limited session.
- Sessions remember how you signed in. Every session carries a signed record of how it was signed in. A passkey sign-in proves you hold the passkey's private key, which never reaches us. A session from an authenticator code, an emailed link or a remembered 30-day sign-in is limited: it can use your account, but the server refuses it when it tries to add another passkey or remove one, change your authenticator or recovery codes, mint an API key, register an agent, or rename or delete the account, until you sign in with your passkey again.
- Optional TOTP second factor with a pending→confirm setup: until you confirm it, the authenticator isn't accepted for sign-in, and it doesn't stand between you and a passkey sign-in.
- Recovery. A passkey on a second device is the recovery that works on its own. An emailed sign-in link (to a verified address) or a code from an authenticator app you set up gives you a limited session, and a limited session cannot add a passkey to an account that already has one. Lost the only device with your passkey? A one-time recovery code created after signing in with a passkey, or an email recovery to your verified address that opens only after a 72-hour hold with a link to cancel it, lets you add a new passkey and nothing else. If you lose every passkey and your email too, contact us: recovery is case by case and is not guaranteed. If you generate recovery codes, they are shown once and we store only their SHA-256 hashes.
- Federation. Obelisk is an OpenID Connect provider. Cloudflare, 1Password, and Microsoft Entra can use Obelisk as their OpenID Connect sign-in. Each ID token's
obelisk.assuranceclaim says how the person signed in, so a tool that reads it can require a passkey. SAML apps such as GitHub, Google Workspace, AWS, Slack, and Atlassian can't be connected on the hosted Gate yet. A SAML sign-on, once connectable, accepts any valid Obelisk session and its assertion does not say how the person signed in. - Sender-bound tokens — DPoP (RFC 9449). Access tokens can be bound to a client-held P-256 key: the token endpoint accepts a
DPoPproof, stamps the key's thumbprint into the token (cnf.jkt), and every protected call must present both the token and a fresh proof signed on-device. Opt-in, per request: an access token can be bound to a client-held P-256 key, and each call then carries a fresh proof signed with that key. A copy of a bound token does not work without that proof wherever the proof is checked: Obelisk checks it where it accepts these tokens, and your own server has to check it too. A token issued without a proof is an ordinary bearer token.
Data protection
- Encryption at rest. The identity database is encrypted with AES-256-GCM. The service is built not to log, display or return secret material, and its tests check for this.
- No user credentials in your app. Your app stores no user credentials: it receives a signed ID token describing the person, not a password, passkey or authenticator secret. A public (PKCE) client holds no client secret at all; a confidential client holds one client secret, shown to you once, of which Obelisk keeps only a SHA-256 hash.
- Tenant isolation. All tenants share one encrypted identity database, kept apart per tenant: no two tenants share a return origin, and no artifact carries secret material.
Tamper-evident audit
Sign-ins, token issuance, grants, console access and account changes are written as hash-chained receipts: each one carries the hash of the one before it, so changing or deleting one changes every hash after it. The latest head of those ledgers is anchored, published and ES256-signed. Here is what you can check yourself, and where those checks stop:
What you can check today, without an account
- Save the signed ledger head, and compare it later. Fetch
/.well-known/obelisk-transparency.jsonand keep itsheadAnchorHashandanchorCount. On any later fetch the count must never go down, and while the count is the one you saved, the head must not change. A break in either rule is evidence the record was cut short or replaced. - Check that the head was signed with our key. The document's
sthfield is an ES256 signature over the head. Verify it against our published keys at/.well-known/jwks.json; the head check on the Verify it yourself page does this in your browser. - Check that a receipt you hold is in the ledger. Paste its hash into the receipt check on the Verify it yourself page. Your browser recomputes the Merkle proof from
/api/proof/<hash>, and a match shows the receipt is in the ledger we serve today. The check searches the receipts ledger; sign-in records are kept in a separate ledger it doesn't search. - Check a token we issued. Verify an ID or access token's ES256 signature with any JWT library against
/.well-known/jwks.json. Once you have the keys, that check needs nothing more from us.
What those checks can't show yet
- That a later head extends the one you saved. We don't publish consistency proofs between heads, and we don't serve past heads, so comparing heads catches a history that was cut short or replaced, not one that was rewritten and then extended with new entries.
- That a receipt check is covered by the signature. The root a receipt proof is checked against is computed by us when you ask and arrives in the same response. It isn't part of the signed head yet.
- That our keys and our records are honest. You fetch the signed head and the keys that verify it from us, so a valid signature shows the head was signed with the key we publish, not that what it describes is complete.
- That nothing happened without a record. The ledgers show what the service recorded, not what it didn't. Sign-in records are written on a best-effort basis, so a failed write doesn't block a sign-in.
- That someone outside holds the same head. Whether an outside copy of the head is verified is shown live on the status page. While none is, the copy you save is the outside record.
Your own record of the sessions our sign-in paths mint for your account, and of every passkey added or removed, is at /account/issuance. For what that record can and can't show, see what we can and can't do.
What we can — and can't — do
We can't use your passkey. Its private key is never sent to us — it stays on your device, or in your own end-to-end encrypted password manager if it syncs — and we store only the public key, so we can't produce your passkey's signature. Security-sensitive account changes need that passkey.
What we could do, like any identity provider. The service that issues sessions and tokens holds the keys that sign them, so in principle an operator with access to the server could issue a session or token without your passkey. The sessions our sign-in paths mint for your account, and every passkey added or removed, are recorded in a hash-chained log you can read at /account/issuance, naming the passkey behind each passkey sign-in (a sign-in made without one names none), so a sign-in you don't recognise stands out. That log shows what the service recorded. It can't prove nothing was issued outside it, and its writes are best-effort, so a failed write doesn't block a sign-in.
Authenticator codes. If you turn on an authenticator app, its seed is encrypted at rest under a key our service holds, so an operator with server access could in principle read it. That is one reason a code sign-in gets a limited session. Moving these seeds to per-user sealed storage is listed on the roadmap; it isn't done. For the strongest protection, sign in with a passkey.
OWASP Top 10 for agentic applications
How Obelisk's controls line up with the OWASP Top 10 for Agentic Applications (2026). Obelisk is an identity, authorization and evidence layer: it narrows what an agent may do and records what it did. It does not run your agent, so some risks stay with your runtime.
| Risk | What Obelisk does | Coverage |
|---|---|---|
| ASI01 Agent Goal Hijack | Obelisk scores untrusted content for injection markers inside an authorization decision, so a hostile document requires step-up or a refusal. That decision point is live at /access/v1/evaluation (AuthZEN 1.0), and every decision it returns is receipted. The score is one signal, not a guarantee. | Partial |
| ASI02 Tool Misuse and Exploitation | Agents act through scoped, expiring grants rather than standing credentials. The pin_tool_manifest tool on our MCP server digests a tool manifest so an approval is bound to the exact tool definitions it covered. | Partial |
| ASI03 Identity and Privilege Abuse | Every agent has its own identity, separate from the person who owns it. Tokens are short-lived and can be bound to a key with DPoP, and sensitive actions can require a fresh human step-up. | Core layer, for agents that authenticate through Obelisk |
| ASI04 Agentic Supply Chain Vulnerabilities | A tool manifest that changed after approval, gained or lost a tool, or carries hidden Unicode text is refused by pin_tool_manifest. Our own catalogue publishes its digest so you can pin us too. | Partial |
| ASI05 Unexpected Code Execution | Not Obelisk's layer: sandboxing and code execution controls belong to the runtime that executes the agent. | Not covered |
| ASI06 Memory & Context Poisoning | The same decision point scores a batch of context fragments together, weighted by where each came from, before they are used. Obelisk does not store or manage your agent's memory. | Partial |
| ASI07 Insecure Inter-Agent Communication | An agent can present a run proof that Obelisk signed, and the receiving agent or service verifies it against our published keys instead of trusting a self-description. | Partial |
| ASI08 Cascading Failures | Suspending an agent, or marking it compromised, makes Obelisk refuse its keys from that moment, so one failing agent can be cut off without touching the others; a suspension can later be lifted. | Partial |
| ASI09 Human-Agent Trust Exploitation | The person accountable for an agent is recorded separately from the agent, and a step-up asks the person, not the agent, to approve. | Partial |
| ASI10 Rogue Agents | Grants, token issuance and account changes are written as hash-chained receipts, and an agent can be suspended immediately. Detecting rogue behaviour inside your runtime is not something we observe. | Partial |
Cryptography & quantum readiness
We don't invent cryptography: every signature, hash and cipher the service's code computes is a standard, published algorithm, run by Node.js's built-in crypto library or by two open-source libraries (@simplewebauthn/server checks passkey signatures, and xml-crypto handles SAML's XML signatures). The full inventory of the cryptography in the service's code:
- OIDC tokens — signed ES256 (ECDSA P-256) by default; the JWKS can publish more than one key, so a key can be rotated without breaking tokens already issued.
- Sessions — HMAC-SHA256 macaroons with caveat attenuation, so a session can be narrowed to fewer permissions, never widened.
- Receipts — sensitive actions are written as SHA-256 hash-chained receipts; each ledger's latest hash is anchored into a chain of anchors whose head is ES256-signed (
obelisk-sth+jwt) and verifiable against the published JWKS. Per-receipt inclusion proofs (a sparse Merkle tree over SHA-256) are computed on request and aren't yet part of the signed head. - Refresh tokens — rotating, so a stolen token is detectable on next use.
- Post-quantum — an ML-DSA-65 signer (RFC 9964, FIPS 204) adds a second signature to the transparency tree head beside ES256, in a separate field, so existing verifiers are unaffected; its public key is in the JWKS. Tokens are not post-quantum signed.
- SAML federation — assertions signed RSA-SHA256 with a pinned X.509 certificate — built and tested, though no SAML app can be connected on the hosted Gate yet.
Not listed: a time-lock demonstration in our command-line tooling, built on hand-written arithmetic over a small test modulus. Nothing on the hosted service uses it, and it is not a security control.
Resilience & availability
An encrypted primary store, an immutable break-glass fallback for the operator's own identity, and encrypted backups are designed so the Gate can be restored after a corrupted database, a failed migration, or a misconfiguration; /status says what is measured, including how much recent data a restore could lose. That is the operator's resilience, not a way back into your own account: for that, keep a second passkey on another device.
The disaster-recovery layers, recovery-time targets, and the honest availability caveat all live in one place so they cannot drift: the availability & resilience page →
Vulnerability disclosure
Found a vulnerability? We want to hear from you.
Email security@obeliskgate.com with steps to reproduce. Please give us a reasonable time to remediate before public disclosure.
Safe harbor. We will not pursue legal action against good-faith security research that respects this policy: avoids privacy violations, data destruction, and service degradation; tests only accounts you own or have explicit permission to test; and does not access, modify, or exfiltrate other users' data. In scope: obeliskgate.com and the Obelisk identity service. Out of scope: denial-of-service, social engineering, physical attacks, and third-party services we don't operate. A coordinated machine-readable policy is published at /.well-known/security.txt.
The Obelisk Rating
Obelisk continuously scores its own posture across identity strength, the operator's lockout resilience, database integrity, OIDC health, receipt-chain health, threat coverage, and more — each with a confidence weight. Organizations can run the same engine against their own website. See About.