draft optional
This document defines the /compromised/pubkeys endpoint, which accepts a list of pubkeys and returns compromise records for any of them whose private key is known or suspected to have been compromised.
A Nostr identity is fully controlled by its private key. If a private key is compromised, anyone who obtains it can impersonate that identity indefinitely. There is no revocation mechanism in Nostr; the only recourse is (manual) key rotation.
Some forms of compromise are detectable. A publicly posted nsec can be found by crawling Nostr events and verified cryptographically. Other forms can be inferred from heuristic signals, or attested by third parties using Nostr events. Providers that index Nostr events can surface these signals to clients, enabling them to warn users before they interact with a compromised identity.
POST /compromised/pubkeys
Accepts a list of pubkeys and returns a compromise record for each one that is known or suspected to be compromised. Pubkeys with no known compromise are omitted from the response.
Compromise results fall into two classes depending on the algorithm that produced them.
Produced by deterministic algorithms. The compromise is backed by a cryptographic proof that any verifier can check independently.
| Field | Type | Required | Description |
|---|---|---|---|
status |
string | yes | Always "confirmed". |
detected_at |
integer | no | Unix timestamp of when the provider first detected the compromise. |
proof |
string | yes | A cryptographic proof of the compromise. See The signature-proof Algorithm. |
{
"status": "confirmed",
"detected_at": 1700000000,
"proof": "2a9f3c..."
}Produced by probabilistic algorithms. The compromise is inferred from heuristic signals without a cryptographic proof.
| Field | Type | Required | Description |
|---|---|---|---|
status |
string | yes | Always "suspected". |
detected_at |
integer | no | Unix timestamp of when the provider first detected the compromise. |
confidence |
number | yes | A probability between 0.0 and 1.0 expressing the provider's confidence that the key is compromised. |
{
"status": "suspected",
"detected_at": 1701000000,
"confidence": 0.87
}Deterministic algorithms MUST only return Confirmed Results. Every result they emit is backed by a verifiable proof. Clients MAY verify each proof independently.
Probabilistic algorithms MAY return both Confirmed Results and Suspected Results. Providers are free to define their own heuristics, signal sources, and confidence thresholds. Clients SHOULD treat Suspected Results as advisory and let users decide how to act on them.
Probabilistic algorithms MAY require a pov pubkey to personalize results. A personalized algorithm can weight signals by how much the point-of-view identity trusts their source, for example, prioritizing compromise attestations made by pubkeys the user follows.
Providers that implement this endpoint MUST advertise it in the capability document as defined in ORE-01. The following example shows a provider offering both the standard signature-proof algorithm and a custom probabilistic algorithm.
{
"/compromised/pubkeys": [
{
"id": "signature-proof",
"name": "Cryptographic Proof",
"description": "Returns only confirmed compromises backed by a verifiable Schnorr signature."
},
{
"id": "heuristic-wot-v1",
"name": "Web of Trust Heuristic Detection",
"description": "Returns confirmed and suspected compromises using third-party attestations from pubkeys trusted by the provided pov.",
"pov": true
}
]
}signature-proof is the standard deterministic algorithm defined by this ORE. All providers that implement it MUST follow the specification below exactly, ensuring that results are interoperable and independently verifiable across providers.
The proof is a Schnorr signature over a fixed message, produced using the compromised private key. This allows any client to verify the claim using only the public key.
The message to sign is the UTF-8 string:
this-key-was-compromised-<pubkey>
where <pubkey> is the 64-character lowercase hex encoding of the public key corresponding to the compromised private key.
The proof is the resulting 64-byte Schnorr signature, encoded as a 128-character lowercase hex string.
To verify a proof, a client MUST:
- Reconstruct the message:
this-key-was-compromised-<pubkey>, using the pubkey from the response key. - Verify the Schnorr signature in
proofagainst that message using the same pubkey.
If verification fails, the client MUST discard the result and SHOULD treat the provider response as untrustworthy.
Providers MUST verify each proof before returning it. Providers MUST NOT emit a result with status: "confirmed" without a valid proof.
| Field | Type | Required | Description |
|---|---|---|---|
pubkeys |
array of strings | yes | The pubkeys to check. MUST contain at least one element. Each pubkey MUST follow the format defined in ORE-00. |
algorithm |
string | no | The algorithm to use. If omitted, the provider MUST use the default algorithm for this endpoint as defined in ORE-01. |
Clients SHOULD NOT send more than 1000 pubkeys in a single request. Providers MAY enforce their own limit and SHOULD respond with 413 Payload Too Large if the request exceeds it.
{
"pubkeys": [
"a3f9c...",
"b7e2d...",
"cc481..."
],
"algorithm": "heuristic-v1"
}The response is a flat JSON object mapping each pubkey with a known or suspected compromise to its result object. Pubkeys with no known compromise are omitted. If no compromises are known for any of the requested pubkeys, the response MUST be an empty object.
The shape of each result object depends on its status field, as defined in Result Classes.
{
"b7e2d...": {
"status": "confirmed",
"detected_at": 1700000000,
"proof": "2a9f..."
},
"cc481...": {
"status": "suspected",
"confidence": 0.87
}
}| Status | Description |
|---|---|
200 |
The result is ready and the response body contains the result. |
202 |
The result is not yet available. Clients MUST retry the identical request after the number of seconds indicated by the Retry-After response header. |
| Status | Reason |
|---|---|
400 |
The request body is malformed or not valid JSON. |
413 |
The number of pubkeys in the request exceeds the provider's limit. |
422 |
The pubkeys array is missing or empty. |
422 |
One or more entries in pubkeys are not valid pubkeys. |
422 |
The requested algorithm is not supported by this endpoint. |