# 15 — Production: Durability, Secrets, Law, Longevity

*This is the chapter that decides whether "we run on Nostr" survives contact with a lost key, a deleted file, a subpoena, or a regulator's letter. Chapters 01-13 answer "how does this work." This one answers "what breaks, who is liable when it does, and what do we do before it happens" — the audit rendered as teaching. Grounded in a same-day, three-agent production audit (durability economics, secrets/custody, longevity) plus live re-verification of every load-bearing citation below.*

**Verified: 2026-07-10**

## Confidence

| # | Section | Confidence | Why |
|---|---|---|---|
| 1 | Data-durability economics | High | Direct fetch of the source paper's own numbered sections; two figures corrected from this chapter's source audit (below) |
| 2 | Media persistence | High | Direct ToS + spec fetch; the media-cap figure is corrected from the source audit |
| 3 | Deletion vs. privacy law | **Medium — inference-flagged** | NIP text is High; "no ruling exists" is a documented absence, not a citable presence; the defensible-posture recommendation is explicitly SYNTHESIZED, not documented industry practice |
| 4 | Operator legal exposure | **Medium** | Statute/regulation text is High; applying it to a Ditto instance's classification is reasoned analysis, not an actual ruling; the nearest precedent is fediverse (Mastodon), not Nostr-specific |
| 5 | Degradation engineering | High | Direct fetch of Nostrify and nostr-ux.com docs; corrects this chapter's own source audit's premise (below) |
| 6 | Monitoring + backup | High for spec/tooling; Medium for the Ditto-runbook absence (a negative claim) | NIP-66/Prometheus/Grafana directly confirmed live |
| 7 | Secrets + custody | High | Verified against the maintainers' own configuration files, not just vendor docs |
| 8 | Longevity | Medium-High | Bus-factor/funding figures are this session's own audit measurement, not independently re-run here; pinning/remote evidence is directly verified against the maintainers' own repository |
| 9 | Incident catalog | Medium | The Black Hat paper is High; two of the source audit's named incidents could not be verified live — substituted with verified adjacent evidence, flagged below |

---

## 1. Data Durability: The Economics of "Free"

A 2025 measurement study of the live network — Wei and Tyson, "An Empirical Analysis of the Nostr Social Network: Decentralization, Availability, and Replication Overhead" (arXiv:2402.05709v2, accepted CoNEXT '25) [1] — puts a number on what operators feel anecdotally: **free relay infrastructure does not pay for itself.** Its own finding: "our estimates show 95% of the free-to-use relays cannot cover their operational cost" from donations/zaps alone [1]. Not a governance failure — the base economics of the model.

**Correcting this chapter's source audit:** the audit cited "median zap ≈$67." The paper reports no median — it reports a 90th percentile: relays that receive zaps at all see a 90th-percentile total of 150,000 sats (≈$67) [1]. That is a more damning number, not the same one — if the *top* 10% of zap-earning relays top out near $67, the true median sits lower. Separately, 64% of all relays receive **zero** zaps in the observed window [1]. The paper describes medium-scale paid relays (50-1k users) only qualitatively as "most... able to cover their operational costs" [1] — no exact percentage is given, so this manual does not repeat a "64% of medium paid relays" figure; that 64% belongs to a different statistic (relays earning nothing at all).

What the paper measures precisely is replication and waste: the average post lands on 34.6 relays across 12.4 distinct Autonomous Systems [1] — real redundancy — while 98.2% of download/retrieval traffic network-wide is duplicate, an estimated 144 TiB wasted [1]. The network already over-replicates data it then fails to fund.

**The zero-SLA finding.** No relay or Blossom media host surfaced in this or the source audit's research publishes a contractual uptime or durability guarantee — free or paid. Public infra is a cache. An owned archive relay, plus BUD-04 media mirroring (§2), is storage.

**The practical answer: own your archive relay.** NIP-65 already establishes that a user's write relays are the outbox clients SHOULD check first [2]. The corollary for an operator: run a self-hosted strfry as one of your write relays, treat it as source of truth, and let every public relay you also write to be exactly what §1's economics say it is — a cache with no promises attached.

**The negentropy caveat.** NIP-77 wraps the Negentropy set-reconciliation protocol so an archive relay can catch up with peers without re-transferring events it already holds [3]; it carries `draft` `optional` status as of this verification [3]. Merged into the spec is not the same claim as deployed across the relay population — most public relays do not yet support it. Budget for targeted REQ backfill from each write relay as the default, with negentropy as an accelerant once a peer confirms support, not a dependency.

```mermaid
flowchart TD
    A[App publishes event] --> B["NIP-65 outbox:<br/>user's declared write relays"]
    B --> C1[Public free relay]
    B --> C2[Public paid relay]
    B --> D[Own archive strfry]
    C1 -.->|"95% can't cover costs<br/>no SLA anywhere"| X[Eviction / silent loss]
    C2 -.->|"cache, not storage"| X
    D --> E["cron: strfry export --fried"]
    E --> F[Cold storage backup]
    D -.->|"negentropy sync<br/>where peer supports it"| C1
    D -.->|"targeted REQ backfill<br/>where it doesn't"| C2
```

---

## 2. Media Persistence: Blobs Are Not Backups

nostr.build's free-tier Terms of Service state that for free-service media, nostr.build "has the unrestricted right to delete any uploaded content" [4], and more broadly that it "may ban any user, delete any Media, or terminate any account for any reason or no reason, at their sole discretion, without notice or liability" [4]. Paid plans carry one floor free accounts don't: media stays online for a stated period after account expiration [4] — implying no equivalent floor below that tier.

**Correcting this chapter's source audit:** the audit cited a "100MB cap." Live-checked against nostr.build's own plan and README pages, the actual free-tier ceiling is far lower — 5MB per file on the free service, roughly 20MB as a hard limit on unauthenticated/free uploads; the entry paid tier raises that to 450MB per file. Treat "100MB" as a figure this manual cannot stand behind; re-check the live plan page at time of adoption, since these numbers move.

**The resilience mechanism is BUD-04, not hope.** Blossom's server-to-server mirroring spec defines a `PUT /mirror` endpoint: server B fetches a blob from a URL on server A, verifies the downloaded content's hash against the authorization token, and stores its own copy [5]. Paired with BUD-03 (a user's published server list, per ch06 §5), mirroring is what makes a single host's ToS survivable — if nostr.build deletes a file, a client can still resolve it from another server in the uploader's list, provided a mirror was actually made first. **Mirroring is opt-in and per-upload; nothing forces it to happen.** Any media this organization treats as important — logos, policy-post attachments, anything cited from a long-form NIP-23 post — needs an explicit mirror-on-upload step to a server you control, not an assumption that Blossom's redundancy story covers you by default.

---

## 3. Deletion vs. Privacy Law

Two Nostr-native deletion primitives exist, and they are not the same strength. **NIP-09** is advisory: relays "SHOULD" honor a kind-5 deletion request [6]. **NIP-62 ("Request to Vanish")** is the strong version, merged into the spec on 2025-02-19 [7] — missing from this manual's ch06 NIP table, which currently jumps 61 to 65; add it there. Its language is MUST-level: "Relays MUST fully delete any events from the .pubkey if their service URL is tagged in the event," relays "MUST ensure the deleted events cannot be re-broadcasted," and even "paid relays or relays that restrict who can post MUST also follow the request to vanish regardless of the user's status" [7]. Merged status is not the same claim as universal implementation — adoption is thin, and this manual found no data quantifying it.

**No Nostr-specific privacy ruling exists anywhere.** This chapter searched for a GDPR or CCPA enforcement action, regulatory guidance, or court decision naming Nostr specifically and found none. The nearest general analog: the European Data Protection Board finalized blockchain-specific GDPR guidance on 2026-07-08 — two days before this verification — ruling that encrypted or hashed on-chain data remains personal data, that immutability and encryption are not technical exemptions from GDPR obligations, and that the right to erasure applies "even when blockchain technology makes deleting records technically challenging" [8]. On the US side, commentary on decentralized social platforms generally (Mastodon-class, not Nostr-specific) describes the same structural tension: fragmented server operators and unclear liability assignment under CCPA's comply clock, which assumes a single accountable party exists to receive the request [9]. Neither source rules on Nostr; both describe the exact problem Nostr shares with any federated or append-only architecture — **there may be no single entity who can legally "control" a user's data once it has propagated to relays outside your operation, and "technically hard to delete" is not a recognized excuse.**

**The defensible posture — [SYNTHESIZED INFERENCE, not documented industry practice; no source found states this as a standard]:**
1. Scope every deletion promise to "systems we control" — your own relays, your own Blossom mirrors, your own database exports. Do not promise deletion from relays or clients you do not operate; NIP-62 [7] is a best-effort ask once content has left your infrastructure, not a guarantee.
2. Issue a NIP-62 request as standard practice on any verified deletion ask, understood as best-effort beyond your own systems.
3. For content that must never be recoverable even from your own cold storage, prefer NIP-17/NIP-59 gift-wrapped encryption [10] at time of creation over after-the-fact deletion — destroying the decryption context ("crypto-shredding") is something you can actually guarantee for content you hold the keys to, in a way "delete the plaintext everywhere" is not.

---

## 4. Operator Legal Exposure

Two liability regimes matter, and both turn on the same mechanism: knowledge plus inaction, not mere hosting.

**United States — Section 230 has a criminal-law hole.** 47 U.S.C. §230(e)(1): "Nothing in this section shall be construed to impair the enforcement of section 223 or 231 of this title, chapter 71 (relating to obscenity) or 110 (relating to sexual exploitation of children) of title 18, United States Code, or any other Federal criminal statute" [11]. Section 230's civil immunity was never a shield against federal criminal prosecution, CSAM statutes included. Separately, 18 U.S.C. §2258A obligates a provider that obtains actual knowledge of apparent CSAM to report it to NCMEC's CyberTipline "as soon as reasonably possible" [12] — most recently amended 2025-12-18 (Pub. L. 119-60) [12]. This duty attaches to knowledge, not to platform size or architecture.

**European Union — actual-knowledge-plus-inaction, with size-tiered duties layered on top.** Article 6(1) of Regulation (EU) 2022/2065 exempts a host from liability for stored content only if it "(a) does not have actual knowledge of illegal activity or illegal content... or (b) upon obtaining such knowledge or awareness, acts expeditiously to remove or to disable access to the illegal content" [13]. **Correcting this chapter's source audit:** small and micro enterprises are exempted from Chapter III Section 3 (Articles 19-28 — internal complaint handling, trusted flaggers, most transparency reporting) except Article 24(3)'s active-user-count reporting, which still applies [14]. Independent-audit duties sit at Article 37, not 42, and apply only to designated Very Large Online Platforms/Search Engines in the first place — small/micro operators were never in that scope, so this isn't something they're "exempted" from so much as categorically outside of [14]. What size never exempts anyone from: **Article 16's notice-and-action mechanism**, in Section 2, applying to every hosting provider regardless of size [14] — a visible, working way to flag illegal content is baseline, not a large-platform-only duty.

**Enforcement is not staying at the top of the size ladder.** National Digital Services Coordinators, not only the European Commission, are "the primary point of contact for users and the enforcers of the DSA's obligations on smaller platforms" [15] — enforcement structurally reaches non-VLOP platforms through this national layer, even though public attention has focused on designated giants.

**Product shape sets the liability tier — [reasoned application of the DSA's structure, not a ruling that has classified either product].** A bare relay — a WebSocket server storing and forwarding events with no public-facing dissemination surface — reads as mere hosting. A Ditto instance bundles a Mastodon-API-compatible web UI that disseminates content to the public at a recipient's request, the DSA's own definitional shape for "online platform" — a heavier class carrying Article 16's duty regardless of size, plus Section 3's obligations once large enough to matter. Treat a Ditto-based community instance as if it is an "online platform," not a bare relay, when scoping compliance work.

**The nearest real precedent is the fediverse, not Nostr.** The Stanford Internet Observatory's "Child Safety on Federated Social Media" (Thiel & DiResta, 2023-07-24) scanned the 25 most popular Mastodon instances over two days and found 112 PhotoDNA hash matches for known CSAM, plus nearly 2,000 posts using the top 20 hashtags associated with CSAM-trading communities [16] — all reported to NCMEC. Mastodon is federated, not relay-based, but it is the closest architecturally-similar network anyone has actually audited for this failure mode, and the finding generalizes uncomfortably well: decentralized, low-moderation-friction networks accumulate this content measurably, not hypothetically, once they reach any scale.

**What mitigation looks like in practice:** a visible, working notice-and-action mechanism; a real NCMEC relationship established before it's needed, not after; human-reviewed report queues. NIP-56 itself warns against pure automation — "reports are easily manipulated," with "trusted moderator judgment" as the intended backstop [17] — which happens to match what both US and EU law expect: a human acting on knowledge, not a bot acting on volume.

---

## 5. Degradation Engineering

**The hang risk is real but method-specific — not the blanket claim this chapter's source audit assumed.** Nostrify's `NPool` exposes two request shapes [18]. `pool.req()` waits for an EOSE from every relay in the pool with no documented timeout at all — one unresponsive relay can hang the whole call indefinitely. `pool.query()`, by contrast, ships a documented default: 1000ms after the first relay's EOSE before giving up on the rest (`eoseTimeout`, configurable, settable to `0` to force wait-for-all) [18]. **Correction: "no documented default timeout" only holds for `pool.req()`.** Use `pool.query()` for anything user-facing; treat `pool.req()` as the specific call that needs an operator-added timeout wrapper if used at all.

**Ship the pattern, don't invent it.** nostr-ux.com's core-interaction patterns give implementable numbers: a 5-second timeout on the primary publish flow (`timeout: 5000`, "Pattern A: Reliable Post Publishing") [19]; treat an action as successful once at least 3 relays confirm (`successful.length >= 3`) [19]; render partial success explicitly — `"[!] Posted (2/4 relays) [Retry]"` [19]; retry stragglers in the background with exponential backoff, never blocking the user on them [19]. This is shared infrastructure every consumer-facing app needs and no framework in this stack provides by default.

**The replaceable-event wipeout class is real and documented, though not at the specific citation this chapter's source audit named.** Live re-verification could not locate the "franzap" stacker.news post the audit cited. What is directly verifiable: `nostr-protocol/nips` issue #261 documents the identical failure class — kind-0 (profile) and kind-3 (contact list) events are fully replaceable, so "for each combination of pubkey and kind, only the latest event must be stored," and a client publishing its own partial view of a profile (missing a field it doesn't understand, e.g. a lightning address) silently erases that field for every other client, because the relay has no mechanism to merge two partial updates [20]. Never publish a replaceable event kind from a partial local model of it — merge against the latest known state first, or you become the client that wipes someone's profile.

---

## 6. Monitoring + Backup

**Relay health has a NIP.** NIP-66 ("Relay Liveness Monitoring") defines kind 30166 (a monitor's probe results — RTT for open/read/write, auth requirements, DNS resolution, geolocation) and kind 10166 (a monitor announcing itself) [21]. Its own text builds in graceful degradation: "Clients MUST NOT require 30166 events to function. Absence of monitoring data MUST NOT prevent relay connections" [21] — a signal layered on top of §5's degradation patterns, not something they can depend on. nostr.watch is the ecosystem's most visible public implementation of relay monitoring, useful for spot-checking a relay's general reputation before depending on it — a third-party view, not your own instrumentation.

**Metrics are first-party on the relay software itself.** strfry ships built-in Prometheus metrics: "Metrics are exposed via HTTP at the `/metrics` endpoint on the same port as the relay WebSocket server" [22]. nostr-rs-relay carries the same shape internally — a `create_metrics()` Prometheus registry wired into its server code, exposed at its own `/metrics` endpoint [23]. Either pairs directly with **Grafana dashboard 21844**, a community-maintained Ditto dashboard published on Grafana Labs [24] — the fastest path to a working operational view if Ditto is any part of the stack.

**Ditto's backup story is a gap, not an oversight you missed.** This chapter's source audit searched twice for a first-party Ditto backup runbook and found none either time [25]. Ditto's storage is Postgres — which makes the discipline here entirely conventional, not Nostr-specific: `pg_dump` on a schedule at minimum, `pgBackRest` (or an equivalent WAL-archiving tool) for anything called production. Pair this with §1's archive-strfry backup story — event data and Ditto's relational state are two different backup problems, and Ditto ships a runbook for neither.

---

## 7. Secrets + Custody

*The mental model every other stack teaches does not transfer here. There is no "rotate the key" button.*

**No rotation mechanism exists, full stop.** NIP-41 (key migration) has been an open pull request since October 2023 — three approvals, over 100 comments, still unmerged as of its most recent activity (2025-11-25) [26], blocked on an unresolved fight over automatic migration's griefing window ("stolen recovery kits enable permanent griefing... you will always worry whether you're losing your social graph to scammers," per one maintainer's objection) [26]. NIP-26 (delegated signing), once floated as a workaround, is deprecated [27]. If an nsec leaks, there is no protocol-level undo — every mitigation below is blast-radius reduction, not a rotation story.

**FROSTR is the closest exception, and it is early.** FROSTR implements FROST threshold signatures over Nostr relays: split an nsec into t-of-n shares across signing devices, and a threshold of shares signs without ever reconstituting the full key [28]. Rotation, in FROSTR's model, means destroying the old shares and issuing a new set — the npub never changes [28]. Its browser-extension component is explicitly documented as "under heavy development" [29]; its core library (Bifrost) is further along — v2.0.2, released 2026-01-25, with a documented threat model [28] — but nothing in the ecosystem carries a completed third-party audit as of this verification. Revisit for brand-key custody once it exits that phase.

**Keycast is the team-custody answer, with its own caveat attached.** Keycast targets teams specifically (versus nsec.app/Amber for individuals, ch06 §1), with row-level AES-256 encryption, file- or AWS-KMS-backed key storage, and policy-gated NIP-46 remote signing [30]. Its own README states the caveat this manual adopts: "Keycast is an early-stage project. A May 2026 audit found and fixed several auth, permission, data integrity, and dependency issues, but this should still get a deployment review before it is trusted with real team keys on the public internet" [30]. Read that as audited, not yet trust-worn.

**Structurally, there is no HSM/KMS integration and no keyless-signing analog anywhere in this ecosystem.** Every custody tool above is a software wallet with better or worse blast-radius properties — none hands signing authority to a hardware security module or a short-lived, identity-bound credential the way mainstream software-supply-chain tooling (Sigstore/Fulcio, cloud KMS) does. This is a gap in the protocol's tooling, not any one product's oversight.

**The stack's own defaults point the wrong way.** Both products in this manual that document their server-side signing pattern do it the same way — a raw nsec in an environment variable. Ditto (Deno + Postgres) documents `DITTO_NSEC`; ditto-relay (Bun + OpenSearch) documents `NOSTR_NSEC` [31] — do not conflate the two; they are different products with different variable names.

### Secrets architecture (the maintainers' own adopted pattern — a reusable template for your own Nostr work)

| Secret type | Storage | Rotation story | Detection |
|---|---|---|---|
| Brand nsec | Keycast (self-hosted, deployment-reviewed) or nsec.app interim [30] | None — grant revocation on teammate departure, not rotation; revisit FROSTR once it exits heavy development [28][29] | gitleaks custom rule (below) |
| Per-service nsec (relay identity, bots, publishers) | Injected from a secret store at deploy only — never in repo, Dockerfile, or wrangler.toml | None — one npub per service keeps blast radius small and audit trails attributable via `authors` queries | gitleaks custom rule (below) |
| Human-touchable backups | `ncryptsec` (NIP-49) [32], passphrase in its own secret-store entry | Re-encrypt on passphrase rotation only | gitleaks custom rule (below) |
| CI signing key | Encrypted blob + passphrase from secret store (same shape as GPG signing), own npub per pipeline | Passphrase rotation only | gitleaks custom rule (below) |
| `VITE_*` build-time config | Public by construction — baked into the client bundle as literal strings | N/A — never put a secret here | Treat as already public; anything sensitive goes in a Worker secret (`wrangler secret put`) |

**gitleaks has zero Nostr coverage by default, and that is now fixed in the maintainers' own workspace.** The default ruleset ships roughly 190+ rules covering AWS/Azure/GCP, Stripe/PayPal, Slack/Discord, GitHub/GitLab, and more [33] — and not one pattern for `nsec1…`, `ncryptsec1…`, or a `bunker://` secret. A committed raw nsec would pass CI today on the default config alone. The maintainers' own `.gitleaks.toml` now extends the default set with three custom rules — `nostr-nsec` (`nsec1[a-z0-9]{58}`), `nostr-ncryptsec` (`ncryptsec1[a-z0-9]{80,}`), and `nostr-bunker-secret` (an embedded `secret=` parameter in a `bunker://` URI) — landed the same day as this audit [34]. If you fork this pattern into your own repo, copy that file before the first Nostr credential exists there, not after.

**The `nostr-security` skill shipped with this stack does not cover any of the above, and should not be mistaken for doing so.** Read directly, its threat model is entirely XSS/CSP: `localStorage` key theft via script injection, URL and CSS sanitization for untrusted event data, `authors` filtering for trust-sensitive queries [35]. It never mentions `.env` discipline, `VITE_` exposure, key rotation, or custody. That is a correct and useful scope for what it covers — the risk is an operator reading "we have a nostr-security skill" and assuming secrets sit inside its perimeter. They do not; extend this fork's AGENTS.md with a dedicated secrets section rather than growing this skill past its stated scope.

---

## 8. Longevity: Funding, Bus Factor, Exit Playbook

**Funding is one demonstrated line.** This chapter's source audit measured the funding picture directly: OpenSats is the one confirmed, self-reported funding relationship; the Human Rights Foundation, previously assumed a grantor, reclassifies on closer reading to a prize/event partner — no 2026 grant naming Soapbox, Ditto, or Agora was found anywhere [25]. MIT/AGPL licensing makes forking every component in this stack legal. It does not make forking cheap once a maintainer disappears — that is a bus-factor problem, and pre-positioning against it now is inexpensive; doing it after a maintainer goes dark is not.

**Bus factor, measured this session via each repo's contributor history** [25]:

| Repo | Primary-author share | Read |
|---|---|---|
| Nostrify | 85.2% (Gleason) | High-risk — the framework every MKStack app compiles against has one author |
| mkstack | 71.9% (Gleason) | High-risk |
| ditto-relay | 99.3% (Gleason) | Highest concentration measured |
| Ditto | 47.4% (Gleason) | Healthiest of the four — the only repo with real secondary maintainers |

**Two cheap moves, one already partly done here.** First: add a fetch-only `upstream` remote to any fork of an upstream Soapbox/MKStack repo, so `git diff <pin> upstream/main` is a live command instead of a dead note. The maintainers' own `trespies-stack` fork already has one — `git remote -v` shows `upstream → gitlab.com/soapbox-pub/mkstack.git (fetch)`, push disabled [verified directly, 2026-07-10] — extend the same pattern to any other forked component before treating a commit pin as more than documentation. Second: schedule recurring re-verification of this manual's highest-churn claims (tags, licenses, DNS, funder pages, bus factor) — every number in the table above has a shelf life.

### Per-component exit playbook

| Component | Exit posture | Why |
|---|---|---|
| Ditto | YES — fork and self-maintain | AGPL; 47.4% bus factor is the healthiest measured; Postgres backend is boring and portable |
| Nostrify | CONDITIONAL — vendor the source | 85.2% bus factor on the one library every MKStack app depends on; vendoring plus one engineer who has read `NStore`/`NRelay` end-to-end is the insurance |
| MKStack | CONDITIONAL — license ask outstanding | A license-clarification ask to Soapbox is drafted but unsent; confirm before treating forked output as unencumbered |
| Shakespeare | YES — export and go | AGPL; output is a static/portable site — the tool disappearing doesn't strand what it already built |
| NostrHub | CONDITIONAL — `license: None`, repo one month old | Created 2026-06-11, zero stars/forks at last check, no license file at all — treat anything built against it as provisional until that changes |
| ditto-relay | CAUTION | 99.3% bus factor, roughly five months old, no known external production deployment found beyond Soapbox's own — use behind an exit hatch, not as a dependency without a workaround |

### Pre-positioning checklist (ranked by cost)

1. **Send the outstanding MKStack + NostrHub license outreach.** The ask is drafted; NostrHub's `license: None` gap is a new finding this closes at the same time. One email; the window closes permanently if the maintainer goes dark first.
2. **Add fetch-only `upstream` remotes** to every forked component that doesn't have one yet (one already does — see above).
3. **Schedule recurring re-verification** of this manual's high-churn claims via your own scheduling tooling.
4. **Vendor Nostrify's source locally**, and have one engineer read `NStore`/`NRelay` end-to-end — insurance on the single highest-leverage bus-factor risk in the stack.
5. **Stand up the archive strfry** from §1, syncing from every relay this organization writes to, with a cron export to cold storage.
6. **Open a light relationship with Ditto's non-Gleason maintainers** — low-touch, before it's needed.
7. **Keep at least one paid relay in the relay budget**, on the economics established in §1.

---

## 9. Incident Catalog

**Black Hat USA 2025 — "Not Sealed: Practical Attacks on Nostr, a Decentralized Censorship-Resistant Protocol."** Presented 2025-08-06 by Hayato Kimura, Ryoma Ito, Kazuhiko Minematsu, Shogo Shiraki, and Takanori Isobe [36]; the underlying paper (preprint title "Not in The Prophecies: Practical Attacks on Nostr," eprint.iacr.org/2025/1459) [37] describes four attack classes — plaintext recovery, DM forgery, profile forgery, and Bitcoin-payment hijacking — rooted in flawed client-side signature verification compounded by CBC-mode encryption weaknesses and a link-preview mechanism that leaks a recipient's IP address and message-open timing via external HTTP fetches [36][37]. The research affected past versions of four named clients: **Damus (iOS), Iris (iOS), FreeFrom (iOS/Android), and Plebstr** [36]. No CVE identifiers were found assigned to any of these findings in available sources. This is the concrete answer to "why migrate off NIP-04 at all": the researchers' own recommendation matches this manual's ch06 guidance exactly — move to NIP-44-based encryption and NIP-17+NIP-59 gift-wrapped DMs, disable automatic link previews, and prefer clients that verify every event signature [36].

**The replaceable-event wipeout class** (mechanism in §5) is documented directly in the protocol's own issue tracker, `nostr-protocol/nips` issue #261 [20] — real, citable, still open. **This chapter's source audit also named a specific incident — a "franzap" post on stacker.news — that could not be independently re-verified live**; the citation did not resolve to retrievable content this session. What live research surfaced instead: two real, narrower Damus bugs — issue #1994, "Profile is wiped (Balaji's bug)," a local profile-edit bug from 2024-02 [38], and issue #2264, "bookmarks wiped on purple expiration," a local bug from 2024-05 [39] — neither of which is the "relay-upgrade wipe" the source audit described, though both confirm the same underlying lesson: client-side state and relay-side state disagreeing silently is a recurring Nostr bug class, not a one-off. Nostr's own explainer material states the broader durability risk plainly: "If all the relays that you have used in the past go offline, all your posts will be unretrievable" [40].

**DVM decay as protocol-churn precedent.** NIP-90 (Data Vending Machines) — the base spec for AI-job marketplaces relevant to DojoGenesis-style agent dispatch — is itself now marked `unrecommended`, its own text conceding "this got totally out of control, prefer use-case-specific microstandards" [41]. Governance moved to an informally-maintained sister kind-registry repo rather than the spec dying outright [41]. The lesson for anything built on this manual's NIP table: merged into the spec is a snapshot, not a guarantee. Re-verify currency verdicts on the cadence recommended in §8, not once at project start.

**Disclosure note.** ditto-relay — the Bun-based relay/search product covered in ch13 — runs on a runtime Anthropic acquired on 2025-12-02 [42][43]. This manual is Claude-authored, researching a stack whose relay layer partly depends on an Anthropic-owned runtime. Bun remains open-source and MIT-licensed under the new ownership [42], so this changes no technical recommendation above — but it's the kind of overlap a trustworthy manual states rather than leaves for a reader to notice first.

---

## Sources

1. [Wei & Tyson — "An Empirical Analysis of the Nostr Social Network: Decentralization, Availability, and Replication Overhead"](https://arxiv.org/abs/2402.05709v2) (full text: [arxiv.org/html/2402.05709v2](https://arxiv.org/html/2402.05709v2)), accepted CoNEXT '25 — accessed 2026-07-10 — free-relay cost coverage (95%), zap-income percentile ($67/90th), replication factor (34.6 relays/12.4 ASes), wasted bandwidth (98.2%/144 TiB).
2. [NIP-65: Relay List Metadata](https://github.com/nostr-protocol/nips/blob/master/65.md) — accessed 2026-07-10 — outbox model.
3. [NIP-77: Negentropy Syncing](https://github.com/nostr-protocol/nips/blob/master/77.md) — accessed 2026-07-10 — draft/optional status, bandwidth-efficient reconciliation.
4. [nostr.build Terms of Service](https://account.nostr.build/tos) (nostr.build/tos/ redirects here) — accessed 2026-07-10 — free-tier unrestricted deletion right; plan limits cross-checked against [account.nostr.build/plans](https://nostr.build/plans/) and the [FOSS README](https://github.com/nostrbuild/nostr.build).
5. [BUD-04: Mirroring Blobs](https://github.com/hzrd149/blossom/blob/master/buds/04.md) — accessed 2026-07-10 — server-to-server mirroring mechanism.
6. [NIP-09: Event Deletion Request](https://github.com/nostr-protocol/nips/blob/master/09.md) — accessed 2026-07-10 — advisory SHOULD-level deletion.
7. [NIP-62: Request to Vanish](https://github.com/nostr-protocol/nips/blob/master/62.md); merge commit [619e3be, "Right to Vanish (#1256)"](https://github.com/nostr-protocol/nips/commits/master/62.md) — accessed 2026-07-10 — MUST-level deletion, merged 2025-02-19.
8. [EDPB — Guidelines on processing of personal data through blockchain technologies](https://www.edpb.europa.eu/documents/guideline/guidelines-on-processing-of-personal-data-through-blockchain-technologies_en), finalized 2026-07-08 — accessed 2026-07-10 — no technical exemption from GDPR obligations; right to erasure applies despite technical difficulty.
9. [Decentralized Social Media and CCPA Compliance](https://secureprivacy.ai/blog/decentralized-social-media-ccpa) — accessed 2026-07-10 — fragmented-liability framing for federated platforms under CCPA.
10. [NIP-17: Private Direct Messages](https://github.com/nostr-protocol/nips/blob/master/17.md) / [NIP-59: Gift Wrap](https://github.com/nostr-protocol/nips/blob/master/59.md) — accessed 2026-07-10 — encryption mechanics underlying the crypto-shredding inference.
11. [47 U.S.C. §230](https://www.law.cornell.edu/uscode/text/47/230) — accessed 2026-07-10 — §230(e)(1), no effect on federal criminal law.
12. [18 U.S.C. §2258A](https://www.law.cornell.edu/uscode/text/18/2258A) — accessed 2026-07-10 — NCMEC CyberTipline reporting duty, current through Pub. L. 119-60 (2025-12-18).
13. Regulation (EU) 2022/2065 (Digital Services Act), Article 6 — [eur-lex.europa.eu/eli/reg/2022/2065](https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32022R2065) — accessed 2026-07-10 — actual-knowledge-plus-inaction hosting liability standard.
14. DSA Articles 16, 19, 24, and 37 — [eu-digital-services-act.com/Digital_Services_Act_Articles.html](https://www.eu-digital-services-act.com/Digital_Services_Act_Articles.html) — accessed 2026-07-10 — small/micro exemption scope (Section 3 minus Art. 24(3)), notice-and-action baseline (Art. 16, all sizes), audit obligation (Art. 37, VLOP/VLOSE-only).
15. [The Dawn of DSA Enforcement — Lessons from the Digital Services Coordinators' First Annual Reports](https://the-platform-law.com/2025/10/06/the-dawn-of-dsa-enforcement-lessons-from-the-digital-services-coordinators-first-annual-reports/), Platform Law Blog, 2025-10-06 — accessed 2026-07-10 — DSC enforcement reaching smaller platforms.
16. [Thiel & DiResta — "Child Safety on Federated Social Media"](https://purl.stanford.edu/vb515nd6874), Stanford Internet Observatory, 2023-07-24 (see also [fsi.stanford.edu coverage](https://fsi.stanford.edu/news/addressing-child-exploitation-federated-social-media)) — accessed 2026-07-10 — 112 PhotoDNA CSAM matches, ~2,000 hashtag-flagged posts across 25 Mastodon instances.
17. [NIP-56: Reporting](https://github.com/nostr-protocol/nips/blob/master/56.md) — accessed 2026-07-10 — warning against automated moderation on report volume.
18. [Nostrify — NPool](https://nostrify.dev/relay/pool) — accessed 2026-07-10 — `pool.req()` vs `pool.query()` EOSE/timeout behavior, `eoseTimeout` default.
19. [nostr-ux.com — Core Interaction Loops](https://nostr-ux.com/docs/patterns/03-core-interactions/) — accessed 2026-07-10 — 5s publish timeout, 3-relay confirm threshold, partial-success UI, background backoff retry.
20. [nostr-protocol/nips issue #261 — "Metadata. Kind:0 Profiles."](https://github.com/nostr-protocol/nips/issues/261) — accessed 2026-07-10 — replaceable-event field-overwrite failure class.
21. [NIP-66: Relay Liveness Monitoring](https://github.com/nostr-protocol/nips/blob/master/66.md) — accessed 2026-07-10 — kind 30166/10166, graceful-degradation clause.
22. [strfry README — Prometheus metrics](https://github.com/hoytech/strfry/blob/master/README.md) — accessed 2026-07-10 — built-in `/metrics` endpoint.
23. [scsibug/nostr-rs-relay](https://github.com/scsibug/nostr-rs-relay) (see [server.rs](https://github.com/scsibug/nostr-rs-relay/blob/master/src/server.rs)) — accessed 2026-07-10 — built-in `create_metrics()` Prometheus registry.
24. [Grafana dashboard 21844 — Ditto](https://grafana.com/grafana/dashboards/21844-ditto/) — accessed 2026-07-10 — community-maintained Ditto operational dashboard.
25. Maintainers' internal production-secrets-longevity audit note (companion document, not part of this public chapter set; same-session production audit) — internal source, 2026-07-10 — Ditto backup-runbook absence (twice-confirmed), funding verdict, bus-factor measurements.
26. [NIP-41 pull request #829](https://github.com/nostr-protocol/nips/pull/829) — accessed 2026-07-10 — unmerged since October 2023, griefing-risk objection.
27. [NIP-26: Delegated Event Signing](https://github.com/nostr-protocol/nips/blob/master/26.md) — accessed 2026-07-10 (also ch06) — deprecated.
28. [FROSTR-ORG/bifrost](https://github.com/frostr-org/bifrost) — accessed 2026-07-10 — FROST threshold-signing library, v2.0.2 (2026-01-25), documented threat model.
29. [FROSTR-ORG/frost2x](https://github.com/FROSTR-ORG/frost2x) — accessed 2026-07-10 — browser-extension signer, "under heavy development."
30. [Keycast](https://github.com/marmot-protocol/keycast) — accessed 2026-07-10 — team key management, May 2026 audit caveat (quoted verbatim from README).
31. This manual, ch06 §3 correction log — `DITTO_NSEC` (Ditto, Deno+Postgres) vs `NOSTR_NSEC` (ditto-relay, Bun+OpenSearch); see [ch06](./06-nostr-foundations.md).
32. [NIP-49: Private Key Encryption](https://github.com/nostr-protocol/nips/blob/master/49.md) — accessed 2026-07-10 (also ch06) — `ncryptsec` backup format.
33. [gitleaks default config](https://raw.githubusercontent.com/gitleaks/gitleaks/master/config/gitleaks.toml) — accessed 2026-07-10 — ~190+ default rules, zero Nostr coverage.
34. The maintainers' `.gitleaks.toml` (their own workspace root) — read directly, 2026-07-10 — three custom Nostr credential rules, landed same-day as the source audit.
35. `trespies-stack/.agents/skills/nostr-security/SKILL.md` (the maintainers' own MKStack fork) — read directly, 2026-07-10 — confirmed XSS/CSP/injection-only scope; no custody or `.env` coverage.
36. [Black Hat USA 2025 — "Not Sealed: Practical Attacks on Nostr, a Decentralized Censorship-Resistant Protocol"](https://i.blackhat.com/BH-USA-25/Presentations/USA-25-Kimura-Not-Sealed-Practical-Attacks-on-Nostr.pdf) (project page: [crypto-sec-n.github.io](https://crypto-sec-n.github.io/)) — presented 2025-08-06 — accessed 2026-07-10 — named affected clients, attack classes, mitigation recommendations.
37. [eprint.iacr.org/2025/1459 — "Not in The Prophecies: Practical Attacks on Nostr"](https://eprint.iacr.org/2025/1459) — accessed 2026-07-10 — abstract, attack-class taxonomy.
38. [damus-io/damus issue #1994 — "Profile is wiped (Balaji's bug)"](https://github.com/damus-io/damus/issues/1994) — accessed 2026-07-10 — local profile-edit data-loss bug, 2024-02.
39. [damus-io/damus issue #2264 — "bookmarks wiped on purple expiration"](https://github.com/damus-io/damus/issues/2264) — accessed 2026-07-10 — local data-loss bug, 2024-05.
40. [nostr.how — relays explainer](https://nostr.how/en/relays) — accessed 2026-07-10 — "if all the relays... go offline, all your posts will be unretrievable."
41. [NIP-90: Data Vending Machines](https://github.com/nostr-protocol/nips/blob/master/90.md) (also ch06) — accessed 2026-07-10 — deprecation notice, successor governance.
42. [Anthropic — "Anthropic acquires Bun as Claude Code reaches $1B milestone"](https://www.anthropic.com/news/anthropic-acquires-bun-as-claude-code-reaches-usd1b-milestone) — accessed 2026-07-10 — acquisition announcement, 2025-12-02; Bun remains MIT-licensed.
43. [Bun — "Bun is joining Anthropic"](https://bun.com/blog/bun-joins-anthropic) — accessed 2026-07-10 — corroborating first-party announcement.
