Guide to Open Source Nostr Security
People keep asking us to audit AI-built Nostr apps. Our advice: limit the attack surface, audit with AI, use bounties, and when risk is high, ship slow.
We have been getting a lot of requests lately to audit open source Nostr apps. Most of them were built heavily with AI, and some are intended for people in sensitive situations: activists, journalists, people who cannot afford a mistake.
We are not security auditors, and this post is not a substitute for a professional audit. But our team has been shipping open source Nostr software for years, and the advice we give in these conversations is always the same. Given the number of requests of this nature we receive, we decided to write it down.
Is Open Source a Security Liability in the Age of AI?
People keep arguing that AI has made open source a security liability. It's incredibly easy to scan any open codebase with AI and find vulnerabilities. And state actors, including ones hostile to the activists these apps serve, get frontier models before the public does. Publishing your code just gives them a head start.
But hiding your code doesn't fix either of those things. AI is also good at reverse engineering compiled binaries and probing running systems, so closed source slows a well-funded attacker down less than it ever has. What it reliably does is stop everyone else from reviewing your code. Researchers, contributors, and whatever models you do have access to can only audit what they can read.
The open source community has been having this argument for decades. Attackers have always been able to read open code, and open source software has a strong security record anyway, because visibility helps defenders at least as much. The tools have changed. The tradeoffs haven't.
Don't assume hand-written code is the safe baseline either. Human slop predates AI slop by decades. Veracode's State of Software Security reports, built from scans of hundreds of thousands of applications written mostly by humans, have found year after year that roughly three quarters of applications contain at least one security flaw on first scan. Classic industry estimates put defect density at 15 to 50 bugs per 1,000 lines of delivered human code (Steve McConnell, Code Complete). Code needs review either way.
I went through this whole argument in my talk "Open Source is Dead" at Bitcoin++:
Derek Ross
July 16, 2026
@Alex Gleason's talk from Bitcoin++ is now live. Open Source is Dead! https://www.youtube.com/watch?v=w7KQl6qh4yM
View post on Ditto →First, Understand the Nostr Security Model
In traditional Web 2.0 sites, you authorize yourself to a server. You might use OAuth, for example. The server is protecting some resource, usually entries in a database, and you have to prove that you're allowed to access it. If the database were breached, everyone would be screwed.
In Nostr the security model is flipped. You hold a secret key. The secret key IS the protected resource. So instead of authorizing yourself to servers, servers authorize to you. This is a sovereign model where the servers (relays) are dumb data stores designed to serve the user.
Nostr relays don't store user PII. They don't store emails, phone numbers, names, or any other personal information. Users generate their own key out of thin air (a long random number), sign events with it, and publish those events to relays. The authorization model is: is the signature valid? If so, the event is accepted, otherwise it's rejected. The relay doesn't care whose signature it is, just that a valid signature is used. There is nothing to attack. All of the application logic is handled by clients, which query relays for events published by keys they trust. Most data on Nostr is public, but private data is supported using encryption with the private key. To relay operators and everyone else, encrypted data just looks like noise.
As a result, massive data breaches cannot occur on Nostr. The only way to exploit Nostr is through targeted attacks on specific users running specific vulnerable clients. This is "united we stand, divided we fall" encoded into computer infrastructure. Traditional sites like Facebook, and even Mastodon, suffer from data breaches that simply aren't possible on Nostr.
A Nostr client has exactly two security jobs: validate events, and store the secret key safely. The entire security model hinges on these two things.
Event validation is the easy half, because all of the complexity is handled by battle-tested libraries available in every programming language. If those libraries (or the underlying cryptography) were compromised, the world would have much bigger problems. Still, if you're worried, audit them. With AI at your fingertips, no one can stop you.
Storing the secret key safely is harder. That's where the rest of this guide comes in. Relays are considered untrusted by clients anyway, so there is not much you can do wrong with a relay. It's all about the client.
1. Limit the Attack Surface
The simplest way to protect the secret key is to never touch it. When users log in with a remote signer, the application can only call functions like signEvent and decrypt. It cannot access the secret key directly. A compromised client can misuse those functions while it's running, but it cannot exfiltrate the key itself. On the web, browser extension signers (NIP-07) give you the same property. Support these login methods first, and encourage your users toward them.
On desktop, we recommend the Ditto Extension, our open source browser signer. It keeps the key inside the extension and exposes only the NIP-07 signer interface to websites.
When your client does store the secret key, contain it to a single place in the code, and expose a limited signer interface (similar to the remote signer interface) to the rest of your codebase. Your code should act on the signer, never pass the raw key around. This alone mitigates many issues, because the amount of code that can leak the key shrinks to one module you can actually review.
Beyond key containment:
- Web apps: send a Content-Security-Policy header with the site response to defend against cross-site scripting (XSS). Even if an XSS bug exists, a strict CSP neutralizes it. Nostr apps render a lot of user-generated content, so assume XSS attempts will happen.
- Native apps: store the key in secure device storage (Keychain on iOS, Keystore on Android) and take care not to introduce remote code execution vulnerabilities, for example through embedded web views or dynamic code loading.
- Everyone: keep the dependency tree small. Every package you add is code you didn't write running next to the key.
If you're building with MKStack, most of this is done for you. The stack ships with the signer interface and key containment described above, remote signer support, and CSP configuration, so you start with these Nostr best practices already baked in rather than adding them after the fact.
2. Audit With AI
AI review is not a replacement for human review, but it is cheap, fast, and catches real bugs, so there is no reason to skip it.
Generic prompts like "review this code for security issues" produce generic results. Point the AI at the two jobs that matter. Here are prompts you can copy and paste:
Trace every code path in this codebase that touches the Nostr secret key (nsec) or seed phrase. Report every place the key is logged, serialized, stored, passed as a function argument, or sent over the network, including React state and context, localStorage, error reporters like Sentry, analytics payloads, and the clipboard. The key should live in exactly one module behind a signer interface. Flag anything that violates that. For each finding, give the file, the line, a severity (critical, high, medium, low), and how an attacker would exploit it. Only report issues you can point to concrete code for. If you find nothing, say so.Review how this client handles events received from relays. Relay data is untrusted input. Verify that each event's ID is recomputed from its content and that signature validation happens before any event is rendered, stored, or acted upon. Flag any place where relay data is trusted without validation, including tags, kind 0 metadata, and decrypted payloads. For each finding, give the file, the line, a severity (critical, high, medium, low), and how an attacker would exploit it. Only report issues you can point to concrete code for. If you find nothing, say so.Scan this codebase for classic web vulnerabilities: innerHTML and dangerouslySetInnerHTML usage, eval and other dynamic code execution, unsanitized URL and redirect handling, secrets appearing in error messages or logs, and missing or weak Content-Security-Policy configuration. For each finding, give the file, the line, a severity (critical, high, medium, low), how an attacker would exploit it, and a suggested fix. Only report issues you can point to concrete code for. If you find nothing, say so.Run the review more than once, and with more than one model. Different models catch different things, and results vary between runs. Treat findings as leads to verify, not verdicts. An AI review that finds nothing is not a certificate of safety, but an AI review that finds something has saved you an incident.
3. Harness the Open Source Community With Bounties
"Open source means anyone can audit the code" is true, and it's also true that by default, nobody does. Reviewers show up when there is an incentive.
Bounties fix the incentive. You don't need a formal program on a big platform to start. Add a SECURITY.md to your repository with a contact for private disclosure, then publicly offer rewards for concrete outcomes rather than vague ones. "Demonstrate a way to extract the user's secret key from this app" is a good bounty. "Find security bugs" is not, because it invites low-effort reports.
On Nostr you can pay bounties in Bitcoin directly, with no payment processor or bounty platform in the middle. A few hundred dollars in sats for a key-extraction proof of concept is dramatically cheaper than a professional audit, and it pays only on results.
We recently did this ourselves with Armada, our encrypted communities project. I posted a bounty, hzrd149 found a vulnerability and claimed it, and $1,000 in Bitcoin was dispatched:
Alex Gleason
July 13, 2026
Update: @hzrd149 won this bounty. $1k in Bitcoin dispatched. 🫡 Armada being updated!
Alex Gleason
July 7, 2026
You guys should try it! I think you'll enjoy: https://armada.buzz/ And if any of y'all can figure out how to hack or disrupt it I'll pay you Bitcoin, up to $1,000 depending on the severity of your find. Email: alex@soapbox.pub
Put bounties out early, before you have serious at-risk users. A vulnerability found while your user base is small costs you a bounty payment. The same vulnerability found later, in the wild, costs your users.
4. Don't Rush Security-Critical Updates
Speed is a liability in security-critical software. If your users include people in sensitive situations, a slow release costs you little. Shipping a compromised or broken build to people who trusted it can cost them everything.
- Hold releases behind a review window. Cut a release candidate, announce it, and give the community days or weeks to test and review before it becomes the recommended build. Nothing about an update to a working app is urgent, except actual security fixes.
- Pin your dependencies and let new versions age. Most npm supply chain attacks are detected within days of a malicious version being published. If you only adopt dependency updates after they have been public for a while, you let the rest of the ecosystem absorb that risk for you.
- Make builds reproducible where you can. If anyone can rebuild your release from source and get the same artifact, a tampered binary becomes detectable.
This is the opposite of how AI-assisted development usually feels, where shipping ten times a day is the whole point. Ship fast while you're building. Once real people depend on the app for their safety, the release process should slow down on purpose.
5. Help Users Understand Their Risk Surface
A perfectly built client can still get its users hurt if they misunderstand what it protects. If your app serves people in sensitive situations, part of the security work is making the boundaries legible.
- Be explicit about what is public. Most data on Nostr is public and effectively permanent. Users coming from platforms with delete buttons and private accounts will assume protections that do not exist. Say what is public, in the interface, at the moment it matters.
- Explain the metadata. Even when content is encrypted, relays can see IP addresses, publish times, and often who is talking to whom. If your app does not hide the social graph, say so. Users deciding whether to organize on your app need this information more than they need a feature list.
- Make key consequences clear. Anyone who obtains the secret key is the user, everywhere, with no password reset. Users should know this before it matters, along with what to do if the key leaks.
- Publish a plain-language threat model. One page: what the app defends against, what it does not, and what the user is trusting (their device, their relays, your release process). Honest scope is worth more to an at-risk user than a vague promise of security.
Nostr Security Checklist
Master this, and you will have mastered Nostr security. It's all about validating events and protecting the key. Limit how much of your code can touch the key, use AI to check the parts that do, pay strangers to try to break it, give every release time to be looked at before people rely on it, and make sure the people relying on it know exactly what it does and does not protect.
None of this requires a security team or an audit budget. It requires slowing down and doing the checks before people rely on the app.
Limit the attack surface
Remote signers, one key module, CSP headers, secure storage.
Audit with AI
Targeted reviews of key paths and validation, multiple models, repeated runs.
Post bounties
SECURITY.md plus Bitcoin rewards for concrete exploits.
Ship slow
Review windows, pinned dependencies, reproducible builds.
Help users understand their risk surface
Say what is public, what metadata leaks, and what the key means. Publish a plain-language threat model.
Frequently Asked Questions
Is Nostr secure?
Nostr relays store no personal information, so mass data breaches are not possible the way they are on traditional platforms. Security on Nostr comes down to the client: it must validate event signatures and protect the user's secret key. If a client does those two things well, the attack surface is very small.
What is the biggest security risk in a Nostr app?
Mishandling the secret key. The key is the user's entire identity. Clients should either avoid holding the key at all by supporting remote signers, or contain it to a single place in the code behind a limited signer interface.
Is AI-generated code safe to ship?
AI-generated code is not inherently less safe than human code, but it is often shipped faster and with less review. The same AI tools that wrote the code can review it. Run repeated, targeted security reviews with multiple models before shipping, especially for apps used in sensitive situations.
What is a remote signer?
A remote signer is an app or service that holds the user's Nostr secret key and exposes only limited functions like signEvent and decrypt. The client never sees the key itself, so a compromised client cannot leak it.
Do I need a professional security audit?
If your app serves users in high-risk situations and you can afford one, yes. But most of the practical risk in a Nostr client is covered by the five practices above: limiting the attack surface, AI-assisted review, community bounties, delaying releases behind a review period, and helping users understand their risk surface.
Related Reading
Soapbox is funded by grants and donations, not ads or data sales.
Everything we build is open source and belongs to the community. Help us keep it that way.
