Nostr Key Management & Signer Security: Where Your nsec Actually Lives
Never paste an nsec into a web page. An nsec1… string is your raw private key in plaintext — bech32 is an encoding, not encryption. Whoever reads it owns your identity permanently, because Nostr has no key rotation and no revocation. Any site asking for your nsec should be closed, not corrected. D-Central's own NIP-19 converter refuses private-key input by design, and so should everything else.
Quick answer
A Nostr account is exactly one secp256k1 keypair — the same curve as Bitcoin, BIP-340 Schnorr signatures, x-only public keys as in Taproot. That makes key management the whole of Nostr security, and it is harsher than Bitcoin's: there is no account record, no registrar and no issuer, so there is nothing that can mark a key revoked. The practical question is therefore not which client you like but where your private key physically lives and who can reach it. The options run from a dedicated signer app that holds the key in OS-protected storage and hands back only signatures, through self-hosted and hosted remote signers, to browser extensions, down to pasting the raw key into an app — which is the absence of a signer rather than a kind of one.
Pick the option that keeps the key out of the client. On Android that is a NIP-55 signer app; for desktop, web and iOS it is a self-hosted NIP-46 bunker, with a hosted bunker a materially weaker fallback; a NIP-07 browser extension is a solid improvement over pasting. Hardware signing for Nostr is not production-ready today, whatever a comparison chart may imply. And treat your nsec as permanent: back it up encrypted with NIP-49, never broadcast it, and assume you will never get to change it.
The fact that governs everything else: you cannot rotate a Nostr key
No — as of July 2026 a compromised Nostr key cannot be rotated or revoked, and there is no shipped mechanism, no merged spec, and no rough consensus on one.
How we verified that
The frequently cited "NIP-41" does not exist. Fetching 41.md from the nostr-protocol/nips repository returns HTTP 404; the numbered file sequence runs 38, 39, 40, 42, 43, 44 with no 41; the commits API filtered to path 41.md returns an empty array, meaning no commit has ever touched that filename; and it is absent from the README index. The number is simply unallocated. What does exist is five open, unmerged migration proposals — #1056 (2024-02-16), #1452, #2114, #2137, #2139 — plus #1906, closed 2025-05-07. The oldest has been open roughly 2.5 years, and the two most recent disagree on philosophy rather than detail: #2137 is a cryptographic scheme using OpenTimestamps-anchored precommits and Shamir-split migration keys, while #2139's author states he does not believe in cryptographic securities for key migration because they require a global state which we don't have. Unresolved objections on the record include relay centralization, the attacker-migrates-first attack, migration-as-harassment, and a sharding weakness. NIP-26 "Delegated Event Signing" is not the workaround either — it is struck through in the index as "unrecommended: adds unnecessary burden for little gain".
What it means if your key leaks
If your nsec leaks, the attacker can sign any event as you, forever, indistinguishably from you: post as you, DM as you, rewrite your kind-0 profile and your follow list. Both of you hold equally valid signing authority over the same pubkey, and no relay or client can cryptographically tell the legitimate holder from the thief — both produce valid BIP-340 signatures. There is no password to change and no operator to appeal to.
What you can actually do about it
The only recourse is social. Generate a new key, then tell your followers out-of-band — through channels they already trust — to re-follow the new pubkey and distrust the old one. Followers do not transfer and reputation does not transfer, so expect to rebuild. Plan every other decision on the assumption that your nsec is permanent and unrevocable, because today it is.
Recommendation ladder, safest first
The single question that orders this list is how far the private key sits from the code that renders your feed.
1 Dedicated signer app (NIP-55, Android)
The client hands events to the signer, which holds the key in OS-protected storage and returns signatures, so the key never leaves the device — configure the Content Resolver's remembered permissions conservatively, since that background path is what removes approve-every-event fatigue.
2 Self-hosted remote signer / bunker (NIP-46)
The key lives on a machine you control and clients reach it over relays using kind 24133 events with NIP-44-encrypted payloads, matching the spec's own rationale that private keys should be exposed to as few systems as possible; this is also the main answer for iOS and desktop web.
3 Third-party hosted bunker service (NIP-46)
Same NIP, materially weaker trust model — a hosted operator holds your key material, and a breach there is unrecoverable given there is no rotation, so do not let a comparison table flatten this into the self-hosted case.
4 Browser extension (NIP-07)
The page never sees the key, calling only window.nostr.getPublicKey() and window.nostr.signEvent(), which is a solid architecture and a large improvement over pasting — but extensions auto-update, can change ownership, and run with broad privileges, so prefer ones that also encrypt at rest behind a NIP-49 password.
5 Raw nsec in a native or desktop client
The app holds your plaintext key, so you are trusting that binary and its entire dependency tree forever — acceptable only for a low-stakes or disposable identity, and the common iOS fallback lands here.
6 An nsec entered into a web page — never do this
The page's JavaScript then holds your permanent, unrevocable identity, exposed to any XSS, any compromised or typosquatted build dependency, any compromised CDN, any browser extension with page access, plus history, autofill, and clipboard persistence — and because there is no revocation, there is no remediation afterward, so the correct response to any site asking for an nsec is to close the tab.
Every signing option, and where your key ends up
Grouped by architecture. “Where the key lives” is the field that matters most; read it before the feature list.
Amber (NIP-55, on-device) Android signer high confidence
- Where the private key lives
- On the Android device only, in app-private storage, encrypted with an AES-256-GCM wrapping key held in the Android Keystore. Verified in SecureCryptoHelper.kt: ANDROID_KEYSTORE = "AndroidKeyStore", TRANSFORMATION = "AES/GCM/NoPadding", .setKeySize(256). On Android P+ it attempts .setIsStrongBoxBacked(true) (hardware secure element), excludes MediaTek devices via a hasStrongBox() check on hardware/board/SOC manufacturer strings, and falls back to TEE with .setIsStrongBoxBacked(false) if StrongBox generation throws. IMPORTANT AND OFTEN MISREAD: the secure element holds only the AES wrapping key, NOT the nostr private key. The secp256k1 Schnorr signing is done in software, which means the plaintext nsec is unwrapped into the app's process memory on every signing operation. This is not secure-element signing and Amber is not a hardware signing device. The README confirms the design goal is to sign "without any need for servers or additional hardware."
- Who you must trust
- You trust: the Amber app binary itself (MIT, effectively single-maintainer, greenart7c3), the Android OS, the app sandbox, and your device's Keystore/StrongBox implementation. You do NOT have to trust the client app with key material — clients receive signatures only. For same-device NIP-55 signing, no server, relay, or third party is in the trust path. In NIP-46 bunker mode a relay is added as transport but sees only encrypted kind 24133 payloads, not the key. The understated part: pre-authorization is a real delegation of trust. NIP-55 lets a client request a permissions array, and once granted, the Content Resolver path serves those requests silently in the background with no prompt. A client holding blanket sign_event permission can obtain signatures on arbitrary events of the permitted kinds without you ever seeing it — functionally a standing signing right on your identity. Granting broad permissions moves the client back into your trust boundary.
- How it could leak
- The Keystore wrapping key is generated WITHOUT setUserAuthenticationRequired() — verified absent from SecureCryptoHelper.kt — so decryption is not gated on biometric or PIN re-auth at the crypto layer. An attacker with an unlocked device, or root/malware running as the app's UID, can drive decryption. (Whether the UI layer adds an app-level biometric/PIN lock was NOT verified in this review; do not assume one.) Because signing is software-side, the plaintext nsec is present in app process memory during every signature, so it is reachable by root, a kernel exploit, or memory-forensic extraction of a live unlocked device. A malicious or backdoored Amber build is the main supply-chain risk — mitigated by GPG-signed releases (key 44F0AAEB77F373747E3D5444885822EED3A26A6D) and F-Droid/Zap.store distribution, but only if you actually verify the signature. A trojaned client cannot read the key but can spam signing prompts to fatigue you into approving a malicious event, or request over-broad permissions up front. Realistic exfiltration path: full device compromise or forensic extraction of an unlocked phone. Critically, any successful exfiltration is permanent — see limitations.
- NIPs implemented
- NIP-55 ("Android Signer Application") as the on-device transport — verified present at nips/55.md and in the NIPs index. Also implements NIP-46 ("Nostr Remote Signing", transport kind 24133) so it can act as its own bunker for desktop/web clients. Signs NIP-01 events and serves the NIP-55 method set: get_public_key, sign_event, nip04_encrypt, nip04_decrypt, nip44_encrypt, nip44_decrypt, decrypt_zap_event. Note for callers: NIP-04 is flagged "unrecommended — deprecated in favor of NIP-17" in the official NIPs index, so nip04_* methods are legacy-compatibility surface, not a recommendation.
- Platforms
- Android only. Not on Google Play — distributed via F-Droid, Zap.store, Obtainium, and GitHub APK releases. No iOS build exists, and NIP-55 is specified around Android Intents and Content Resolvers, so it cannot be ported to iOS as written. iOS users must reach Amber indirectly through its NIP-46 bunker mode, or use a different signer entirely; this is a genuine platform gap, not a packaging detail.
- What it costs you in convenience
- Every signing request raises an approval prompt unless you pre-authorize. NIP-55 defines a permissions array (each entry a method type plus optional event kind) so clients can request blanket pre-approval, which the Content Resolver path then serves in the background with no prompt. That is the real tradeoff and it is a security tradeoff, not just a convenience one: stay strict and you tap approve constantly on a busy client; pre-authorize and you have granted a standing signing right whose use you will never see. Approve-fatigue is real and is the mechanism by which careless users sign malicious events. Desktop and web use requires NIP-46 bunker mode, which adds relay round-trips, latency, and occasional reconnection friction.
- Limitations
- NO KEY ROTATION OR REVOCATION EXISTS — this is a protocol-level limitation, not an Amber one, and it dominates every other caveat. Verified directly: nips/41.md returns HTTP 404, NIP-41 is absent from the repository file listing (the sequence runs 40.md then 42.md), and no NIP for key migration, rotation, revocation, or invalidation appears in the official index. NIP-26 (Delegated Event Signing), the closest adjacent mechanism, is marked "unrecommended" in that same index. Consequence: if your nsec leaks, you cannot rotate, revoke, or invalidate it. The identity is permanently compromised and your only recourse is abandoning it and rebuilding your social graph from a new key. Treat any claim that a nostr key can be rotated as false as of this review. Further limitations: Android-exclusive; effectively a single-maintainer project despite heavy adoption, which is real bus-factor and supply-chain concentration risk; the Keystore key is not gated on user re-authentication at the crypto layer; StrongBox protects only the wrapping key, not signing. NIP-55 does not name Amber — the spec uses a generic com.example.signer placeholder throughout, so Amber is the reference implementation by adoption, not by designation. Backup remains entirely your problem: the README gives no key-backup guidance, and since Keystore-wrapped material is not portable off the device, losing the device without an independently retained nsec or seed is irreversible identity loss.
- Project status
- Actively maintained, verified via GitHub API on 2026-07-20: pushed_at 2026-07-20T12:48:15Z (same day as this review), updated_at 2026-07-20T12:25:58Z, created_at 2023-07-26, 327 stars, 9 open issues, MIT licensed, archived false, disabled false, not a fork. Maintenance signals are genuinely current. Caveat on interpretation: a low open-issue count on a single-maintainer repo reflects one person's triage habits and should not be read as an independent quality or security signal, and 327 stars is modest relative to the project's practical importance in the Android nostr ecosystem.
Use it if: Android-first users who want key isolation from client apps: one app holds the key, every other app must ask. It is the de facto standard signer on Android and a reasonable default recommendation for Android users who will verify release signatures and keep permission grants narrow. It is not a substitute for a hardware signing device, and it does not suit anyone whose threat model includes device seizure, root-level malware, or forensic extraction of an unlocked phone.
FROSTR / Igloo (threshold signing) Threshold signing medium confidence
- Where the private key lives
- Split into n shares under threshold Schnorr signing, k of which must cooperate. The README states: "Threshold Schnorr signing for Nostr using your FROSTR shares (k-of-n). The full private key is never reconstructed." That statement is accurate at SIGNING time but must not be read as "the key never exists whole." Setup is dealer-based: the project's own docs/SECURITY.md states that if the dealer is compromised during setup, "All shares are compromised." The key material therefore exists in one place, on one machine, at generation — that machine is a full-compromise point, and this is the single most under-stated fact about the design. In operation, shares are supplied as GROUP_CRED / SHARE_CRED credentials (bfgroup1.../bfshare1... format) via environment variables in headless mode, or stored server-side in database mode as AES-encrypted credentials. In database mode a share does live on the server, so that host plus its encryption key yields that share. Shares are intended to live on separate devices; keeping them together silently collapses the entire security model.
- Who you must trust
- You trust, per the project's own SECURITY.md: (1) the dealer at setup — dealer compromise during key generation means total compromise, and no threshold protection applies at that moment; (2) that "At least N-M+1 shareholders are honest" — the docs state FROSTR "operates optimistically, assuming trusted group members," so it is not robust against malicious insiders below threshold, only against forgery by them; (3) the system RNG for secure randomness; (4) out-of-band secure channels for initial share distribution; (5) relay availability — at least one relay reachable by all participants, making relays a liveness dependency; (6) roughly synchronized participant clocks. Above threshold the stated guarantee holds: "An adversary must compromise at least M shareholders to forge signatures," and if M or more shareholders are malicious, "Signatures can be forged." You are additionally trusting an unaudited implementation of cryptography considerably more complex than "encrypt a key at rest," and complexity is itself a risk.
- How it could leak
- Steady-state, an attacker must compromise k of n share-holding devices, which is materially harder than compromising one bunker. But the residual risks are larger than the threshold framing suggests. Dealer compromise at setup leaks everything at once, per the project's own docs. No share revocation or share-refresh mechanism is documented in bifrost's README or SECURITY.md, and none could be verified — so a stolen share appears to stay valid indefinitely, and the only certain remedy found is generating a new keyset, which produces a new npub and abandons the identity. In a common 2-of-3 layout, one silently stolen share means the attacker needs just one more, with no documented way to invalidate the one they hold. Further risks: flaws in the unaudited threshold implementation, compromise of the coordinating node's session material, server-side share theft in igloo-server database mode, relay-level metadata exposure, and user error in share distribution.
- NIPs implemented
- Implements NO NIP for its signing transport. The igloo-server README contains no reference to NIP-46, "bunker", nostrconnect, or remote signing; it runs the Bifrost FROSTR protocol. Client-facing access is via NIP-07 ("window.nostr capability for web browsers") through igloo-chrome and frost2x. Do not file this under NIP-46 ("Nostr Remote Signing"). Verified NIP titles for contrast in any comparison table: NIP-07 window.nostr for web browsers; NIP-46 Nostr Remote Signing; NIP-49 Private Key Encryption (ncryptsec); NIP-55 Android Signer Application. Note also that NIP-41 (often cited as Nostr "key migration") is NOT a merged NIP — it is absent from the nostr-protocol/nips index, which jumps 40 to 42, and 41.md returns HTTP 404. There is no standardized Nostr key rotation or revocation mechanism to point at.
- Platforms
- Self-hosted server (igloo-server, MIT, Bun runtime required — uses Bun APIs such as bun:sqlite), a PWA (igloo-pwa), CLI (igloo-shell), and Chrome NIP-07 extensions (igloo-chrome, MIT; frost2x, a fork of fiatjaf/nos2x). Desktop is mid-transition: igloo-desktop last received a code push 2026-02-05 and appears superseded by igloo-home, described as "Run a desktop signing device on the FROSTR V2 protocol." iOS should NOT be presented as solved: igloo-ios exists and is MIT-licensed, but it was created 2026-01-07, has had no code push since 2026-03-28, carries 1 star and 0 forks, and no App Store release could be verified. Treat it as an early prototype, not a working answer to the iOS signer gap.
- What it costs you in convenience
- The steepest learning curve of any option here. You must understand dealer-based share generation, threshold selection, and share custody across multiple physical devices, and you must keep enough shares online to reach k every time you want to sign — so signing has a liveness requirement that a local key or a single bunker does not. Relay reachability and rough clock sync are operational dependencies. Recovering from a lost or stolen share is not a documented push-button operation. This demands more of the user than a hardware wallet does, and more ongoing operational attention.
- Limitations
- Does not solve the un-rotatable-key problem, despite the FROSTR org describing itself as a "FROST-based multi-signature and key rotation protocol." No implemented share-rotation or revocation mechanism could be verified in bifrost's README or SECURITY.md, and even a working FROST share refresh would rotate shares while preserving the same group public key — your npub still cannot be rotated, migrated, or revoked, and no NIP provides that (NIP-41 is unmerged and returns 404). Not NIP-46, so it does not interoperate with the standard bunker ecosystem; compatibility runs through its own extensions and nodes, and client support is far narrower. No third-party audit found. Adoption is very small (igloo-server 8 stars, bifrost 12). Licensing is NOT uniformly MIT: igloo-server, igloo-chrome, igloo-ios, igloo-ui, igloo-paper, igloo-web and bifrost are MIT, but frost2x, igloo-pwa, igloo-shell, igloo-home, igloo-shared, bifrost-rs and frostr-infra showed no license, which defaults to all-rights-reserved. Bun runtime is a hard dependency for the server. One verification gap, stated plainly: the FROSTR org self-describes as a key-rotation protocol, and this review could not conclusively confirm or refute an undocumented share-refresh implementation in code — web search budget was exhausted before that could be closed. The row therefore reports only what the project's own written docs support, and confidence is held at medium for that reason.
- Project status
- Actively developed but early, and currently split across a V1-to-V2 migration — adopting it today means picking a side of that migration. The FROSTR org (29 public repos, created 2024-10-18) made a coordinated push on 2026-07-05 across V2-era components: frostr-infra, igloo-pwa, igloo-shared, igloo-home, igloo-chrome, igloo-ui, igloo-paper, bifrost-rs. Meanwhile the components a user would actually deploy today are quiet: igloo-server last pushed 2026-05-28, bifrost (the core library) 2026-02-16, igloo-desktop 2026-02-05, igloo-ios 2026-03-28, and frost2x 2025-12-18 (roughly seven months). Nothing is archived. Describe this as experimental and in active redesign — not as a settled, production-ready alternative to Amber or a plain NIP-46 bunker.
Use it if: Experimenters and expert operators with a high-value Nostr identity who already think in multisig terms, can run their own infrastructure, and can accept unaudited cryptography mid-way through a protocol version migration. The useful mental model is 2-of-3 Bitcoin multisig applied to a Nostr key — with the honest caveat that it hardens the key against single-device theft rather than making the identity rotatable. Not appropriate as a general recommendation for a mainstream reader; for most people a maintained NIP-46 bunker or a NIP-55 Android signer is the correct choice.
Amber in bunker mode (NIP-46) Remote signer (NIP-46) medium confidence
- Where the private key lives
- The nsec is stored on your own Android device in Amber's app-private storage, isolated in a single dedicated app, protected by the Android app sandbox, device disk encryption, and Amber's own unlock. No server or third-party service holds a copy. Caveat on "and nowhere else": that is only true if you have made no backup — and if you have made no backup, the identity is unrecoverable on device loss, so in practice a copy exists somewhere and that copy's storage is part of your real attack surface. UNVERIFIED: I could not confirm from primary sources whether the key at rest is wrapped by the Android Keystore / hardware-backed secure element or protected only by app-private storage plus an app passphrase. Do not assume hardware-backed key storage.
- Who you must trust
- You trust the Amber app and its maintainer, your Android device and OS, the build you installed, and the distribution/signing channel (releases are GPG-signed; key fingerprint 44F0 AAEB 77F3 7374 7E3D 5444 8858 22EE D3A2 6A6D). Correcting a common overstatement: it is NOT true that "no third party is in the signing path." Relays are in the path as transport — they cannot read your key or plaintext payloads (NIP-44 encrypted) but they do see the client and signer pubkeys, timing, and traffic volume, and they are a liveness dependency that can stall or censor signing. Authorized clients are also part of the trust model: once you grant a client a NIP-46 session — especially with "remember my choice" — that client can obtain signatures within its granted scope without further prompting. Such a client can never extract the key, but a malicious or compromised one can get arbitrary events signed under your identity for as long as the grant stands.
- How it could leak
- Key extraction: physical device theft or compromise; Android malware with sufficient privilege; a rooted device, unlocked bootloader, or ADB/backup extraction path; a malicious build installed from an unofficial source (install only from F-Droid, Zap Store, Obtainium, or GitHub releases, and verify the GPG signature); and clipboard exposure at the moment you import an existing nsec. Signature abuse without key extraction — the risk most often understated: XSS in an authorized web client, or a malicious local Android app holding a remembered NIP-55 permission, cannot steal the nsec but can drive the signer to sign attacker-chosen events under your identity. Because Nostr has no deployed revocation (see limitations), events signed during such a window cannot be repudiated. Genuinely not applicable: hosted-operator compromise and server breach, since no third-party bunker host holds the key.
- NIPs implemented
- NIP-46 "Nostr Remote Signing" (verified against nostr-protocol/nips/master/46.md) and NIP-55 "Android Signer Application" (verified against 55.md). This row concerns the NIP-46 role. Correction to a common description: NIP-55 is not intents-only — it specifies three transports (Intents, Content Resolver, and a Web method). NIP-46 request/response payloads are encrypted with NIP-44. Amber's README states the goal verbatim: "The goal of Amber is to have your smartphone act as a NIP-46 signing device without any need for servers or additional hardware."
- Platforms
- Android only. Distribution: F-Droid (latest listed 6.2.3, published 2026-07-03), Zap Store, Obtainium, and GPG-signed GitHub releases; not on Google Play. In NIP-46 mode it signs for desktop browsers and web clients over relays, so an Android user can sign for a desktop client without any browser extension. There is no iOS version and the project documents no iOS path. This is the largest platform gap in Nostr key management and is a major reason iOS users fall back to pasting keys into apps or trusting a hosted bunker.
- What it costs you in convenience
- Your phone must be present, unlocked, awake, and network-reachable to sign for a desktop session, and every request round-trips through a relay, so desktop signing is slower and can stall on poor connectivity, a sleeping phone, or aggressive OEM battery/background restrictions. Amber supports remembering per-app permissions, so it is not approve-every-event by default — but note that this convenience is itself a security downgrade: a remembered grant is a standing signing authorization. If you instead enable per-event approval for a chatty client, notification fatigue is real and is exactly how users get trained to approve blindly. Either setting has a cost; there is no free configuration.
- Limitations
- No key rotation, migration, or revocation exists in deployed Nostr — verified: there is no NIP-41 file in the NIPs repository (404), the NIPs index lists no key-migration/rotation/revocation NIP, and the proposals remain unmerged open pull requests (nostr-protocol/nips #1452 "Key Migration and Revocation", opened 2024-08-28; #2137 "Key migration" and #2139 "Simpler key migration", both opened 2025-11-25/26). Consequence: if your nsec leaks, you cannot revoke or rotate it. You can only abandon the identity and rebuild your follower graph from scratch, and the attacker retains the ability to sign as you indefinitely. This applies to every signer in this comparison, not just Amber, but it is what makes device compromise here unrecoverable rather than merely bad. Additionally: Android exclusive with no iOS path; the phone is a single point of failure — lose it with no backup and the identity is gone permanently; desktop signing requires the phone reachable and awake; relay availability gates NIP-46 responsiveness. No published independent security audit of Amber was located during this review.
- Project status
- Actively maintained, verified via the GitHub API on 2026-07-20: last push 2026-07-20, 327 stars, 9 open issues, not archived or disabled, created 2023-07-26. Licensed MIT — confirmed by the LICENSE file, the API, and F-Droid; note the README's shields.io badge incorrectly displays "Apache-2.0", a stale badge rather than a real license conflict. The same maintainer also actively ships Citrine, a phone-local Nostr relay that pairs with it (126 stars, 16 open issues, MIT, last push 2026-07-20, not archived). Tempering a comparative claim: the project is healthy and current, but 327 stars and a single primary maintainer make it a small project, and bus-factor risk should be read as real rather than dismissed.
Use it if: Android users who want their key out of every client app without renting or running infrastructure — a reasonable default recommendation for that group. Caveat on a popular analogy: it is not equivalent to a hardware wallet. A hardware wallet is a dedicated, minimal-attack-surface device with a secure element and an out-of-band confirmation screen; Amber is an app on a general-purpose, internet-connected phone running arbitrary other software. It is a large improvement over pasting your nsec into clients, not a substitute for dedicated signing hardware.
Keycast (team bunker) Remote signer (NIP-46) medium confidence
- Where the private key lives
- On infrastructure your organization controls: private keys sit in a SQLite database, encrypted at rest. Both the stored user keys and the per-authorization bunker keys are encrypted with a single root `master.key` file generated by `bun run key:generate` and held on the host — file-based key management via the project's `FileKeyManager`, not an external KMS or HSM. Since the May 2026 audit the file is no longer baked into container images and is mounted read-only at runtime, but it remains a plaintext file on the host filesystem. That one file plus the database is the crown jewel: together they yield every key in the system. The signer must also hold decrypted keys in process memory to sign, so they exist unencrypted at runtime.
- Who you must trust
- Every member trusts the organization's operator and its infrastructure, not just themselves — a fundamentally broader trust surface than a personal bunker. It is designed so several people can post as one shared identity under policy controls, which necessarily means an admin can grant, revoke and observe signing authority. State this more strongly than "the admin manages permissions": anyone holding `master.key` and the database can decrypt the underlying private keys outright and copy them, permanently and undetectably. A member is not merely trusting that policy will be enforced at signing time; they are accepting that the operator has recoverable custody of the key itself. Appropriate for a brand or project account. Not a substitute for personal self-custody, and a key you hand to Keycast should be treated as a key the operator has.
- How it could leak
- Host compromise yields the SQLite database and the `master.key` beside it, and those together expose every stored key at once — one breach is a total, multi-identity loss, not a single-key loss. Decrypted keys are additionally exposed in signer process memory. Insider risk from any admin, with no cryptographic check on an operator who simply reads the file. Route-level authorization or policy-validation weaknesses are a live concern rather than a theoretical one: the project's own May 2026 audit found and fixed real defects in this class, including a signer that did not default-deny when a policy lacked custom permissions, acceptance of empty policies, panics on invalid permission configs, and NIP-98 verification that did not bind the signed payload tag to exact request bytes. Residual risks the audit leaves open include reliance on the reverse proxy to supply correct `Host` and `x-forwarded-proto` headers for NIP-98 URL validation. Because Nostr has no deployed key-revocation mechanism, any such exfiltration is permanent for that identity.
- NIPs implemented
- NIP-46 (Nostr Remote Signing) for the bunker connection strings and signer daemons, and NIP-98 (HTTP Auth) for authenticating API requests with signed events. It documents interop with clients using NIP-07 (`window.nostr` capability for web browsers) and NIP-55 (Android Signer Application). All four numbers and titles verified against the nostr-protocol/nips repository.
- Platforms
- Self-hosted via Docker Compose (containerized API, web and signer components) with prebuilt images from GitHub Container Registry; hardened in the audit with digest-pinned bases, read-only root filesystems and non-root UID/GID 10001. Client-side it serves any NIP-46 capable client on any platform, and documents NIP-07 and NIP-55 (Amber) paths. It is server software, not a personal mobile product — there is no iOS or Android Keycast app, and mobile users reach it through a NIP-46 capable client.
- What it costs you in convenience
- Substantial operational and governance overhead: you are running production infrastructure and administering teams, roles and per-key policies, plus backing up `master.key` and the database together — the audit is explicit that recovery requires both, so a backup of one alone is worthless. For the end user on the team, signing is transparent and low-friction once authorized, which is the point. The cost is borne by the operator, not the member.
- Limitations
- Self-described as early-stage; its own documentation says it should get a deployment review "before it is trusted with real team keys on the public internet," and points readers to residual notes in AUDIT.md. Take that at face value. Small project (28 stars, 3 open issues). File-based `master.key` rather than HSM/KMS backing is a real architectural ceiling for high-value organizational identities. Critically, "revocable" here means revoking a bunker authorization, never revoking the key: there is no merged Nostr key-rotation or revocation specification — NIP-41 does not exist in the nostr-protocol/nips repository, where the sequence skips from 40.md to 42.md — so if the underlying nsec leaks, the identity is compromised permanently and every follower must be migrated by social convention. Revoking a member's authorization also does not help if that member ever obtained the raw key by other means. The project moved orgs (erskingardner → marmot-protocol), so older links redirect.
- Project status
- Maintained but immature, and quieter than "actively maintained" implies. The repository is not archived or disabled, is MIT licensed, and passed a security audit dated 2026-05-14 that fixed real auth, permission, data-integrity and dependency defects — more security diligence than most projects in this category. However the last push was 2026-05-18, roughly two months before this review with no activity since, and the maintainers still explicitly withhold a production-ready endorsement. Treat it as a viable but young project whose maintenance trajectory should be re-checked before adoption rather than one under continuous active development.
Use it if: An organization that needs several people to post as one shared brand identity with auditable, administrator-revocable signing authorizations — a company account, a project account, a newsroom. Explicitly not for individuals: its own README contrasts it with individual remote-signing workflows like nsec.app, Knox and Amber. Given its early-stage self-assessment, best suited to a team that can perform its own deployment review and accepts operator custody of the key.
Signet (self-hosted bunker) Remote signer (NIP-46) medium confidence
- Where the private key lives
- On hardware you own, encrypted at rest on that machine with NIP-49 or the legacy AES-256-GCM mode. No third party ever holds the key material, and the key is never transmitted to a connecting client — NIP-46 returns only signatures. Critically, the key does not stay encrypted during use: you enter the passphrase at daemon start to decrypt it, and the project's own SECURITY.md states that "if the server running Signet is compromised, an attacker could potentially extract decrypted keys from memory while they are unlocked." Keys are cleared from memory only when locked. So the accurate statement is: encrypted on disk, plaintext in RAM whenever the signer is live.
- Who you must trust
- You trust yourself, your host's operational security, and an unaudited independent implementation. It is not correct to say there is no third party in the path: NIP-46 sessions are carried over Nostr relays, so a relay operator is an availability dependency and a metadata observer (connection timing, session activity, client and signer pubkeys) even though payloads are NIP-44 encrypted. Separately, any app you have authorized can request signatures. Signet's docs describe permissions requested in a nostrconnect:// URI as "informational only" and reference "policy-based auto-approval" without documenting its enforcement, so a hostile or compromised authorized client should be assumed capable of getting arbitrary events signed under your identity even though it can never obtain the key. There is no third-party security audit of the crypto implementation.
- How it could leak
- Dominant risk is compromise of the host: root on that box yields the decrypted key straight out of process memory while the daemon is unlocked (stated in the project's own SECURITY.md), not merely the encrypted keystore. Secondary risks: exposing the admin dashboard or API to the internet — the documented default `authHost` is 0.0.0.0, which binds all interfaces, so network isolation is on you; a weak passphrase on the NIP-49 keystore; leaked keystore backups; and compromise of the admin npub used for DM-based control. Not exposed to a hosted-service operator, browser XSS, or key theft by a malicious client. But a malicious client is not a null risk: it cannot steal the key and can still obtain signatures under your identity for as long as its authorization stands.
- NIPs implemented
- NIP-46 (Nostr Remote Signing) is the primary protocol — verified present as 46.md in the NIPs repo. NIP-46 carries its session traffic as kind 24133 events encrypted with NIP-44 and relayed through Nostr relays. Keys are encrypted at rest with NIP-49 (Private Key Encryption / ncryptsec, verified as 49.md) using XChaCha20-Poly1305 with scrypt, or a legacy AES-256-GCM mode with PBKDF2 at 600,000 iterations. Optional admin control via DM uses NIP-04 or NIP-17; NIP-04 (Encrypted Direct Message) is explicitly marked unrecommended/deprecated in the NIPs README in favor of NIP-17 (Private Direct Messages), so prefer NIP-17 for admin channels. The Android companion is a management app for the bunker; it is not verified to implement NIP-55 (Android Signer Application) and should not be assumed to.
- Platforms
- Self-hosted daemon on any machine you control (home server, VPS, Umbrel-class box); Docker deployment documented. Port numbers are inconsistent across the project's own docs — the README cites a web dashboard on 4174 while CONFIGURATION.md documents `authPort` defaulting to 3000 — so confirm the binding for your build rather than trusting either figure. A companion Android app is distributed via ZapStore. A Chrome/Firefox approval extension is in development in-repo with store releases only planned, not shipped. There is no iOS companion or admin app; however, because NIP-46 is transport-agnostic, any NIP-46-capable iOS client can still connect to a Signet bunker via a bunker:// URI. "No iOS support" would overstate the gap — the gap is management tooling, not signing.
- What it costs you in convenience
- The highest setup cost of any option here: you provision, secure, patch, and keep a machine running, and if it is down you cannot sign at all. The README is emphatic — "DO NOT run the daemon on a public machine. We recommend private network access only," with Tailscale the documented approach, so budget for running a private network overlay as well. Day-to-day signing is smoother than per-event approval extensions, but the exact approval behavior is under-documented: the docs reference policy-based auto-approval and a UI for approving signing requests without specifying which events bypass prompting. Assume less granular per-app control than the summary implies until you have read the config yourself. An optional Inactivity Lock (dead-man's switch) auto-locks all keys and suspends apps if not reset within a configured window.
- Limitations
- No key rotation, revocation, or migration — this is a protocol-level gap, not a Signet gap, and it is the most important caveat on this row. There is no merged NIP for key migration or revocation: 41.md does not exist in the nostr-protocol/nips repository and NIP-41 is absent from the NIPs index. If your nsec leaks there is no mechanism to invalidate it; the identity and its social graph are permanently compromised. Signet's kill switch and Inactivity Lock only lock the local keystore and suspend connected apps — local access control, not cryptographic revocation — and they do nothing about a key an attacker already copied. Losing the host without a backup loses the identity permanently, with no seed-based recovery. Beyond that: small young project (created 2025-10-24, 27 stars, 8 forks, effectively one maintainer), no third-party audit found, browser extension unreleased, no iOS management app, and internally inconsistent port documentation.
- Project status
- Actively maintained as of this research. Last push 2026-06-29, roughly three weeks prior; MIT licensed; not archived or disabled; 2 open issues; ongoing feature work on a browser extension and Android app. Caveat on maturity rather than activity: the repo was created 2025-10-24, so it is under a year old, is effectively a single-maintainer project, and has no published third-party security audit. Avoid ranking it as the single healthiest self-hosted NIP-46 option — that comparison was not verified against the field, and the upstream nsecbunkerd it forked from is itself still active (last push 2026-06-02, 144 stars, not archived).
Use it if: Someone who already runs a home server or Tailnet, is comfortable owning uptime and patching, and treats their Nostr identity the way they treat a hardware wallet. Also the practical answer for an always-on signer driving bots, automation, or scheduled posting without handing a key to a third party. Overkill and probably counterproductive for a casual user who just wants to post from a web client — a self-hosted box run badly is weaker than a well-run signer app.
nsec.app (hosted bunker) Remote signer (NIP-46) medium confidence
- Where the private key lives
- In your browser's IndexedDB (via Dexie), under the nsec.app web origin, on your device — not in plaintext on the operator's server. A NIP-46 signer runs inside a service worker and holds the decrypted key in memory while unlocked. The key is encrypted at rest with a user-defined password through a key-derivation function. Optional "cloud e2ee sync" uploads the key to the noauthd server in encrypted form only, so the server is designed to store ciphertext it cannot open. Two caveats that are usually dropped: the encryption and decryption are performed by JavaScript the operator serves on every page load, so "the key is on your device" does not mean "the operator cannot reach it"; and the encryption scheme has no published audit, so its resistance to offline attack is asserted by the authors, not independently verified.
- Who you must trust
- You trust the web origin on every single page load — this is the real threat, and it is categorically different from trusting a server that merely holds a key. Because the signer is JavaScript delivered by nsec.app, the operator, or anyone who compromises the domain, its hosting, its CDN, its TLS, or its build pipeline, can serve modified JS that captures your password and exfiltrates the decrypted key at the next unlock. Client-side encryption defends against a passive server breach; it does not defend against a malicious or compromised server, because the server ships the code that performs the decryption. There is no subresource pinning a user can rely on and no reproducible-build or signed-release process to check what you were served against what is in the repo. You additionally trust: that your password is strong, since anyone obtaining the e2ee cloud blob can brute-force it offline at leisure; the noauthd push server for availability and for the connection metadata it necessarily sees; and the relays carrying kind-24133 traffic for timing and metadata, though contents are encrypted. Finally, and decisively — trust here is one-way and permanent. See exfiltration_risk: there is no recovery path from a compromise.
- How it could leak
- Primary: malicious or compromised JS served by the origin — hostile operator, domain or DNS takeover, CDN or supply-chain compromise, dependency compromise — capturing the password at unlock time and shipping out the decrypted nsec. Secondary: offline brute force of the e2ee cloud blob if the server is breached and the password is weak, against an unaudited KDF of unverified parameters. Also: XSS in the app; a malicious browser extension reading the page or its storage; and importing an existing nsec, which means typing or pasting a private key into a web page — structurally the same exposure as any web key entry even though the app is designed not to transmit it, so prefer generating a fresh key in the app to importing a valuable one. The consequence is the part most references get wrong: a leaked nsec is unrecoverable. There is no merged NIP for key rotation, migration or revocation — NIP-41 is not present in the NIPs repository at all (41.md returns 404 and the index does not list it), and NIP-26 delegated event signing, the nearest relative, is flagged in the index as "unrecommended: adds unnecessary burden for little gain". Once your key leaks, the attacker is permanently, indistinguishably you; the only remedy is abandoning the identity and rebuilding your social graph from zero.
- NIPs implemented
- NIP-46 "Nostr Remote Signing" — verified against the NIPs repo: event kind 24133, served over bunker:// and nostrconnect:// URIs. The merged spec defines connect, sign_event, ping, get_public_key, nip04_encrypt/nip04_decrypt, nip44_encrypt/nip44_decrypt, switch_relays and logout; nsec.app exposes the core signing and encryption subset. It does NOT implement NIP-07 — it substitutes for one, letting web clients reach a signer without a browser extension. Its at-rest password encryption is NOT verified to be NIP-49 (ncryptsec, scrypt + XChaCha20-Poly1305); the README describes only "a good key derivation function" without naming a standard, and the pinned nostr-tools ^1.17.0 predates that library's NIP-49 support, so treat the at-rest format as a custom, unaudited scheme rather than a standardized one.
- Platforms
- Any modern browser, desktop or mobile, and it works with any web client supporting NIP-46. Desktop browser is where it is strongest. Cross-device reliability is a known weak spot the authors call out directly: "if your phone is locked then service worker might not wake up." The noauthd server sends a web push to wake the service worker, so signing availability depends on push infrastructure staying up — which is a live concern given the server component's maintenance state. On iOS this is structurally worse than on Android: Safari's service-worker eviction is aggressive and web push requires the site be installed to the home screen as a PWA, so a mobile-iOS-only setup is the least reliable configuration. We did not bench iOS behavior directly, so treat that as platform-general reasoning rather than a measured nsec.app result. iOS users wanting a dependable signer have no equivalent of Android's NIP-55 signer apps; that gap is real and nsec.app only partly fills it.
- What it costs you in convenience
- Low friction, and this is its genuine selling point — it is the easiest way to consume NIP-46 from web clients. You approve connections per app and can grant standing permissions, so it is not approve-every-event fatigue by default. What you give up: a password you must remember, since losing it with no cloud backup loses the key permanently; dependence on the service worker being awake, so signing can hang or fail outright rather than fail loudly; and an extra relay round trip on every signature, making signing perceptibly slower than a local NIP-07 extension or a NIP-55 Android signer. The convenience is real and it is purchased with the origin-trust exposure described above — that is the actual trade, not a footnote to it.
- Limitations
- Maintenance is now as much the concern as the design. Verified 2026-07-20 against the GitHub API: the noauth app repo's last push is 2025-05-26 (~14 months stale) with 46 open issues and NO license declared in its metadata, which leaves reuse and forking legally ambiguous; the separate noauthd server repo was last pushed 2025-01-08 (~18 months) with 2 open issues and is MIT-licensed. Neither repo is archived, so this is drift rather than a declared end of life. Dependency rot is visible in the manifest: nostr-tools is pinned at ^1.17.0, a full major version behind, on a codebase whose only real defense is the integrity of the code it ships. Availability is now degraded, not merely uncertain: the app host https://use.nsec.app/ serves (HTTP 200, JS-rendered shell) while the apex https://nsec.app/ actively refused the TLS connection (ECONNREFUSED on 443) after earlier attempts timed out — so the apex is not serving HTTPS, though whether that is intentional, an outage, or a routing artifact is unconfirmed. No published security audit, no written threat model, no reproducible builds or signed releases, and no way for a user to verify the JS they receive matches the public source. And the ceiling on all of it: no key rotation or revocation exists anywhere in Nostr today, so this signer cannot offer a recovery story no matter how well it is run.
- Project status
- Live but unmaintained, and the combination is the problem. The service still answers at use.nsec.app, but active development appears stopped — ~14 months since the last app commit, ~18 months on the server component — and the apex domain is currently refusing HTTPS connections. Neither repo is archived and no deprecation notice has been published, so it is drifting rather than formally dead. For a web app whose entire security rests on the integrity of the code it ships on every load, unmaintained-but-still-serving is an actively deteriorating position, not a neutral one: unpatched dependencies, an unattended deployment, and a lapsing domain footprint are precisely the preconditions for a JS supply-chain compromise. Do not present this as a current, healthy recommendation alongside actively maintained signers.
Use it if: Someone who needs a working Nostr identity across web clients on desktop today, has no Android device (where a NIP-55 signer such as Amber keeps the key off the web origin entirely and is the stronger choice), and is carrying a low-value or experimental identity they could afford to lose outright. Sound for generating a fresh throwaway or test key. Given both the origin-trust model and the maintenance state below, it is a poor place to keep an established identity with real reputation, followers or zap history attached — because there is no rotation path, that is a bet you only get to lose once.
AKA Profiles (Chrome) Browser extension (NIP-07) high confidence
- Where the private key lives
- VERIFIED FROM SOURCE — plaintext, unencrypted, on disk. `src/common/common.js` writes keys with `browser.storage.local.set({keys: keys})` and reads them back with `getPrivateKey(pubkey)` returning `key.private_key` directly. There is no `crypto.subtle`, no AES, no password/passphrase derivation, and no NIP-49 `ncryptsec` handling anywhere in the storage path; `src/common/storage.ts` passes `private_key: keypair.private_key` through untransformed, and `src/background/background.js` uses the raw `sk` directly in `finalizeEvent()`, `schnorr.sign()` and `nip04.encrypt()`. Net effect: every nsec you load sits in cleartext in the Chrome profile's extension storage, readable by anything that can read that directory. There is no unlock step — the keys are not protected by anything except your OS file permissions.
- Who you must trust
- You trust, in order: (1) your OS user account and disk — this is the load-bearing one, because the keys are plaintext and there is no passphrase gate, so file-read access equals total key compromise; (2) the publisher's Chrome Web Store account and its silent auto-update channel — the listing is published by Metarep Labs Inc. (Vancouver, BC), not by an anonymous individual, so a compromised or coerced company account can push signing code straight onto your machine; (3) the extension's own content script, which is injected at `<all_urls>`, so its code runs on every page you visit; (4) every web app you approve, since NIP-07 approval grants ongoing signing capability to that origin. The multi-key design concentrates risk: one read of one storage blob yields every identity you have loaded, which inverts the entire purpose of maintaining separate npubs for separate personas. There is no license on the repository, so you have no granted right to fork, audit-and-redistribute, or maintain it — "audit it yourself" is not a legally clean fallback here.
- How it could leak
- High and low-effort, because the keys are cleartext at rest. Concretely: any commodity infostealer or any process running as your user reads the extension storage directly with no password to defeat; any full-disk or profile-directory backup, cloud sync, or disk image silently copies every nsec; forensic recovery of a discarded or resold drive yields them; another malicious extension with broad permissions, or OS-level malware, reads them the same way. Supply chain: a malicious or compromised Web Store update auto-installs and can exfiltrate all stored keys in one push — and since the project is dormant, a hijacked publisher account might not be noticed quickly by the maintainer. The `<all_urls>` content script widens the surface, and XSS in an approved web app can request signatures without touching storage at all. Blast radius is all-personas-at-once. CRITICAL: a leaked Nostr secret key cannot be undone — see limitations.
- NIPs implemented
- NIP-07 ("`window.nostr` capability for web browsers") — verified against nostr-protocol/nips/07.md. It implements the two required methods (`getPublicKey`, `signEvent`) plus the optional `nip04.encrypt/decrypt` (NIP-04 is marked deprecated in NIP-07) and `nip44.encrypt/decrypt`. It also exposes non-standard surface beyond NIP-07: `signString()`, `getRelays()`, an `accountChanged` event for identity switching, and a `nip60.signSecret()` hook (NIP-60 = Cashu Wallets, status `draft` `optional`). It does NOT implement NIP-46 (Nostr Remote Signing) or NIP-49 (Private Key Encryption / `ncryptsec`). NIP-26 (Delegated Event Signing) is NOT supported — the repo Readme records "removed support for signing delegation" in v1.05, even though the Chrome Web Store description still advertises NIP-26. Trust the code, not the listing. (NIP-26 is in any case marked `draft` `unrecommended` upstream.)
- Platforms
- Chrome desktop only, distributed via the Chrome Web Store (listing live, v1.0.9, last updated 2025-04-01, ~356 users, publisher Metarep Labs Inc.). Manifest V3. Chromium-family browsers that install Web Store extensions (Edge, Brave) will likely run it but are not officially supported or tested. No Firefox listing (the code calls the `browser.*` namespace but is packaged Chrome-only). No Android, no iOS, no mobile path of any kind.
- What it costs you in convenience
- Very low friction, and that is precisely the security trade. One-click approvals plus genuine one-click identity switching via the `accountChanged` event, with per-app permission management and a recent-apps list. There is no master password and no unlock prompt at any point, so nothing stands between an attacker with file access and your keys — the convenience and the exposure are the same design decision. You do get the ordinary NIP-07 benefit of not pasting your nsec into individual web clients.
- Limitations
- Keys are stored unencrypted with no passphrase (verified in source) — the single biggest limitation. No license file and `license: null` via the GitHub API, so forking, auditing-and-redistributing, or adopting the project is legally murky. Small project: 34 stars, 5 forks, 2 open issues. Chrome-only. No NIP-46 and no NIP-49, so there is no remote-signing or encrypted-key-export escape hatch. Documentation gap: the Web Store listing still claims NIP-26 support that the code removed in v1.05, and the repo manifest reads 1.0.10 while the published build is 1.0.9 — listing and code are out of sync. Reviewed from repository source; the shipped Web Store bundle was not independently disassembled, so store-build/repo divergence cannot be ruled out. PROTOCOL-LEVEL, NOT THE EXTENSION'S FAULT BUT DECISIVE HERE: a compromised Nostr secret key cannot be rotated, migrated, or revoked. There is no merged NIP for key migration or revocation — no 41.md exists in nostr-protocol/nips, and the proposals (PR #1452 "Key Migration and Revocation", #2137 "Key migration", #2139 "Simpler key migration") are all still open and unmerged. NIP-26 delegation, sometimes cited as a workaround, is marked `draft` `unrecommended` upstream and is not implemented here anyway. Theft of an nsec is permanent loss of that identity.
- Project status
- Dormant, and should be treated as unmaintained rather than as a current option. Last code push `pushed_at` 2025-05-17T17:37:58Z — about 14 months stale as of 2026-07-20 — and the published Web Store build has not moved since 2025-04-01 (v1.0.9), despite a 1.0.10 sitting in the repo. Not archived, not disabled, only 2 open issues, and the store listing is still live and installable, so it is not visibly broken. But it has shipped nothing through a period in which NIP-46 remote signing and NIP-49 encrypted key storage became the baseline expectation, and it has not addressed plaintext at-rest storage. Do not present this as a maintained signer.
Use it if: A narrow niche: people who run several throwaway or low-stakes Nostr identities on Chrome and want fast switching without juggling browser profiles. Given verified plaintext storage, use it only for personas you would be willing to abandon publicly tomorrow. Do not put a primary identity, a reputation-bearing npub, a key tied to funds, or anything zap/Cashu-adjacent in it — the `nip60.signSecret()` surface means it can touch ecash material, which does not belong behind unencrypted at-rest storage. Anyone wanting real key isolation should use an Android signer (NIP-55) or a remote signer (NIP-46) instead.
Alby Browser Extension Browser extension (NIP-07) medium confidence
- Where the private key lives
- Plaintext-capable on your machine, in browser extension storage, encrypted at rest only by an application-level field encryption. Verified in `setPrivateKey.ts`: `account.nostrPrivateKey = encryptData(privateKey, password)`, persisted via `state.getState().saveToStorage()`. Verified in `getPrivateKey.ts`: `decryptData(account.nostrPrivateKey, password)` with the password from `state.getState().password()`. The cipher is crypto-js in passphrase mode — `src/common/lib/crypto.ts` calls `AES.encrypt(JSON.stringify(data), password).toString()` with the raw password string and no explicit KDF in Alby's code. Two things this means, precisely: (1) crypto-js is not doing "no KDF" — passphrase mode silently derives the key via OpenSSL `EVP_BytesToKey`, verified in crypto-js `cipher-core.js`/`evpkdf.js` as EvpKDF with default hasher MD5 and `iterations: 1` plus a random 8-byte salt. So it is a weak legacy KDF, not an absent one. (2) Only this field is encrypted; the surrounding extension storage is ordinary unencrypted browser storage. Alby's own code also tracks a `hasImportedNostrKey` flag distinguishing an imported nsec from one derived from the account mnemonic, so on some accounts the Nostr key is recoverable from the wallet seed rather than being an independent secret. UNVERIFIED AND MATERIAL: Alby's public documentation does not state whether any copy of the key or encrypted blob is synced to Alby servers, and querying their docs endpoint returned that the docs do not explicitly describe where the Nostr key is stored or whether it is backed up to Alby servers. Treat server-side backup as unknown, not as ruled out.
- Who you must trust
- Wider than a pure signer. You trust: the Alby extension codebase (which can read the plaintext key — a `getPrivateKey` action exists and the key is exportable through the UI, so there is no hardware-style "signs but never reveals" boundary); Alby's auto-update channel and their web-store publishing accounts, since an auto-updating extension can silently ship new code to an already-installed instance; the Chrome/Firefox extension sandbox and the browser vendor's store review; and Alby's dependency chain, including crypto-js, which has had no release since August 2024. Also trust your own OS, since the encrypted blob and the in-memory unlocked key sit on a general-purpose machine. Separate the two Alby products cleanly: the Nostr key here is self-custodial and local, while Alby's legacy custodial Lightning account is a distinct offering (still operational but de-emphasized in favor of the self-custodial Alby Hub). Custodial-wallet reputation should transfer neither to nor away from the Nostr key handling.
- How it could leak
- High relative to a dedicated or hardware signer. The key sits inside a browser on a general-purpose machine — the most attacked surface a normal user has — and is exportable in plaintext by design. Realistic paths: (1) malware or an infostealer reading extension storage and brute-forcing the password offline, which is cheap here because crypto-js passphrase mode derives the AES key with OpenSSL EVP_BytesToKey using MD5 at a single iteration (verified in crypto-js source); the random salt defeats rainbow tables but not GPU brute force, so a stolen blob is orders of magnitude weaker than a NIP-49 `ncryptsec` at scrypt log_n 16+. (2) Anyone with brief physical or remote access to an already-unlocked browser session can simply export the nsec through the extension UI — no password re-entry barrier assumed. (3) Another installed extension with broad permissions. (4) A malicious or compromised Alby update, or a compromised developer/web-store account. (5) While unlocked, the password is in memory and the key is decryptable. One genuine mitigation, stated precisely: a website cannot read the key through NIP-07 — XSS on a site can only ask the extension to SIGN arbitrary events (itself serious: unlimited impersonation while connected), not to export the key.
- NIPs implemented
- NIP-07 ("`window.nostr` capability for web browsers") — verified against nips/07.md. Implements both required methods (`getPublicKey`, `signEvent`) and both optional encryption pairs (`nip04.encrypt`/`decrypt`, `nip44.encrypt`/`decrypt`); source files `nip44EncryptOrPrompt.ts` and `nip44DecryptOrPrompt.ts` confirm NIP-44 support. Note NIP-04 is marked deprecated in the spec itself. Alby also exposes `signSchnorr` and `hashAndSignSchnorr`, which are NOT part of NIP-07 — vendor extensions, so do not rely on them being portable to other signers. Current NIP-07 does not define `getRelays`, and Alby does not expose it. Alby separately implements NIP-47 (Nostr Wallet Connect) for Lightning, but NIP-47 uses a per-connection keypair distinct from your identity key — do not conflate the two. Alby does NOT implement NIP-46 (remote signing) or NIP-49 (`ncryptsec`) for its own at-rest storage.
- Platforms
- Desktop browsers: Chrome/Chromium, Firefox, and Chromium derivatives (Edge, Brave, Opera). No meaningful iOS story — iOS Safari does not support this extension model, so iOS users need a different approach entirely (typically a NIP-46 remote signer). Availability on Firefox for Android was not verified; do not assume a working Android path from this row.
- What it costs you in convenience
- Low — this is the convenient end of the spectrum, and that convenience is bought directly with the security tradeoff above. Unlock once per session, then approve per-site; approval fatigue is mild compared with a strict mobile or remote signer. The cost is not clicks, it is that the key lives on the same machine that runs untrusted code, and that an unlocked session is effectively an unlocked key.
- Limitations
- Weak at-rest KDF relative to NIP-49 (MD5, one iteration, via crypto-js passphrase mode). Very large attack surface for a key holder: 236 open issues and a scope spanning Lightning, Nostr, Liquid and onchain in a single extension — far more code than a signer needs, and correspondingly more to audit. Key is exportable in plaintext, so it offers no hardware-style signing boundary. Documentation gap: Alby's user guide does not clearly document Nostr key storage or whether any backup leaves the device, and their docs endpoint confirms it does not explicitly describe this; for a self-custody audience that gap is itself a finding. Aging dependency: crypto-js has had no release since August 2024 (repository is not archived, but is effectively dormant). CRITICAL AND NOT SPECIFIC TO ALBY: a compromised Nostr key cannot be rotated, migrated, or revoked. There is no merged NIP for this — NIP-41 does not exist in the NIPs repository; the "NIP-41: simple account migration" proposal (PR #829) has been open and unmerged since October 2023, and an earlier "NIP-41: Key Invalidation" draft (PR #158) was closed. NIP-26 delegated event signing is explicitly marked "unrecommended" in the NIPs README. Any claim that you can recover from a leaked nsec by rotating keys is false as of this review; recovery means abandoning the identity and rebuilding your social graph.
- Project status
- Actively maintained, verified via GitHub API on review date: `pushed_at` 2026-07-14T17:04:16Z, `updated_at` 2026-07-19T13:53:41Z, 582 stars, MIT licensed, `archived: false`, `disabled: false`. Not abandoned and not experimental. Caveat on health rather than liveness: 236 open issues against a four-protocol scope indicates a broad, busy project rather than a tight, narrowly-audited one, and its crypto dependency (crypto-js) is itself dormant since August 2024.
Use it if: Desktop users who want frictionless Nostr web-client login and already use Alby for Lightning and zaps. Appropriate for a day-to-day social identity you could genuinely afford to lose. Not appropriate for a high-value, reputational, or irreplaceable identity — for that, use a signer that keeps the key off the browsing machine (Android NIP-55 signer, or NIP-46 remote signing), because a Nostr key compromise is permanent.
Nostore (Safari) Browser extension (NIP-07) medium confidence
- Where the private key lives
- On the user's Apple device, in the Safari WebExtension's own storage. The README states verbatim: "All private key data is sequestered in the extension's separate browser storage," and "This extension does not collect any user data, or transmit any data over a network connection." Read this precisely: browser extension storage is NOT the iOS/macOS Keychain and NOT the Secure Enclave. The project documents no NIP-49 passphrase encryption and no OS-level key protection, so the working assumption must be a private key sitting in extension storage protected only by the app sandbox — not by hardware or by a passphrase. This is the extension's own claim from documentation; it was not confirmed by reading the Swift/JavaScript source, so treat the storage mechanism as documented-but-unaudited.
- Who you must trust
- Not moot — anyone still running an installed copy is inside this trust model right now. You trust: (1) the extension binary and the App Store build that delivered it; (2) Safari's WebExtension storage isolation and the app sandbox as the only barrier between your nsec and other local code, since no keychain or Secure Enclave is documented; (3) every website you grant `window.nostr` access to, because a NIP-07 signer's approval scope is what limits how many events a page can have signed; and (4) the author's past code with the permanent knowledge that no one will patch it. The last item converts the first three from ordinary risks into unfixable ones: a flaw found in the extension, or in any dependency it bundles, has no path to remediation.
- How it could leak
- Concrete paths, in rough order of likelihood. (1) Local disk/malware read: a key in browser extension storage with no documented keychain or passphrase layer is exposed to any process or backup that can reach the extension's container — malware, a malicious app with the right entitlements, or an unencrypted device backup. Hardware-backed storage would blunt this; it is not claimed here. (2) Over-permissive signing: a malicious or XSS-compromised page granted `window.nostr` can request signatures; the damage ceiling is set by the approval prompts, which were not audited here. (3) Deprecated crypto: exposing only the NIP-04 methods means DM content handled through it uses the encryption scheme NIP-07 marks deprecated, with NIP-04's known metadata-leak weaknesses. (4) The permanent-patch-gap: every one of the above stays open forever, and a disclosure has no maintainer to receive it. There is no server or hosted component, so remote/server-breach exfiltration is not in scope.
- NIPs implemented
- NIP-07 ("`window.nostr` capability for web browsers", status: draft/optional). Per its README it implements `getPublicKey`, `signEvent`, and `nip04.encrypt`/`nip04.decrypt`. Note it exposes only the NIP-04 encryption methods — NIP-07 itself marks the nip04 methods deprecated in favour of `nip44.encrypt`/`nip44.decrypt`, which Nostore does not document support for. It is not a NIP-46 remote signer, not a NIP-55 signer (that spec is Android-only), and does not document NIP-49 (`ncryptsec`) passphrase encryption of the stored key.
- Platforms
- Safari on macOS and iOS/iPadOS. Its availability is degrading, not merely frozen: the author warns that "when the Apple developer license expires, this app will drop off the App Store," so new installation may already be impossible. It was a prominent Safari NIP-07 signer, but the claim that it was *the* flagship or only such attempt could not be verified in this review (web search was unavailable) — do not repeat that superlative as fact.
- What it costs you in convenience
- Not a live consideration — this should not be newly adopted, and may no longer be installable. For anyone still running it, the real cost is not prompt fatigue but migration work: generating or moving to a maintained signer, and accepting that the old key's exposure history cannot be undone.
- Limitations
- Unmaintained by the author's own statement, and heading off the App Store. Beyond that, two structural constraints that outlive this project. First, the platform gap: NIP-55 is titled "Android Signer Application" and is Android-specific, so iOS users cannot use the Android-signer route at all; with the browser-extension route weakened, they are pushed toward NIP-46 ("Nostr Remote Signing") bunkers or, far worse, pasting an nsec into apps. Second, and more important: a Nostr key that leaks cannot be rotated, revoked, or migrated. There is no NIP-41 in the NIPs index — that number does not correspond to a live key-migration spec — and NIP-26 delegation is explicitly marked unrecommended in the index ("adds unnecessary burden for little gain"). Treat any exposure of an nsec as permanent and unrecoverable; identity recovery means starting a new identity and rebuilding your follower graph by hand.
- Project status
- ABANDONED, by explicit maintainer declaration — not an inference from inactivity. The GitHub API reports `archived: true`, `disabled: false`, last push 2025-02-11T13:44:27Z, 66 stars, 8 open issues frozen, MIT license. The README states: "This app is no longer in support. I haven't been a Nostr or Safari user for some time and no longer have the will to maintain this application," and warns it will drop off the App Store when the Apple developer license expires. The author suggests forking rather than naming a successor; the MIT license permits that, but no maintained fork was verified in this review. (The repo's `updated_at` of 2026-04-06 reflects metadata, not code activity.)
Use it if: Nobody, as a current choice. Its only remaining use is as evidence: it documents that the Safari/iOS NIP-07 route lost a significant implementation to abandonment. Existing users should treat migration as overdue, and anyone auditing an iOS Nostr setup should check whether an install of this is still signing events.
nos2x (Chromium) Browser extension (NIP-07) high confidence
- Where the private key lives
- In browser extension local storage, IN PLAINTEXT HEX. Verified in source, not inferred. background.js reads it with `await browser.storage.local.get('private_key')`, assigns `let sk = results.private_key`, and passes it straight to `finalizeEvent(params.event, sk)` — no decryption step exists anywhere in the signing path. options.jsx persists it with `browser.storage.local.set({private_key: hexOrEmptyKey})`, raw hex. The NIP-49 path calls `encrypt(data, password, 16, 0x00)` purely to produce an ncryptsec string for the user to copy out; that encrypted value is never what gets persisted. Notably log_n=16 is the lowest value in NIP-49's own reference table, and the security byte 0x00 is defined by NIP-49 as "key handled insecurely" — nos2x is accurately self-declaring its own handling.
- Who you must trust
- You trust the extension code (small and auditable — a genuine advantage), the browser sandbox, the Chrome Web Store distribution channel, and critically the integrity of your OS user account. There is no password, PIN, or unlock layer of any kind, so the browser profile's file permissions ARE the security boundary for your nsec. Anything that can read your user's files can read your identity. Compounding this: Nostr has no merged key rotation, migration, or revocation NIP, so this trust is irreversible — see limitations.
- How it could leak
- Highest at-rest risk of any maintained extension in this class, and the mechanism is trivial: any process running as your user, any infostealer malware (these routinely sweep browser extension storage as a matter of course), anyone with disk access to an unencrypted drive, or a synced/backed-up/cloud-restored browser profile can read the nsec as plaintext hex. No brute force required, no password to crack, no memory-scraping needed. A malicious extension update or a compromised web store listing would also hand it over directly, as would any code with extension-storage access. As with all NIP-07 signers, a malicious website still cannot read the key directly — it can only request signatures — but see ux_cost, because a granted permission is permanent.
- NIPs implemented
- NIP-07 (`window.nostr` capability for web browsers) — implements the two mandatory methods `getPublicKey()` and `signEvent()`, plus the optional NIP-04 and NIP-44 encrypt/decrypt methods (both confirmed handled in background.js). Also implements NIP-49 (`ncryptsec`, Private Key Encryption) in the options UI, but for export/import display only — never for storage. Does NOT implement NIP-46 (Nostr Remote Signing); there is no bunker/remote-signer capability.
- Platforms
- Chromium desktop only — the README states plainly "This extension is Chromium-only" (Chrome, Brave, Edge and similar). Firefox requires the separate nos2x-fox fork (diegogurpegui/nos2x-fox), which is in fact more actively maintained than nos2x itself (last push 2026-07-10 vs 2026-03-21) and carries a proper Unlicense. No mobile support: no Android, no iOS.
- What it costs you in convenience
- Lowest friction of any option here, and that is precisely the problem. Permissions are stored per-host and never expire: common.js writes `policies[host][accept][type]` with a `created_at` timestamp that is set but never read back for expiry — no expiration logic exists in the codebase. An empty `conditions` object means blanket approval for that method on that host. Grant once and the site can sign that event kind silently, forever, for as long as the extension is installed. There is no approve-every-event fatigue because there is effectively no ongoing approval step — which is a usability win and a security loss.
- Limitations
- No encryption at rest — the disqualifying issue for a self-custody audience; NIP-49 support exists but is cosmetic with respect to actual storage safety. No unlock/password layer. Chromium-only, no mobile. No NIP-46, so the key cannot be isolated from the browser. Licensing is ambiguous: GitHub reports no detected license (API `license: null`, no SPDX license file), while the README states only "LICENSE: public domain" — a bare informal declaration with no formal dedication text such as CC0 or Unlicense, which is legally weaker than it appears. 22 open issues against a small codebase. CRITICAL AND OFTEN OMITTED: if this key is exfiltrated it cannot be rotated, migrated, or revoked. Verified against the NIPs repository index — there is no merged NIP for key rotation, migration, or revocation; NIP-41 does not exist in the repo at all (returns 404), and NIP-26 "Delegated Event Signing," the closest historical mechanism, is explicitly marked *unrecommended* by the maintainers. Recovery from compromise means abandoning the identity and rebuilding your social graph from zero. Plaintext-at-rest plus no possible revocation is the combination that should drive the decision.
- Project status
- Alive but low-activity; not abandoned and not archived. GitHub API `pushed_at` 2026-03-21T23:20:09Z — roughly four months without a code push as of 2026-07-20. Repo created 2022-01-10, 387 stars, 22 open issues, `archived: false`, `disabled: false`. Reasonable to describe as maintained-but-slowing: it still works and the maintainer (fiatjaf, Nostr's originator) is active in the ecosystem, but it is not under active development and the Firefox fork is currently receiving more attention than the upstream project.
Use it if: Developers testing Nostr clients, throwaway and burner identities, and people who specifically want minimal auditable code and fully understand what plaintext-at-rest means. Defensible as a burner-key or development tool. Not defensible for an identity you cannot afford to lose, and not appropriate as a general recommendation to a self-custody audience.
nos2x-fox (Firefox) Browser extension (NIP-07) high confidence
- Where the private key lives
- In Firefox extension storage (`browser.storage.local`) on your machine. Verified by reading the shipped source (repo `main` = manifest v1.20.1 = current AMO release), not inferred from upstream: **Default install stores the nsec as plaintext hex.** `isPinEnabled()` in `src/storage.ts` returns `(data[PIN_ENABLED] as boolean) ?? false` — PIN protection is strictly opt-in and off until the user turns it on. With PIN off, `readActivePrivateKey()` returns the raw hex key straight from local storage. **With PIN protection enabled, encryption is real.** `src/pinEncryption.ts` uses AES-GCM-256 with PBKDF2-SHA256 at 100,000 iterations, a 16-byte random salt and 12-byte random IV stored alongside the ciphertext. `updateActivePrivateKey()` actively throws if a caller tries to write a plaintext key while PIN is on, so the two paths do not silently mix. The PIN lives in memory only, is cached ~10 minutes, and is lost when the browser closes. So the honest statement is: encrypted-at-rest only if the user opts in; plaintext otherwise, which is the out-of-the-box state.
- Who you must trust
- You trust: (1) the fork maintainer, diegogurpegui — a different individual from upstream nos2x author fiatjaf, so this is one additional independent party versus running upstream; (2) the Mozilla add-on review and auto-update channel, which can push new code to an extension already holding your key; (3) your OS user account and anything running under it. Two extra exposures visible in the manifest: the content script matches `<all_urls>`, so the extension is injected into every page you visit, and the CSP is `script-src 'self' 'unsafe-eval'` — permitting eval inside an extension process that handles a signing key is weaker hardening than necessary. The decisive point: **Nostr has no key rotation, migration, or revocation.** NIP-41 is absent from the NIPs index entirely (`41.md` 404s on master) — there is no merged, implemented standard for retiring a compromised key. NIP-06 (mnemonic derivation) is explicitly marked *unrecommended* in the index. If any party above is malicious or compromised and your nsec leaves the machine, that identity is permanently and irreversibly lost. You cannot revoke it, and your followers have no protocol-level way to learn it was stolen.
- How it could leak
- With PIN protection off (the default): trivial. Any local malware, any process running as your user, any backup or sync of the Firefox profile directory, or anyone with read access to that directory can lift the plaintext hex key. No password cracking required. With PIN protection on: extraction yields an AES-GCM blob that must be brute-forced against a PBKDF2-SHA256/100k-iteration derivation. That is meaningful against casual theft but weak against a determined attacker if the PIN is short — a numeric PIN has a small keyspace, and 100k PBKDF2 iterations is a modest work factor by 2026 standards (well below what scrypt-based NIP-49 imposes). Treat a short PIN as speed-bump-grade, not as strong protection. Independent of storage: a malicious add-on update, or a malicious/compromised web page abusing a blanket `forever` permission grant, can request signatures or NIP-04/NIP-44 decryptions without further prompting. Because the key is never revocable, any successful exfiltration is terminal for that identity.
- NIPs implemented
- NIP-07 (`window.nostr` capability for web browsers) — itself marked `draft` `optional` in the NIPs repo. Verified in `src/nostr-provider.ts`: implements the two required methods (`getPublicKey`, `signEvent`) plus the optional `nip04.encrypt/decrypt` (NIP-04 is deprecated) and `nip44.encrypt/decrypt`. It does NOT implement NIP-46 (Nostr Remote Signing) or NIP-55 (Android Signer Application) — no bunker/remote-signer code exists in the tree. Critically, its at-rest key encryption is NOT NIP-49: NIP-49 (`ncryptsec`) specifies scrypt + XChaCha20-Poly1305, while this extension uses a custom PBKDF2/AES-GCM scheme. Do not describe it as NIP-49 compliant.
- Platforms
- Firefox desktop (Gecko, Firefox 58.0+) **and Firefox for Android (120.0+)** — Android support is real and current, not speculative: the AMO listing declares Android 120.0 compatibility, and release 1.20.1 (2026-07-10) shipped a fix specifically for popups on Android. No Chromium build (use upstream nos2x there), no iOS — Firefox iOS does not support extensions, and iOS users need a different approach entirely (a NIP-46 remote signer or a native signer app).
- What it costs you in convenience
- Low friction by design, which is exactly the security trade. Per-host permission prompts with granular durations: single-use, 5 minutes, 1 hour, 8 hours, a custom duration, or `forever`. The `forever` option removes approval fatigue and simultaneously removes your last checkpoint before a hostile page gets unlimited signing — the convenience default is the dangerous one. Multi-profile support lets you hold several keys and switch between them. Enabling PIN protection adds genuine friction: an unlock step, a ~10-minute cache window, and a forced re-entry every time the browser restarts, since the PIN is memory-only. Most users skip it, which is why the plaintext default matters so much.
- Limitations
- Plaintext key storage on default install; encryption exists but must be found and switched on by the user. Its encryption is a custom PBKDF2/AES-GCM construction rather than the standardized NIP-49 `ncryptsec` scheme, so encrypted keys are not portable to other NIP-49 tooling, and the implementation has not been independently audited (I read the source and confirmed the parameters; I did not audit the cryptography for subtle flaws). No key rotation or revocation exists anywhere in Nostr — a leaked nsec is permanently burned, and no NIP fixes this today. `unsafe-eval` in the extension CSP and an `<all_urls>` content script widen the attack surface. Released into the public domain under the Unlicense rather than a conventional OSS license, which carries no patent grant and no warranty disclaimer of the kind most OSS licenses provide. Small project: 108 GitHub stars, 6 open issues, ~814 average daily users on AMO, a single maintainer with the bus-factor risk that implies, and no Mozilla Recommended/Verified badge. It is a single-hop fork of fiatjaf/nos2x — not a fork-of-a-fork.
- Project status
- Actively maintained, and currently more active than its upstream. nos2x-fox: last push 2026-07-10T23:05:20Z, AMO release 1.20.1 the same day, not archived, not disabled. Upstream fiatjaf/nos2x: last push 2026-03-21, also not archived — upstream is slower but not abandoned, so this is a "more current fork," not a rescue of a dead project. Note the fork relationship is documented in the README ("a fork from https://github.com/fiatjaf/nos2x focused on Firefox"), while the GitHub API reports `fork: false` because it was created as a standalone repository.
Use it if: Firefox users (desktop or Android) who want the nos2x model and cannot run the Chromium-only original. Reasonable for everyday browsing identities **provided you enable PIN protection immediately after import and choose a long passphrase rather than a short numeric PIN** — it is not on by default, and nobody prompts you. For a high-value or permanent npub, prefer a signer that never exposes the key to a browser process at all: a NIP-46 remote signer, or a NIP-55 Android signer app on mobile. Use burner keys here while you evaluate it.
nostr-keyx (Chrome + native host) Browser extension (NIP-07) medium confidence
- Where the private key lives
- At rest, outside the browser: macOS Keychain (via the `security` command), Windows Credential Manager (PasswordVault API), Linux `pass`, or a GPG/OpenPGP-encrypted blob whose decryption key sits on a YubiKey 5. Critically, at signing time the raw nsec is decrypted into the memory of the Node.js native-messaging host process and passed to `@noble/secp256k1`'s `schnorr.sign` in software — the project's own README states "This extension passes your private key to secp256k1.schnorr.sign and secp256k1.getSharedSecret." The YubiKey therefore only gates decryption of the key; it never performs the Schnorr signature and the key does leave it in plaintext. This is materially weaker than Amber's Android Keystore model and should not be described as hardware-backed signing. The one genuine architectural gain is that the plaintext key is handled in the Node.js process rather than in browser/extension memory, which the README describes as executing NIP-07 functions "outside of the web browser's memory."
- Who you must trust
- You trust: the extension; the Node.js native-messaging host and its entire npm dependency tree (notably `@noble/secp256k1`, which the README explicitly names as the load-bearing dependency); the OS credential store or gpg-agent; and — where used — the YubiKey, but only for decryption, not signing. The native-messaging manifest is a JSON file pointing at an absolute path to a script on disk, so anything running as your user account that can rewrite that file or that path substitutes its own signer. Because the plaintext key is reconstituted in an ordinary user-space Node process, an attacker at user privilege can obtain the nsec itself, not merely individual signatures. The YubiKey does not change this: once decryption succeeds, the key is in host RAM.
- How it could leak
- Better than plaintext extension storage at rest, and better than in-browser signing at use time, but well short of hardware isolation. Concrete paths: (1) malware at user privilege reads the Node host's process memory or attaches a debugger and lifts the decrypted nsec outright; (2) the native-messaging manifest or the script it points to is replaced, substituting a malicious signer; (3) gpg-agent or keychain ACL caching means a YubiKey touch or OS prompt may not be required per operation, so an attacker riding an unlocked session signs silently; (4) any page or extension able to reach `window.nostr` gets signatures subject only to whatever approval UI the extension provides. Layered on top is staleness: over three years without a code push means unaudited, unpatched dependencies in the exact component that touches the private key. Note also that exfiltration is unrecoverable — there is no merged NIP for key rotation, migration or revocation (41.md is absent from the nostr-protocol/nips repository; NIP-26 delegated signing exists but is marked "unrecommended"), so a leaked nsec permanently compromises the identity.
- NIPs implemented
- NIP-07 ("`window.nostr` capability for web browsers") — verified against nips/07.md. It implements the two mandatory methods (getPublicKey, signEvent) plus the optional nip04.encrypt/decrypt. It does NOT implement nip44.encrypt/decrypt; NIP-44 became the current encryption standard after this project stopped receiving commits, and NIP-04 is now marked deprecated in NIP-07 itself. It does not implement NIP-46 remote signing.
- Platforms
- Chrome/Chromium on desktop only — the README is Chrome-specific throughout (Chrome Native Messaging, chrome://extensions). No Firefox support. Host-side backends: macOS (Keychain), Windows (Credential Manager), Linux (`pass`), with GPG/YubiKey as a cross-platform option. Requires a working Node.js runtime on the machine. No mobile support of any kind, on either Android or iOS.
- What it costs you in convenience
- The highest setup cost in the extension category by a wide margin. Beyond installing the extension you must install Node.js, hand-place a native-messaging host JSON manifest containing absolute paths, and provision the chosen backend (keychain entry, `pass` store, or GPG key on a YubiKey). Per-signature friction is not fixed: it depends on keychain access policy and gpg-agent cache TTL, and can silently degrade to no prompt at all once the agent has cached credentials — which is a security property, not just a convenience one, and is not clearly surfaced to the user.
- Limitations
- Effectively unmaintained (see status). NIP-04 encryption only — no NIP-44, so it is incompatible with the current encryption standard and with modern clients that require it. Chrome-only; no Firefox. YubiKey support is described by the project itself as "preliminary" and sits under experimental features, and it protects the key only at rest rather than signing on-device. Requires a Node.js runtime and manual native-messaging configuration. 80 stars, MIT licensed, 1 open issue, not archived. My verification covers the repository metadata, NIP-07's text, and the project's own README; I did not audit the source code, so the security properties described above are the project's claims about its own implementation and are not independently confirmed. Do not build a workflow on it.
- Project status
- Abandoned in practice. The GitHub API reports pushed_at 2023-04-23T12:10:49Z — over three years without a code push as of 2026-07-20. The repository's updated_at field (2026-05-19) reflects metadata changes such as stars, not development activity, and should not be mistaken for maintenance. It is technically not archived and has only 1 open issue, but a three-year gap on a security-critical component covering a protocol that has since standardized NIP-44 encryption and matured NIP-46 remote signing should be read as abandoned, not merely dormant.
Use it if: Nobody should adopt this as a working signer today. Its value is as a citation: it is the clearest existing demonstration that a NIP-07 extension can push signing out of browser memory into a native host gated by OS credential storage. Treat it as a design reference for what a maintained, hardware-backed NIP-07 extension ought to do — not as a recommendation, and not as evidence that hardware-isolated Nostr signing currently exists on desktop.
Nowser (cross-platform) Cross-platform app low confidence
- Where the private key lives
- In software on the device, held by the Nowser app itself. The README attributes protection to platform secure storage (Android native key storage, Apple Keychain, and on Linux a documented libsecret build dependency consistent with the system secret service), but this was not verified in source and no field in the repository documents the key-handling design. Understand the actual boundary: this is a general-purpose Flutter application that must load the plaintext private key into its own process memory to sign, on a general-purpose OS. Platform secure storage protects the key at rest from other applications; it does not protect it from Nowser itself, from a tampered Nowser build, or from anything with code execution in that app or root/jailbreak on the device. This is not hardware key isolation. The separate "Nesigner" ESP32 companion is the only design in this project that would move keys off the general-purpose device, and it is an unaudited hobby prototype (1 star) that should not be relied on as a hardware wallet. Note the standing consequence of any compromise: Nostr has no deployed key rotation, migration or revocation mechanism. NIP-41 does not exist in the NIPs repository (returns 404) and is not in the index; NIP-26 delegated event signing is explicitly struck through and marked "unrecommended." A leaked nsec permanently burns that identity — every follower, every past event, and the reputation attached to the npub. There is no recovery path.
- Who you must trust
- You trust (1) a single maintainer — 42 stars, 2 forks, one contributor of record — with full control over an app that holds your private key and ships its own updates; (2) five separate platform secure-storage integrations, of which only the one you actually run matters, and the weakest sets your real security level; (3) the integrity of an unsigned binary you download yourself from GitHub Releases (a .dmg, two .zip files, and an .apk) with no reproducible-build process and no fastlane or signing configuration in the repository. A `zapstore.yaml` is present, indicating intent to distribute the Android build through Zapstore, where releases are indexed as developer-signed Nostr events — a weaker but real integrity signal for Android only; a live Zapstore listing was not verified. One structural point deserves emphasis: in NIP-07 mode Nowser renders untrusted web content in a browser built into the same application that holds the plaintext key. That collapses a boundary the desktop model deliberately keeps — extension process separate from page — and means a rendering or bridge-injection flaw sits in the same trust domain as the key. In NIP-46 mode the key stays on the phone and relays see only encrypted payloads, so the client and relay are outside the key's trust boundary; that is the strongest configuration this app offers.
- How it could leak
- Device compromise (malware, root/jailbreak, hostile backup extraction) reaches a key that lives in software on that device. A tampered or impersonated build is a live risk: desktop and Android artifacts are unsigned archives fetched over HTTPS from GitHub Releases, with no reproducible builds to verify what you run against the published source — materially weaker than Amber's GPG-signed F-Droid distribution. In NIP-07 mode, hostile web content is rendered inside the key-holding process, so a webview escape or provider-bridge flaw is a direct path to the key rather than an indirect one. Roughly seven months without a code push means any vulnerability discovered in that window — including in the Flutter runtime or bundled dependencies — is likely unpatched. Relays are not a key-exfiltration path in NIP-46 mode: kind 24133 payloads are NIP-44-encrypted, so a relay sees ciphertext only. A relay does, however, see signing metadata — which client pubkey talks to which signer, how often, and when — which is a correlation and traffic-analysis exposure, not a key exposure. Standard signer-app risk applies throughout: a user who approves blindly can be induced to sign an event they did not intend, which does not leak the key but can still cost them.
- NIPs implemented
- NIP-07 (`window.nostr` capability for web browsers), NIP-46 (Nostr Remote Signing), NIP-55 (Android Signer Application) — all three numbers verified against the NIPs index. NIP-46 traffic is kind 24133 with NIP-44 (Encrypted Payloads, Versioned) content, verified in 46.md. Per the project's own platform table, NIP-55 is implemented on Android only; iOS, macOS, Windows and Linux get NIP-07 and NIP-46 only. Caveat on the project's self-description: the README calls NIP-55 "Android's native key management system for secure key storage (similar to Apple Keychain)." That is wrong. NIP-55 is an inter-application signing protocol — a client hands an event to a separate signer app and gets a signature back — and specifies nothing about key storage. A project misdescribing the spec it claims to implement is a reason to weight its other unverified security claims down.
- Platforms
- Android, macOS, Windows and Linux are genuinely installable from GitHub Releases (latest 1.4.1, published 2025-12-12; assets app-release.apk, Nowser.dmg, nowser_linux.zip, nowser_windows.zip). iOS is not. There is no App Store listing and no iOS release asset — the only iOS path the README offers is a TestFlight beta, and that beta was checked on 2026-07-20 and returns "This beta isn't accepting any new testers right now." A new iOS user cannot install Nowser today by any documented route. Even for an existing tester the position is poor: TestFlight builds expire 90 days after upload, and the last iOS build dates to December 2025, so any prior install has long since expired with no newer build published to replace it. Treat Nowser as an Android/desktop signer. Any description of it as a working iOS option is inaccurate as of this writing.
- What it costs you in convenience
- Approve-per-request, as with any signer — and approval fatigue is real: a chatty client generating reactions, and relay-list or profile churn, produces enough prompts that users start approving reflexively, which quietly erases most of the benefit of having a signer at all. NIP-46 mode adds relay round-trips to every signature, so desktop signing feels laggy and fails outright when the relay path is down or the phone is asleep. The Flutter UI is less native-feeling than Amber is on Android. On iOS the cost is not friction but availability — the beta is closed and builds expire, so there is nothing to weigh.
- Limitations
- Single maintainer, 42 stars, 2 forks, 1 open issue, GPL-3.0. No published third-party security audit, no reproducible builds, no signed desktop releases. The README misdescribes NIP-55 as a key-storage system, so its other unverified security claims — specifically which secure-storage API is used on each of five platforms — should not be taken on trust; none of this was confirmed in source. NIP-55 support is Android-only despite the app being cross-platform. iOS is not installable (TestFlight beta closed, no App Store listing). The "Nesigner" ESP32 hardware companion is a separate repository with 1 star and 0 open issues, created 2025-02-22 and last pushed 2026-04-12; it is a hobby experiment, not an audited hardware signer, and no part of Nowser's security should be assumed to rest on it. Finally, a limitation of the whole ecosystem rather than this app: nothing here — and nothing in Nostr today — lets you rotate, migrate or revoke a compromised key. NIP-41 is absent from the NIPs repository and NIP-26 delegation is marked unrecommended, so key loss is terminal for that identity.
- Project status
- Dormant-to-semi-active and materially behind Amber. Last code push 2025-12-12T10:58:45Z and last release 1.4.1 on the same date — roughly seven months stale as of 2026-07-20. Not archived, not disabled, 1 open issue; the repository's `updated_at` of 2026-03-22 reflects metadata activity, not commits. The maintainer has not disappeared — the companion Nesigner repository was pushed 2026-04-12 — but attention has evidently moved off Nowser, and the iOS beta has been left closed with an expired build. Usable on Android and desktop; not a project to depend on for timely security patches.
Use it if: Narrow. Android or desktop users who specifically want one cross-platform signer covering NIP-07 browsing, NIP-46 bunker duty and (Android) NIP-55 intents in a single app, and who accept a semi-active single-maintainer project with unsigned builds. On Android, Amber is the better default — more scrutiny, signed F-Droid distribution, active maintenance — and Nowser should be chosen over it only for the cross-platform or in-app-browser features Amber does not provide. Do not recommend this to iOS users: it cannot be installed on iOS. iOS users wanting to stop pasting nsecs into clients should instead use a NIP-46 remote bunker — self-hosted if they can run one, or a hosted bunker service if not, accepting that a hosted service is a party that can be compromised or coerced — driven from a NIP-46-capable iOS client. That is a real gap in the iOS ecosystem and should be stated as a gap rather than papered over with this project.
Hardware / air-gapped signing Hardware high confidence
- Where the private key lives
- In principle on a dedicated microcontroller or secure element. In practice, overwhelmingly on hobbyist ESP32-class dev boards running single-maintainer firmware with no secure element: lnbits/nostr-signing-device targets the Lilygo T-Display ("you can easily make work with any ESP32"), lnbits/nsec-remote-signer is built for a single board, the Guition JC3248W535 3.5" ESP32-S3. Neither README mentions a secure element, secure boot, or encrypted flash. Two narrow exceptions do involve real secure hardware, and both are near-zero-adoption: BitcoinQnA/passport-nostr-signer (3 stars) derives the key via NIP-06 from the Foundation Passport Prime device seed and seals it to the device — but it is a self-declared "Proof-of-concept" community KeyOS app, not official Foundation firmware; and ygd58/keycard-nip46-proxy (0 stars) is backed by a Keycard smartcard. Key-import paths matter: lnbits/nsec-remote-signer's setup instructs the user to "Generate or import a Nostr private key (nsec format)", so on that project the key may have existed on a hot general-purpose machine before it ever reached the device. (I did not find an import path documented for lnbits/nostr-signing-device; treat import as project-specific, and check it per project.)
- Who you must trust
- You are trusting small, largely unaudited, mostly single-maintainer firmware projects, generally without reproducible builds, most running on general-purpose MCUs with no secure element — plus, for the NIP-46 bridge variants, the relay path. This is a categorically weaker trust position than Bitcoin hardware signing, where mature devices offer secure elements, reproducible builds, years of adversarial review, and a verifiable air-gap format. Note the trap in the two projects that DO sit on real secure hardware (Passport Prime, Keycard): the secure element protects the seed, but you are still trusting proof-of-concept application code and a companion browser extension around it, so device-grade hardware does not confer device-grade software assurance here. Also central: the blind-signing problem. A 135x240 or 320x480 screen cannot meaningfully render the semantic content of an arbitrary Nostr event, so the user approves an opaque blob rather than a decision. A device you cannot read defeats much of the point of having a device. And because no rotation or revocation mechanism exists (NIP-41 unmerged, NIP-26 unrecommended), any one of these trust assumptions failing is unrecoverable.
- How it could leak
- Firmware backdoor or a malicious/unreproducible build — most of these projects cannot be built-and-compared by a third party. Physical extraction from an ESP32 with no secure element and, typically, no encrypted flash and no secure boot enabled. The host computer generally remains trusted, and "air-gapped" is largely a misnomer for what ships: the USB-tethered projects (lnbits/nostr-signing-device and lnbits/horse over WebSerial; passport-nostr-signer over WebUSB) are physically plugged into a potentially compromised machine, while the relay-mediated ones (lnbits/nsec-remote-signer, forgesworn/heartwood, ygd58/keycard-nip46-proxy) run over NIP-46 through relays — neither is a true air gap, they just relocate the exposure. Key import paths mean the nsec may already have been exposed on a hot machine before reaching the device. Blind approval means a malicious host can present one event to the human while obtaining a signature over another, if the firmware does not independently render what it signs. lnbits/nostr-signing-device's README concedes its transport verbatim: "not the most secure data transmission method, but x1000 better than storing the privatekey on a computer" — honest framing that also tells you the bar being cleared is the raw-nsec-in-a-browser baseline, not Bitcoin hardware-wallet security. Any successful exfiltration is terminal: there is no revocation.
- NIPs implemented
- There is NO dedicated hardware-signer NIP and no air-gap transport standard for Nostr. Existing attempts reuse general-purpose NIPs, all verified against the nostr-protocol/nips index: NIP-07 ("`window.nostr` capability for web browsers", exposed through a WebSerial/WebUSB shim), NIP-46 ("Nostr Remote Signing", relay-mediated, used as a bridge to a physical device), NIP-06 ("Basic key derivation from mnemonic seed phrase", deriving the Nostr key from a BIP-39 device seed at m/44'/1237'/account'/0/0), and NIP-01 ("Basic protocol flow description") with BIP-340 Schnorr for the signature itself. Nostr has no equivalent of Bitcoin's PSBT (BIP-174) — no standard, independently verifiable container for passing an unsigned object across an air gap and returning a signature. That absence is the root cause of the immaturity. CRITICAL, and true of every option on this page, not just hardware: a compromised Nostr key CANNOT be rotated, migrated or revoked. NIP-41 (key migration/relinquishment) is NOT a merged NIP — 41.md returns HTTP 404 in the repository and the number does not appear in the NIP index; it exists only as unmerged proposal discussion and MUST NOT be relied on. NIP-26 (Delegated Event Signing), the closest existing delegation mechanism, is struck through in the index and explicitly marked "**unrecommended**: adds unnecessary burden for little gain". There is no deployed recovery path. Compromise of an nsec is permanent loss of that identity.
- Platforms
- Desktop only, and narrowly. WebSerial and WebUSB are Chromium-family APIs, not implemented in Safari or Firefox, so the USB-tethered devices do not work in those browsers at all. The NIP-46 bridge variants are nominally cross-platform because they go via relays rather than USB. iOS is the worst case by a wide margin — no WebSerial, no WebUSB, and NIP-55 is titled "Android Signer Application" and is Android-only, so an iOS user has no hardware-signing path whatsoever and no OS-level signer app to fall back on.
- What it costs you in convenience
- Very high and, for most people, not sustainable: sourcing a specific dev board, flashing firmware, USB driver troubleshooting, being tethered to a Chromium browser, then per-event approval on a tiny screen for a protocol that generates far more signing events than Bitcoin does. Nostr's event volume makes approve-every-event fatigue substantially worse than PSBT approval fatigue, and fatigue reliably degrades into reflexive approval — which, combined with blind signing, is the realistic failure mode rather than an exotic attack.
- Limitations
- The headline finding, stated plainly: hardware signing for Nostr is immature and effectively unavailable compared to Bitcoin, and no major hardware wallet vendor ships it. A GitHub search scoped to Coinkite, Blockstream, LedgerHQ, Trezor, SeedSigner and selfcustody (Krux) for Nostr-related repositories returns total_count 0 — zero official vendor support. Scope caveat: that search matches "nostr" in repo name/description within those six orgs, so it would not catch support buried in closed-source firmware or an unlabelled repo; it is strong evidence, not a proof of absence. Note also that forgesworn/heartwood advertises "ESP32/Ledger" support — that is a third-party bridge, not official Ledger support. The entire visible field is hobby-scale (verified via the GitHub API on 2026-07-20): lnbits/nostr-signing-device (147 stars, last push 2025-10-15), lnbits/horse (40 stars, last push 2025-01-05), lnbits/nsec-remote-signer (5 stars, last push 2025-11-14), BitcoinQnA/passport-nostr-signer (3 stars, last push 2026-07-02, self-described "Proof-of-concept", "Validated on a Passport Prime dev unit over WebUSB", a community KeyOS app plus a companion browser extension and not official Foundation firmware), forgesworn/heartwood (2 stars, last push 2026-07-14), ygd58/keycard-nip46-proxy (0 stars, last push 2026-03-27). Single-digit stars on nearly everything. Compounding all of this: because a Nostr identity IS its key and there is no merged rotation or revocation NIP, a hardware signer's real value would be preventing an unrecoverable loss — yet the immature option itself introduces new firmware and supply-chain risk against that same unrecoverable outcome. One further limitation of this row itself: an additional project sometimes cited in this category, "nSealr", could not be located or verified against a primary source and is therefore excluded rather than described.
- Project status
- Experimental across the board; no project here is production-ready or maintained at a level appropriate for a primary identity. Maintenance is uneven rather than uniformly dead, and the distinction matters: lnbits/horse is effectively abandoned (untouched since 2025-01-05, roughly 18 months) and lnbits/nostr-signing-device — the most-starred project at 147 — has not been pushed since 2025-10-15; meanwhile BitcoinQnA/passport-nostr-signer (2026-07-02) and forgesworn/heartwood (2026-07-14) are actively pushed but carry 3 and 2 stars respectively, i.e. recent commits with essentially no adoption or independent review. Recent activity on a 2-star proof-of-concept is not maturity. This is not a maturing field with a clear leader — it is a scattered set of experiments with no standard to converge on, which is precisely why none of them should be treated as a current option.
Use it if: Honestly: almost nobody, as a primary identity, today. It is a reasonable place for someone who wants to experiment with or contribute to these projects, or for a high-risk user who fully understands they are an early adopter of unaudited firmware and treats the identity as disposable. Anyone whose actual goal is real key isolation right now should use a NIP-55 Android signer or a NIP-46 remote signer instead — both are dramatically more mature than anything in the hardware category. Self-custody users arriving from Bitcoin should specifically not assume their existing signing device covers Nostr; it does not, and the one Passport Prime integration that exists is a community proof-of-concept rather than vendor firmware.
Raw nsec in a client (no signer) No signer high confidence
- Where the private key lives
- Inside the client application itself, with no boundary between the app and the key. A web client stores it in localStorage or IndexedDB scoped to that origin — plaintext hex or nsec, readable by any script running on that origin, unless the client wraps it with NIP-49. A native desktop or mobile app stores it in a config file or, in better implementations, the OS keychain; quality varies per app, is rarely documented, and without source review plus reproducible builds a user cannot verify which of the two a given app actually does. NIP-49 changes only the at-rest form, not the location. In every case the raw 32-byte secret is loaded into the application's process memory to produce each signature, so the application holds the complete key, not a scoped signing capability.
- Who you must trust
- You trust the client absolutely and permanently — every line of code it ships, every dependency it pulls, and every future version it auto-updates to. This is not "trust it to sign this one event"; it is handing over your identity forever. For a web client you additionally trust the web server that re-serves the JavaScript on every page load, plus its CDN, TLS chain and domain registrar. A site that is honest today can serve a key-stealing bundle tomorrow, and the key it steals is the same key. Because a Nostr identity IS its key, there is nothing to revoke afterward: no session to log out, no permission to withdraw, no password to reset. This is not a gap waiting to be filled — as of this review the NIPs repository contains no merged specification for key rotation, migration or revocation, and no NIP title in the index mentions migration, rotation, revocation or recovery. Migration schemes have been floated in unmerged proposals; none is a merged, implemented standard, so plan as though rotation does not exist. Announcing a new npub to your followers is social mitigation only: the compromised key still produces cryptographically valid events forever, and relays and clients have no mechanism to reject them. Compromise is terminal for that identity.
- How it could leak
- Extraction is trivial and multi-path. (1) Malicious or compromised client code — one line of JavaScript reads localStorage and POSTs it anywhere. (2) XSS on the origin: any injected script inherits full read access to the stored key. (3) Supply chain — a poisoned npm dependency inside the client. (4) A silently updated JS bundle on a later visit. (5) Any browser extension holding host permissions for that origin can read the same storage. (6) Clipboard: the OS clipboard and clipboard-history/sync managers retain the pasted nsec long after the paste. (7) Browser profile sync replicates the stored key to other devices and vendor cloud. (8) Disk images, device backups and forensic recovery. (9) Screen recording and shoulder-surfing during entry. (10) A shared or multi-user device or browser profile. Note also that theft is not the only failure: a client holding the raw key can silently sign and publish events you never authored, and can publish the key itself to relays — NIP-49 explicitly warns against publishing encrypted private keys to nostr, because amassing many of them makes cracking easier. Crucially, you cannot audit from outside whether a page signs locally or simply uploads the key — both look identical to the user.
- NIPs implemented
- No signer NIP is involved — that is the defining property. Related, and verified against the NIPs index: NIP-19 "bech32-encoded entities" (defines `nsec` as the bech32 prefix for private keys — the format being pasted); NIP-49 "Private Key Encryption (`ncryptsec`)" (optional at-rest encryption, no status marker); NIP-06 "Basic key derivation from mnemonic seed phrase" at m/44'/1237'/<account>'/0/0, carrying the index warning `unrecommended: prefer a single nsec`. None of these create an isolation boundary — they describe only how the key is encoded, stretched or derived. The NIPs that do create a boundary, and that this pattern forgoes, are NIP-07 (window.nostr capability for web browsers), NIP-46 (Nostr Remote Signing) and NIP-55 (Android Signer Application). Also relevant: NIP-26 "Delegated Event Signing", marked `unrecommended: adds unnecessary burden for little gain`. There is no NIP numbered 41 in master — the index runs 40 ("Expiration Timestamp") straight to 42 ("Authentication of clients to relays"), and `41.md` returns HTTP 404.
- Platforms
- Universal — every platform, every client. It is the only method with no platform gaps, which is why it persists as a fallback everywhere, including on iOS where NIP-55 (Android-only) does not apply. The frequent claim that it is the default onboarding path for most new users is plausible but was not verified against any usage measurement in this review; treat it as an impression, not a statistic.
- What it costs you in convenience
- Effectively zero: no extension to install, no app to pair, no approval prompt per event, no bunker URI. The convenience is the vulnerability — because pasting is frictionless, users paste the same nsec into many clients and websites, and every paste is permanent and irreversible. Each additional paste widens the trusted set forever, and there is no mechanism to narrow it again.
- Limitations
- Do not paste an nsec into a website. It is the weakest option available, and the reason is structural rather than a matter of the site's honesty: a web page re-fetches its code from a server on every load, so trust must be re-extended on every visit to a key that can never be withdrawn. Native apps are meaningfully better than web pages here (the code is pinned at install time and OS-sandboxed) but still hold the full key. On NIP-49: it changes less than users assume. It encrypts the key at rest as `ncryptsec` using scrypt with a user-chosen work factor log_n (N = 2^log_n; the spec's examples run 16 to 22) with r=8 and p=1, then XChaCha20-Poly1305. That genuinely raises the cost of offline theft from a stolen disk, backup or storage dump, and its key-security byte records provenance (0x00 = known to have been handled insecurely, 0x01 = not known to have been handled insecurely, 0x02 = client does not track this). But to sign anything the client must decrypt back to the raw key in memory, so a malicious client, an XSS payload running after unlock, or a keylogger capturing the passphrase all still recover the complete nsec. The spec itself only recommends that clients zero out password and key memory after use — it cannot enforce it. NIP-49 hardens storage; it does not create a signing boundary, and it provides essentially no protection in the paste-into-a-website case because the passphrase is typed into the same page that holds the ciphertext. The escape hatches around this pattern are also closing: NIP-26 can technically issue a kind- and time-scoped delegation, but the index marks it `unrecommended: adds unnecessary burden for little gain`, and NIP-06 mnemonic derivation is marked `unrecommended: prefer a single nsec` — so there is no well-supported sanctioned way to hand out a lesser-privileged sub-key. Real-world client support for NIP-26 was not surveyed in this review.
- Project status
- Not a project with maintainers — a pattern, so "abandoned" does not apply. It is actively used and universally supported while being explicitly discouraged by the ecosystem's own direction of travel: the maintained signer NIPs (07, 46, 55) exist specifically to replace it, and its two adjacent escape hatches are both flagged `unrecommended` in the NIPs index (NIP-26, NIP-06) as of this review. Treat it as the deprecated-by-intent default: available everywhere, endorsed nowhere.
Use it if: A deliberately disposable burner identity with no reputation, no followers and nothing at stake — or local testing and development against a throwaway key. It is defensible only when you have decided in advance that you are willing to lose that key permanently. It is not appropriate for any identity you intend to keep, build reputation on, or receive value through, and it should never be used for a key that also controls funds or a zap destination.
nsecbunkerd — DEFUNCT Defunct high confidence
- Where the private key lives
- Historically: the user's nsec sat on a server the user operated, encrypted at rest. That framing undersells the exposure and should not be repeated — a signing daemon must hold the key in plaintext in process memory to sign, so encryption-at-rest protects only a stolen disk, not a live host. Anyone with root on that machine, a memory dump, the at-rest passphrase, or the daemon's own admin interface could extract the nsec. This is now moot regardless: the software cannot be obtained from its canonical repository.
- Who you must trust
- Do not adopt. Historically you trusted yourself as host operator plus anyone with root on that host — never "nobody but you." Today the trust model is strictly worse and unresolvable: deploying it means running code from a third-party fork or a stale npm artifact with no upstream maintainer, no upstream security patching, and no canonical source to diff against, so you cannot establish that what you are running is what was audited by anyone. Note also that at least one third-party copy (Bitsperitybtc/nsecbunkerd, 0 stars, pushed 2026-06-28) has a recent timestamp and can read as "active" — recency of a fork is not authority. Unverified: why the source was deleted. No deprecation notice, advisory, or maintainer statement was found, so it is not known whether the wipe was prompted by a security issue, a licensing decision, or abandonment; treat the absence of a stated reason as itself a reason for caution.
- How it could leak
- Unpatched vulnerabilities with no upstream to fix them, on a daemon that by design holds plaintext signing keys in memory. Concretely: host compromise or root access yields the nsec directly; a malicious or backdoored fork yields it silently; a stale published package cannot receive a patch. Compounding this, the npm package `nsecbunkerd` still resolves and installs — latest 0.9.0, published 2023-12-20, and NOT flagged as deprecated — so `npm install nsecbunkerd` today silently delivers a ~2.5-year-old unmaintained key-custody daemon with no warning of any kind. That is an unacceptable supply-chain position for a key that cannot be rotated.
- NIPs implemented
- NIP-46 ("Nostr Remote Signing"), confirmed present as 46.md in github.com/nostr-protocol/nips and carrying no draft/deprecated marker. NIP-46 defines the client/remote-signer split over event kind 24133. The NIP number is verifiable; what is NOT verifiable is nsecbunkerd's own conformance to it, because the implementation source has been deleted and cannot be read.
- Platforms
- Historically a Node.js/Docker daemon, self-hosted on a machine you control. Satellite projects (kind-0/nsecbunker-admin-ui, last pushed 2024-02-17; hzrd149/nsecbunker-startos, last pushed 2024-04-16) are likewise stale. Irrelevant in practice now, since the software should not be deployed.
- What it costs you in convenience
- Not applicable — nothing here should be run. For context on what a replacement costs you: any self-hosted bunker means you own uptime, backups, and patching, and if your host is down or unreachable you cannot sign at all.
- Limitations
- The repository has been emptied. Verified directly against the GitHub API: the repo contains exactly one file, a 15-byte README.md whose entire content is the string "Gigi was right". Commit history has been force-pushed down to a single commit, sha 4ca87a50419a79ef1c0fd8f55d918c120bfcd985, titled "initial commit", dated 2026-06-02, despite the repo having been created 2023-05-15. Reported size is 0. The entire codebase and its history were deleted. Separately, and central to why this matters: a compromised Nostr key cannot be rotated, revoked, or migrated. This is not a gap in nsecbunkerd but in the protocol — NIP-46 itself defines no rotation, revocation, or migration mechanism, and there is no NIP-41 in the NIPs repository at all (the index runs 40 → 42, with no 41.md). Do not describe key rotation as an existing or draft standard. Key compromise on Nostr is terminal and permanent, which is what makes running unverifiable custody software disqualifying rather than merely unwise.
- Project status
- Defunct — source deleted upstream on 2026-06-02. This is an active trap for automated tooling: the GitHub API reports pushed_at as 2026-06-02, which naively reads as "updated recently / actively maintained," when that timestamp is in fact the moment the project was wiped. The repo is NOT archived and NOT disabled, carries no deprecation notice, still shows 144 stars, and still advertises the description "Coinbase for nostr" — so dependency scanners, "is this project alive" heuristics, and casual human inspection will all misreport it as healthy. The npm package is likewise undeprecated and still installable. Unverified: the maintainers' reason for the deletion.
Use it if: Nobody. Included specifically because a large volume of Nostr documentation, blog posts, and client help pages still point users to nsecbunker as THE self-hosted signing option, and that advice is now actively dangerous. Readers following it should look instead at a maintained self-hosted NIP-46 signer. The most direct candidate is Signet at github.com/Letdown2491/signet — but note carefully that its status as a successor rests on the project's OWN description ("an extensive rewrite of nsecbunkerd"), not on any handoff, endorsement, or transfer from the original kind-0 maintainers, of which none was found. Use the exact repository path: at least three unrelated Nostr projects are named "signet" (Letdown2491/signet, zig-nostr/signet, and forgesworn/signet, which is a different thing entirely — an identity-verification protocol), and searching the bare name is a realistic way to install the wrong software.
What an nsec actually is
A Nostr account is exactly one secp256k1 keypair — the same curve Bitcoin uses, with x-only 32-byte public keys as in Taproot. NIP-01 states that signatures, public key, and encodings are done according to the BIP-340 Schnorr standard for secp256k1. Events carry a 32-byte hex pubkey, an id that is the sha256 of the serialized event, and a 64-byte signature over that id. If you already think in seed phrases and self-custody, the model transfers directly: there is no account on a server, only a key you hold and the signatures it produces.
bech32 is an encoding, not encryption
An nsec1... string is your raw private key in plaintext, wearing a checksum and a human-readable prefix. It has exactly the secrecy properties of a hex private key — closer to an unencrypted WIF key than to a passphrase-protected seed phrase. Anyone who reads it owns the identity, permanently. NIP-19 exists to prevent confusion between private keys, public keys, and event ids, all of which are 32-byte strings; it adds no protection.
npub and nsec are display formats only
NIP-19 is explicit: npub keys MUST NOT be used in NIP-01 events or in NIP-05 JSON responses, only the hex format is supported there. The bech32 forms exist for display, QR codes, and user input; clients convert to hex internally. Bare 32-byte values use npub (public key), nsec (private key), and note (event id). The TLV-carrying forms are nprofile, nevent, naddr, and the deprecated nrelay.
Identity IS the key, structurally
There is no account record, no registrar, no username table. Your pubkey is your identity: every follower's follow-list contains that 32-byte value, every relay indexes by it, and every signature that ever built your reputation traces to it. There is no issuer who can mark it revoked, because there is no issuer. The property that makes Nostr censorship-resistant — no authority — is the same property that makes revocation unsolvable by decree.
Deriving a Nostr key from a BIP39 mnemonic (NIP-06)
m/44'/1237'/<account>'/0/0
NIP-06 defines BIP-44 derivation at coin type 1237, hardened at the first three levels; a basic client uses account 0 for a single key. If your key came from this path, your BIP39 mnemonic is a complete backup — the nsec regenerates from the words plus the path. The caveat most guides miss: NIP-06 is struck through in the canonical NIPs index, annotated verbatim "unrecommended: prefer a single nsec". It works and is widely implemented, but it is no longer the default.
Backing up a key you can never change
Because there is no rotation, backup discipline carries the whole weight. These are the practices that survive a device loss without handing anyone your identity.
Store the encrypted form, not the raw nsec
NIP-49 wraps the private key with scrypt (log_n 16-22, r=8, p=1, 16-byte salt) and XChaCha20-Poly1305 AEAD, bech32-encoded as ncryptsec. An ncryptsec1... is safe to write down in ways an nsec1... is not, though its security collapses to your password strength.
Back up the password as rigorously as the ciphertext
An ncryptsec with a forgotten password has no recovery path and no rotation path. Store the password separately, with the same discipline you apply to the encrypted key, or you have built a very secure way to lose your identity.
Never publish an encrypted key to Nostr
The NIP-49 spec warns directly that cracking a key may become easier when an attacker can amass many encrypted private keys. An ncryptsec is safe-to-store, not safe-to-broadcast.
Record the derivation path alongside a mnemonic
Words alone plus a wrongly assumed path yields a different key. Write down exactly what it is: "Nostr, NIP-06, m/44'/1237'/0'/0/0". Do not assume a BIP39 passphrase is honoured — client support varies, so verify by re-deriving before you rely on it.
Keep the nsec off screenshots and the clipboard
Screenshots land in cloud photo sync and are often OCR-indexed. Copying an nsec exposes it to every clipboard-reading process and to mobile clipboard history and cross-device clipboard sync.
Do not reuse your Bitcoin wallet mnemonic
Coin type 1237 makes the derived keys different, but reuse widens the blast radius of that one mnemonic to include an identity you will hand to more devices and more flaky clients than you would ever hand a wallet seed. Keep them separate.
Method & related
Every NIP number on this page was verified by fetching the specification text from the nostr-protocol/nips repository rather than recalled from memory, because a transposed NIP number in a security reference is a fatal error rather than a typo. Each signer was then researched from its own source code and handed to an adversarial reviewer told to assume the row understated the risk — understating who can exfiltrate a key is a security failure, not a wording problem. That review is why, for example, this page states that an Android signer's secure element protects only the wrapping key while the actual signing happens in software.
Scope: this is the signer and key-lifecycle layer. Which client supports which signer is already covered by the Nostr client directory; the specs themselves are indexed in the NIPs reference. This page does not repeat either.
Related: Nostr client directory · NIPs reference · relay directory · NIP-19 key converter · Bitcoin wallet recovery matrix · sovereignty vertical
Open data (CC BY 4.0): CSV · JSON · API: /wp-json/dc/v1/nostr-key-management
Related products, repair, and setup paths
- Bitcoiner sovereignty hub
- the plebs sovereign stack
- Nostr for Bitcoiners
- run your own Nostr relay
- getting started with Meshtastic
- Bitcoin over Meshtastic mesh networks
- open-source hardware tools directory
- off-grid Bitcoin mining
Last reviewed July 20, 2026.
