
Incident response
Last updated in the repository as docs/security/INCIDENT_RESPONSE.md.
What counts as an incident, what happens in the first hour, and who we tell. Published including the line saying it has never been run.
Status: DOCUMENT ONLY. This procedure has never been exercised. No drill has been run and no incident has occurred. It is recorded as an unevidenced control (CC7.4) rather than presented as a working one. A tabletop exercise for the first drill is written and waiting to be run; see "Drills" below.
What counts
An incident is any of:
- a credential that may have been disclosed — an API key, a signing token, a webhook secret, an OAuth token, the credential key, a database password, a hosting or vendor console login;
- any evidence, however weak, that one customer's data was reachable from another's session;
- an unexpected change to
audit_events,signature_events,operator_eventsorcompliance_evidence, a broken hash chain, a chain that no longer matches its last anchor, an anchor that no longer names the one before it, or an anchor in the witness mailbox that is not in the database (app.audit_anchor_verify(), and CC7.3 on Ops → Readiness); - a signing link that reached the wrong person;
- unavailability of signing or verification for more than fifteen minutes;
- a lost or stolen device that could reach a production console;
- a subprocessor telling us they had one.
A failing automated compliance check is not automatically an incident, but tenant_isolation, grant_surface, secrets_at_rest and audit_trail_intact failing are: each of those means a control that was holding has stopped.
How serious
| Level | Means | Examples |
|---|---|---|
| 1 | Customer data or a production credential is, or may be, in someone else's hands; or signing is down for everyone | The credential key or the database password seen outside the company; one customer's documents reachable by another; a broken audit chain |
| 2 | A control has stopped, with no sign yet that anything was reached; or one customer is affected | grant_surface failing; a single signing link to the wrong address; one vendor key exposed that reaches no customer data |
| 3 | Something to fix, with no exposure | A failed check that turns out to be a false alarm; a vendor incident that did not touch us |
A level can go up at any point. It does not come down until the record says why.
First hour
- Write it down. Open a record with the time you were told, who told you, and what they said, before doing anything else. Everything after this is easier to reconstruct if the first line is honest.
- Contain, in the order that costs least. Revoke the credential (
revoke_api_key,oauth_revoke_grant,revoke_operator_token), pause the endpoint, or suspend the tenant. Each of these is a single call and each writes to the trail. An operator's lost or stolen device isapp.ops_forget_passkeys(address, reason), from the database: it removes their passkeys and revokes every Ops session they hold (00443). A credential of our own (the credential key, the database password, a vendor key) is rotated by its own procedure — the credential key's isKEY_ROTATION.md. - Preserve. Do not delete anything and do not "clean up". The append-only tables will refuse anyway; the mutable ones will not. Export the hosting providers' logs early: their retention is short, and it is theirs.
- Establish blast radius from the trail, not from memory.
audit_eventsandoperator_eventssay who did what and when, per tenant. Something done directly against the database, outside the product's own functions, may not be on the trail at all — so for a leaked database credential, look at what rows were created in the window as well as at what the trail says.
Then
- Root cause, written as a failing test first. The project's convention: the fix lands with the assertion that would have caught it. Every bug found this session was fixed that way.
- Notify. Who and by when is a legal question, not an engineering one, and depends on jurisdiction and on what was exposed. This procedure does not set a legal deadline, because inventing one we have not taken advice on would be worse than saying we have not. What is decided: the customer whose data was involved is told, in plain words, what happened and what we know about what was reached — without waiting to be asked, as the terms of service promise. An internal target for how soon is proposed in the draft incident response policy, pending counsel; it is not a commitment until that policy is adopted.
- Record it against the control.
app.compliance_attest('soc2','CC7.4', …)with what happened and what changed, so the next auditor sees the procedure operating rather than merely existing.
Notification: questions for counsel
NOT ANSWERED. These are the questions to take to counsel, written down so that the answers can be filled in before they are needed. Nothing in this section is legal advice, and none of the deadlines below should be relied on until counsel has confirmed them for SignSealer's customers and signers.
| Obligation to research | Who would be told | Deadline to confirm | Why it may apply |
|---|---|---|---|
| GDPR (and UK GDPR), Article 33(2): a processor tells the controller | Our customers, who are the controllers for their signers' data | "Without undue delay" — to confirm | The terms say we are the processor. Where a customer or its signers are in the EU or UK, this is our duty to them |
| GDPR Article 33(1): the controller tells the supervisory authority | The customer's regulator — the customer's duty, not ours | 72 hours from the controller becoming aware — to confirm, including when a controller counts as aware | Our notice starts or informs their clock, which is why ours has to be fast |
| GDPR Article 34: the controller tells the people affected | Signers — normally through the customer | "Without undue delay" when the risk is high — to confirm | Decides whether signers are told, and by whom |
| US state breach-notification laws | Residents of each affected state, sometimes a state attorney general or agency, sometimes credit bureaus | Varies by state: some say "most expedient time possible", some set a number of days — to confirm for each state involved | Every US state has one. Which apply depends on where the affected people live, and on whether what was exposed is "personal information" under that state's definition — see the next row |
| What we hold that state laws may treat as personal information | — | — | Names with email addresses, phone numbers, IP addresses, signatures, dates of birth when a template asks, and — where a business turns on ID Evidence — photographs of a government ID, kept encrypted for thirty days. An ID photograph can carry a driver's licence number, which many state definitions name. Counsel to say which combinations trigger which laws |
| State laws on processors ("service providers") | The customer (the data owner), who then notifies people | Often "immediately" or a short fixed period — to confirm | Several states put a separate duty on a company holding data for another |
| Our terms of service | Every affected customer | The terms promise to tell a customer "about a breach that affects you without waiting to be asked"; no deadline is written | Already a commitment |
| A signed DPA with a customer | That customer | Whatever the DPA says — none signed yet | Enterprise customers will send their own; a notice period will be in it |
| Vendors' terms | Stripe, Telnyx, Resend, the app stores, others | To confirm per vendor | Some require notice if their service or credentials were involved |
| Carrier and messaging rules | Telnyx, the carriers | To confirm | If the SMS path or the toll-free number was misused |
| Cyber insurance | The insurer | Per the policy, if one exists — none is recorded | Late notice can void cover |
| Law enforcement | Police or the FBI (IC3) | Optional; counsel to advise | Can also be a reason to delay other notices, which only counsel can say |
What counsel's answer should produce: a one-page table of who is told, by when, by whom, with a template for each notice, kept beside this file.
Roles
OPERATIONAL — not staffed beyond the owner. SignSealer is a small team, led by its owner. There is no on-call rota and no out-of-hours cover, and pretending otherwise in this document would be the exact failure this document set is written to avoid.
What exists:
- The owner leads every incident — decides the level, contains, talks to customers and counsel, and keeps the record.
- A backup contact, who can pause sending, post a status notice and call counsel if the owner cannot act, is to be named in the incident response policy. Not yet named.
- Alerts reach the owner by email, and by text where that is configured. Outside monitoring watches the public health pages from somewhere that is not us.
security@signsealer.comreceives reports, and reports reach a person.
Drills
None performed. A procedure that has never been run is a document. The first drill is a tabletop walkthrough of a leaked credential — the credential key and a database credential visible in a screenshot — because it is the scenario with the most steps that touch production. The script, step by step with the real rotation procedures, is docs/security/INCIDENT_TABLETOP_CREDENTIAL_LEAK.md (kept in the repository, not published, because it is a map of how our credentials fit together). When it has been run it is recorded with compliance_attest against CC7.4, and this section will say the date.

Ready when the next guest is.
Free for the first 25 agreements a month. No card to start.