Security: Harden Nostr private key (prvkey) handling #11

Open
opened 2026-01-01 21:22:54 +00:00 by padreug · 0 comments
Owner

Summary

Security audit identified several improvements needed for Nostr private key (prvkey) handling before production deployment. While no critical vulnerabilities were found (keys are not persisted to storage), the codebase needs hardening.

Risk Level: HIGH ⚠️

Audit Findings

Strong Points (Already Implemented)

  • No browser storage persistence - Keys not in localStorage/sessionStorage
  • Memory-only storage - Keys cleared on logout
  • No logging of private keys - Verified across codebase
  • HTTPS-only transmission - Proper authentication headers
  • Server-side key generation - Keys managed by LNbits

🔴 Critical Issues

1. Vue DevTools Exposure (Production Blocker)

Private keys visible via Vue DevTools inspector and debug globals in development mode.

Files affected:

  • src/app.ts:174-182 - Exposes window.__container in dev mode

Required fix:

// app.ts
if (import.meta.env.PROD) {
  app.config.devtools = false
  // Don't expose debug globals
}

2. No Centralized Signing Service

10+ files directly access authService.user.value.prvkey:

File Usage
nostr-metadata-service.ts Signs metadata (kind 0)
chat-service.ts NIP-04 encrypt/decrypt
ReactionService.ts Signs reactions (kind 7)
NoteComposer.vue Signs notes (kind 1)
RideshareComposer.vue Signs rideshare events
useMarket.ts Market DM decryption
NostrFeed.vue Feed DM decryption

Risk: Each access point is potential exposure if code modified incorrectly.

Recommendation: Create centralized SigningService:

class SigningService {
  async signEvent(event: NostrEvent): Promise<string>
  async encrypt(pubkey: string, plaintext: string): Promise<string>
  async decrypt(pubkey: string, ciphertext: string): Promise<string>
}

⚠️ Other Improvements Needed

  1. No audit trail - Cannot track when/where key is used
  2. No key rotation - Compromised keys cannot be revoked
  3. No rate limiting - No protection against automated extraction
  4. CSP headers missing - Content Security Policy not configured

Implementation Checklist

Immediate (Production Blocker)

  • Disable Vue DevTools in production builds
  • Verify developmentMode: false in production config
  • Ensure window.__container undefined in production
  • Add security headers (CSP, X-Frame-Options)

Short-Term (Next Sprint)

  • Create centralized SigningService
  • Refactor all prvkey access to use SigningService
  • Add audit logging for signing operations (without logging key)
  • Implement rate limiting for signing operations

Long-Term (Roadmap)

  • Server-side signing API (browser never sees prvkey)
  • Amber signer integration (NIP-46) for user-controlled keys
  • Key rotation support
  • HSM integration for server-side keys

Security Testing Checklist

  • Vue DevTools disabled in production build
  • window.__container undefined in production
  • XSS penetration testing
  • Heap dump analysis for key exposure
  • Verify prvkey cleared on logout
  • Verify no browser storage persistence

Risk Matrix

Risk Likelihood Impact Priority
DevTools exposure HIGH (dev) / LOW (prod) CRITICAL P0
XSS attack MEDIUM CRITICAL P1
Memory inspection LOW HIGH P2
Malicious code injection LOW CRITICAL P1 (CSP)

References

## Summary Security audit identified several improvements needed for Nostr private key (`prvkey`) handling before production deployment. While no critical vulnerabilities were found (keys are not persisted to storage), the codebase needs hardening. **Risk Level: HIGH** ⚠️ ## Audit Findings ### ✅ Strong Points (Already Implemented) - **No browser storage persistence** - Keys not in localStorage/sessionStorage - **Memory-only storage** - Keys cleared on logout - **No logging of private keys** - Verified across codebase - **HTTPS-only transmission** - Proper authentication headers - **Server-side key generation** - Keys managed by LNbits ### 🔴 Critical Issues #### 1. Vue DevTools Exposure (Production Blocker) Private keys visible via Vue DevTools inspector and debug globals in development mode. **Files affected:** - `src/app.ts:174-182` - Exposes `window.__container` in dev mode **Required fix:** ```typescript // app.ts if (import.meta.env.PROD) { app.config.devtools = false // Don't expose debug globals } ``` #### 2. No Centralized Signing Service 10+ files directly access `authService.user.value.prvkey`: | File | Usage | |------|-------| | `nostr-metadata-service.ts` | Signs metadata (kind 0) | | `chat-service.ts` | NIP-04 encrypt/decrypt | | `ReactionService.ts` | Signs reactions (kind 7) | | `NoteComposer.vue` | Signs notes (kind 1) | | `RideshareComposer.vue` | Signs rideshare events | | `useMarket.ts` | Market DM decryption | | `NostrFeed.vue` | Feed DM decryption | **Risk:** Each access point is potential exposure if code modified incorrectly. **Recommendation:** Create centralized `SigningService`: ```typescript class SigningService { async signEvent(event: NostrEvent): Promise<string> async encrypt(pubkey: string, plaintext: string): Promise<string> async decrypt(pubkey: string, ciphertext: string): Promise<string> } ``` ### ⚠️ Other Improvements Needed 1. **No audit trail** - Cannot track when/where key is used 2. **No key rotation** - Compromised keys cannot be revoked 3. **No rate limiting** - No protection against automated extraction 4. **CSP headers missing** - Content Security Policy not configured ## Implementation Checklist ### Immediate (Production Blocker) - [ ] Disable Vue DevTools in production builds - [ ] Verify `developmentMode: false` in production config - [ ] Ensure `window.__container` undefined in production - [ ] Add security headers (CSP, X-Frame-Options) ### Short-Term (Next Sprint) - [ ] Create centralized `SigningService` - [ ] Refactor all prvkey access to use SigningService - [ ] Add audit logging for signing operations (without logging key) - [ ] Implement rate limiting for signing operations ### Long-Term (Roadmap) - [ ] Server-side signing API (browser never sees prvkey) - [ ] Amber signer integration (NIP-46) for user-controlled keys - [ ] Key rotation support - [ ] HSM integration for server-side keys ## Security Testing Checklist - [ ] Vue DevTools disabled in production build - [ ] `window.__container` undefined in production - [ ] XSS penetration testing - [ ] Heap dump analysis for key exposure - [ ] Verify prvkey cleared on logout - [ ] Verify no browser storage persistence ## Risk Matrix | Risk | Likelihood | Impact | Priority | |------|-----------|--------|----------| | DevTools exposure | HIGH (dev) / LOW (prod) | CRITICAL | **P0** | | XSS attack | MEDIUM | CRITICAL | P1 | | Memory inspection | LOW | HIGH | P2 | | Malicious code injection | LOW | CRITICAL | P1 (CSP) | ## References - Full audit document: `misc-docs/SECURITY_AUDIT_PRVKEY.md` - NIP-46 (Amber signer): https://github.com/nostr-protocol/nips/blob/master/46.md - Amber signer: https://github.com/greenart7c3/Amber
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: aiolabs/webapp#11
No description provided.