Security
What we protect, how to reach us, and what we do not claim.
Signet guards other people’s users, so a discovered vulnerability obligates a response: fix, disclose to affected customers, re-certify. This page is the working surface for that obligation: the disclosure process, the facts a security review needs, and a plain ledger of what is not yet claimed.
DisclosureDataHow we testWho can reach itIncidentsSubprocessorsWhat we refuseNot claimed
Reporting a vulnerability
Email security@signetauth.com. A plaintext report is fine and is not a reason to delay. Include what you found and its impact, how to reproduce it, and the Signet version and deployment shape if you know them. Do not open a public issue or route it through an ordinary support ticket; a support ticket is read by more people, sooner, than a security report should be.
| Stage | Our commitment |
|---|---|
| Acknowledgement | Within 2 business days, from a human. |
| First assessment | Within 7 business days: severity reading and whether we can reproduce it. |
| Fix or plan | For anything assessed high or critical, a fix or a dated plan within 30 days. |
| Customer disclosure | Part of the fix, per the standing obligation, not at our convenience. |
These numbers are deliberately ones a small operation can hold on a bad week; a published window we miss would be worse than no window. A report classified security is handled by a person: never auto-replied, never agent-triaged, never auto-closed.
Safe harbour. Good-faith research under this process will not be met with legal action. Good faith means you stop at proof, do not access or retain data that is not yours, do not degrade service for others, and give us a reasonable chance to fix the issue first. No NDA is required to report. There is no bug bounty; we offer credit in the release notes and a named acknowledgement if you want them.
In scope: the engine and its served surfaces, the licence-verification path, and our hosted instances. Out of scope: scanner output with no demonstrated impact, volumetric denial of service, social engineering. Resource-exhaustion bugs, where a cheap request costs us disproportionately, are in scope and wanted. The machine-readable advertisement lives at /.well-known/security.txt.
Where your data lives
Every user, session and secret is a row in PostgreSQL: your own database, from the first sign-in. Transport is TLS on every served surface. Encryption at rest belongs to the database and volume layer, so it inherits whatever the operator of that layer configures; on your own metal that operator is you, and on hosted instances it is us. Passwords are stored only as salted, purpose-built password hashes; session tokens are stored only as digests, so a stored session row is not a usable credential.
Nothing phones home: no telemetry, no licence pings, no third-party calls in the sign-in path. The same build runs air-gapped under an enterprise licence.
How changes are tested before they ship
The discipline is published rather than described. Every release must pass better-auth’s own 280-check conformance suite in full and 14 of 14 end-to-end acceptance flows against a live instance; the current receipts are dated 2026-07-25 and served at /certification, machine-readable, from inside the running engine. A change that alters the wire fails that gate before it reaches anyone.
Who can reach your deployment
Hosted: signup provisions the instance automatically. Operators who run the platform can reach the instance they operate for you; that is stated here rather than discovered later. Access is credentialed, logged and limited to operating the service.
On your own metal: we cannot reach your deployment. There is no remote administration path, no callback channel, and nothing in the engine that lets us in. Support happens with you, on evidence you choose to share.
Inside the product, the administrative surface follows the same discipline. It is protected by an instance-level operator credential that is compared in constant time. An organization can also hold a delegated administrative credential, scoped to its own tenant and limited to a short, explicit allowlist of operations; every administrative route outside that allowlist refuses the delegated credential before any handler runs, and that refusal set is enforced by a test matrix covering every route and method, not by review. Delegation cannot escalate: a delegated credential never grants authority it does not itself hold, and authority never widens along a delegation chain. Credentials are bound to their tenant when issued, not inferred from the request, and a cross-tenant request is refused without revealing whether the named target exists.
If we have an incident
If we determine that a security incident on our side affects your data, we notify you within 72 hours of that determination, with what we know, what we have done, and what we recommend. Contractual response targets beyond this live in signed agreements; this window is the floor we publish for everyone.
Subprocessors
On your own metal under an enterprise licence: none. Nothing leaves your infrastructure.
For the hosted service and this website, the parties that touch traffic or data are: Hetzner (instance compute and storage, EU), Cloudflare (DNS and inbound email routing), and Resend (outbound transactional email relay). Payment processing, when it applies, is handled by the payment provider named at purchase. The list changes only with notice on this page.
What we refuse to do
Agent access is where an identity provider is most tempted to be helpful. These are the places Signet refuses instead, and each one is a refusal a reviewer can test rather than a posture we describe.
| What we refuse | Standing | What that means for you |
|---|---|---|
| Creating a person from an agent’s token | never | If the human behind the agent has no account here, we refuse the request rather than making one. Your directory stays the directory. |
| A long-lived agent credential | none issued | The enterprise road hands back no refresh token at all. The token also dies with the grant behind it. |
| A token for a client that identifies itself by a URL | refused | It can prove who it is, and we stop there. One gap in the standard causes it: neither the MCP profile nor the grant draft says which customer a self-registering client belongs to, and we would rather refuse than guess wrong about a tenant. Clients your customer registers work today. |
| Signing with RS256 | EdDSA only | RS256, the usual default, is a declared limitation. Check your client library before you build against our tokens. |
| Keeping a usable copy of a bearer you re-present | hashed | Every bearer credential a client holds and presents again lives in our database as a hash. Emailed one-time codes are the exception, and they live for minutes. |
| Minting a token a scanner cannot spot | prefixed | Tokens we mint now carry a class prefix, so a secret scanner flags one in a repository. Tokens minted before that change carry none, and they keep working. |
The not-claimed ledger
| Claim | Status | The honest date |
|---|---|---|
| SOC 2 | not held | Type I targeted 2027; the date is set when the first enterprise deal requires it, and readiness work is priced into that deal. |
| ISO 27001 | not held | Not scheduled. If a deployment requires it, that is a conversation before a contract, not after. |
| Third-party pen test | not yet performed | Planned alongside the first enterprise engagement; the report goes to customers under NDA when it exists. |
| SLA | contract only | Response targets are written into signed agreements. Outside one, none is offered or implied. |
Ask us what we actually test instead: the conformance receipts above are real, dated, and verifiable against a running instance. When a row in this ledger changes, the change arrives with its artifact, not before it.