I Built My Own Nostr Signer and Discovered a Different Security Problem

I Built My Own Nostr Signer and Discovered a Different Security Problem

By SkyLords | SkyLords Bitcoin Lab | 6 hours ago


I started building my own Nostr signer for a simple reason: I wanted to understand what actually happens between a Nostr client and my private key. I didn't want signing to remain a black box.

That small experiment became a browser extension I called SkySigner.

The first version was simple.

Keep the private key local. Implement the basic NIP-07 interface. Let Nostr clients request my public key and ask SkySigner to sign events without ever giving the client access to the private key.

getPublicKey() worked.

signEvent() worked.

I imported my existing Nostr identity, verified locally that the private key derived the expected npub, and eventually used SkySigner with my real identity to publish and reply on Nostr.

So far, so good.

Then I tried messaging.

And that's where the experiment became much more interesting.

The signer started fighting the user

Modern Nostr messaging involves encryption operations such as NIP-44.

After adding NIP-44 encrypt/decrypt support, I started testing different Nostr clients.

Some clients generated many signer requests while loading messages.

This makes sense technically. A client may need to decrypt multiple messages when opening a conversation.

But imagine a signer asking:

Approve?

Approve?

Approve?

Approve?

...again and again just to read your messages.

At first this looks extremely secure.

Every operation requires consent.

But after clicking Approve twenty times, something changes.

You're probably no longer verifying anything.

You're just trying to make the popup disappear.

And that made me realize that excessive confirmation can become its own security problem.

So I changed the permission model

The current SkySigner experiment works roughly like this:

getPublicKey
    → session permission

NIP-44 encrypt/decrypt
    → session permission

known event kinds
    → configurable per site/session

unknown event kinds
    → always ask

every request/decision
    → local audit log

I also added popup-storm protection.

If the same client generates many requests for the same operation, SkySigner doesn't need to spawn a pile of approval windows. Requests can be queued and handled according to the permission granted to that site.

I then added site trust profiles and browser-session permissions.

For example, I can effectively tell a trusted Nostr client:

You may access my public key and perform these specific encryption operations during this browser session.

The private key still never leaves SkySigner.

But now we've arrived at another security problem.

What exactly are we trusting?

If every operation requires approval, the signer can become unusable.

If everything is automatically approved, the signer loses much of its purpose.

So perhaps the interesting security boundary isn't simply:

client vs private key

Maybe it is:

client + capability + event type + duration + user consent

A trusted client might be allowed to decrypt messages for one browser session.

A known event kind might receive a temporary permission.

An unusual or unknown event should still trigger explicit approval.

And everything should remain visible in a local audit log.

That's the model I'm experimenting with now.

SkySigner is still an experiment, not production-ready security software. Building it has been a way for me to understand Nostr signing, encryption, identity and permissions by actually implementing them instead of only reading about them.

And the experiment changed the question I started with.

Initially I was asking:

How do we keep the private key away from the Nostr client?

Now I'm also asking:

How do we prevent signer security from becoming “click Approve until the popup disappears”?

I'm especially interested in hearing from people who use or build Nostr signers.

How would you design this permission model? Which actions should a signer be able to remember for a trusted site or session, and which actions should always require explicit approval from the user?

Also, click here to read my article, “My Laptop Needs 8.6 Billion Years to Mine a Bitcoin Block”

 

 

How do you rate this article?

2


SkyLords
SkyLords

I'm a tech and crypto enthusiast exploring Bitcoin, Lightning, CPU mining, blockchain projects, and practical experiments with emerging technologies. I enjoy testing ideas myself rather than just discussing them, and I like sharing what works, what fails, and what I learn along the way. Here I'll write about Bitcoin, mining, Lightning, crypto tools, software projects, and interesting developments across the wider blockchain ecosystem.


SkyLords Bitcoin Lab
SkyLords Bitcoin Lab

A hands-on lab for Bitcoin, Lightning, Nostr and experimental software. Real tests, lessons, failures and discoveries from building tools, exploring decentralized protocols and learning how the technology actually works.

Publish0x

Send a $0.01 microtip in crypto to the author, and earn yourself as you read!

20% to author / 80% to me.
We pay the tips from our rewards pool.

Page not displaying correctly?