PSA:
Just got a weird XSS attack as a 0 sats zap (not sure how that even works).
Seems a good thing I was on Wisp on iOS when it happened, and it didn’t seem to execute. If I was to be on Primal on browser it might have worked.
But may be having to start a new nsec soon anyway.
Here’s what my AI thinks it did:
“This looks like a deliberate XSS (cross-site scripting) attack attempt targeting Nostr clients, likely Primal.
Here's a breakdown of what's happening and what it means:
What the payload is doing
The zap description isn't a normal message. It's an injection attempt containing:
<div> <div> <div> — Nested HTML elements designed to bypass naive sanitizers or exploit rendering quirks in a client that displays zap descriptions as HTML rather than plain text.
A webhook[dot]site URL — Webhook[dot]site is a legitimate tool, but here it's being used as an exfiltration endpoint. Any data sent to that URL goes directly to the attacker. They're using it as a quick, anonymous way to capture stolen data without hosting their own server.
localStorage.getItem('primalSec') — This is the smoking gun. primalSec appears to be a localStorage key used by Primal (a Nostr client) to store sensitive session data. The attacker is trying to steal this credential via XSS and send it to their webhook.
In short: the attacker is sending 0-sat zaps with malicious descriptions hoping your client will render the description as HTML/JavaScript, which would then silently steal your session secrets and beam them to webhook[dot]site.”
Login to reply
Replies (17)
Thanks for the heads-up. Wisp should never execute any injected code, but we’ll make sure we look at these types of threat vectors across the apps.
@Zap Cooking is based on the same codebases, so whatever security hardening happens on Wisp will show up there soon after.
Slimy bastards
But you do bring up another thing g we need to think about rotating noubs/nsecs
XSS via 0 sat zap is a clever exploit, likely due to a DOM-based vulnerability. Wisp's iOS sandboxing probably saved you, consider using a userscript blocker for added security.
This seems strange. Unless primal is a vibe coded mess, it should sanitize any user editable fields for html tags. Is there something special about the structure of a zap?
@Cody 👀
@Final does Vanadium protect me? 👀
Whaaaaat? How did you catch it? Now I'm worried
Just got like three 0 sats zaps in a row whenever I posted my Word5 score.
The description was just all raw code when I saw it. However, if it did execute you might not see anything at all.
Based on its target, I assume it would only actually work if I were on Primal via web browser upon seeing the zap, but what do I know.
According to my AI:
“for this attack to work, the malicious JavaScript would need to actually execute on your device, within the app's environment. That's the fundamental requirement of XSS.
Here's why you're very likely fine in this case:
You saw raw code as text. That means Wisp escaped or sanitized the HTML — it treated the zap description as plain text rather than parsing it as HTML/JavaScript. The <div> tags were displayed to you as literal characters, not rendered as DOM elements.
If the code had actually executed, you'd typically see nothing unusual — the divs would be invisible elements in the DOM and the JavaScript would run silently in the background. The fact that you can read the attack code is actually your strongest signal that it didn't run.”
Oh god. I'd be curious to know what the code was designed to do, if you could check that safely. New npub needed?
It seems that it definitively wanted to grab the Key credentials from browser storage and then upload it silently to their webhook[dot]site. I wish I would have thought to do a better job capturing it before I muted the npub.
But it was pretty simplistic. So I can remember most of it.
Most of the whole code was just <div> repeated ~a hundred times, then it ultimately led to <table><style>[webhookURL] localStorage.getItem(‘primalSec’</style></table></div>
Damn. You should tag @primal just in case. I just did though.
You’re right, I’m noticing that @miljan and the like may still be unaware.
Don’t figure it would hurt any for everyone to be aware
Can't be executed on my android app. This affects browser clients, which mycelium for web is unusable anyways. 👍
Not sure about amethyst though since it now offers a web browser available to my knowledge.
Though I have never tested 0 sat zaps in mycelium-android, I don't want to know what would happen or whose problem it is. 🤠

Smesh
A user-friendly Nostr client for exploring relay feeds
This exploits a vulnerability in one of our dependencies. Updating the dependency to the latest version fixes the issue.
This issue has been fixed and is now live. Let me know if you run into any issues