fix(security): origin-check the NIP-07 bridge + share-to-mesh, gate all identity methods behind consent

The nostr bridge derived the caller from the launcher's own URL and
never checked event.origin, so any co-resident iframe could pull the
node's nostr pubkey or use nip04/nip44 decrypt as an oracle while an
app was open. The bridge now rejects senders whose real origin doesn't
match the open app's origin, and every identity-sensitive method
(getPublicKey, signEvent, encrypt/decrypt) requires user consent or a
remembered per-origin approval — previously only signEvent did.

share-to-mesh in App.vue likewise accepted messages from any sender
and force-navigated to /mesh with an attacker-staged CID; it now
requires same-origin, matching Chat.vue's existing handler.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-07-02 12:53:41 -04:00
co-authored by Claude Fable 5
parent 51647b21cd
commit 206d5fe8cf
3 changed files with 43 additions and 22 deletions
+8 -9
View File
@@ -141,15 +141,14 @@ modules; production request/boot paths are essentially panic-free. The real risk
The untrusted mesh/LoRa chat path is **safe** (interpolation, no `v-html` — good).
The real issues are the app-bridge origin model and a bloated bundle.
- [ ] 🟠 **Validate `event.origin` + add consent gates in the NIP-07 nostr bridge.**
`stores/appLauncher.ts:385-490` derives the caller from the launcher's own URL, never
`event.origin`, and `getPublicKey`/`nip04.decrypt`/`nip44.decrypt` have no consent gate →
any co-resident iframe can deanonymize the nostr identity or use the node as a decryption
oracle while an app is open. Check `event.origin` against the open app's real origin; key
approvals on it; gate decrypt/getPublicKey like `signEvent`.
- [ ] 🟠 **Origin-check the `share-to-mesh` handler.** `App.vue:450-464` acts on
`{type:'share-to-mesh', cid}` from any sender and force-navigates to `/mesh` with the CID
pre-staged. Add `ev.origin === window.location.origin` (as `Chat.vue:95` already does).
- [x] 🟠 **Validate `event.origin` + add consent gates in the NIP-07 nostr bridge.**
DONE 2026-07-02: `handleNostrRequest` rejects senders whose `event.origin` doesn't match
the open app's URL origin, and ALL identity-sensitive methods (`getPublicKey`, `signEvent`,
`nip04`/`nip44` encrypt+decrypt) now go through the consent/approved-origins gate, not just
`signEvent`. Verified present in the built bundle.
- [x] 🟠 **Origin-check the `share-to-mesh` handler.** DONE 2026-07-02: `App.vue`
`onShareToMeshMessage` now requires `ev.origin === window.location.origin` (matching
`Chat.vue`).
- [ ] 🟡 **Decide the app-iframe isolation model.** `AppSessionFrame.vue:54` /
`AppLauncherOverlay.vue:79` embed apps same-origin with no meaningful `sandbox`; a
same-origin app can read the CSRF cookie + `localStorage`. Ideal fix (serve apps from a