Summary
Implemented security protection against the "Mike Dilger Attack" in NIP-46 remote signer authentication by requiring secret parameter in all bunker:// URLs.
Background
The Vulnerability
In the signer-initiated flow (bunker://), an attacker monitoring NIP-46 relays could:
- Observe a legitimate
nostrconnect:// request from our app
- Race to send a malicious
bunker:// URL without a secret
- If the user approves the wrong connection, the attacker gains signing access
The Fix
All bunker:// URLs must now include a secret parameter. This is enforced in NostrConnectServiceNDK.js:
// SECURITY: For bunker:// URLs, require a secret to prevent hijacking
if (inputType === 'bunker' && !secret) {
return {
success: false,
error: 'Security: Bunker URL requires a secret parameter',
securityRejection: true,
noSecret: true
};
}
Changes Made
Code
lib/nostr/NostrConnectServiceNDK.js - Added security check (~line 237)
components/auth/NostrConnectModal.js - Added security rejection UI
Tests
- Created
e2e/tests/auth/nip46-security.spec.ts with 11 comprehensive tests:
- Bunker URL security validation (4 tests)
- Console security logging (1 test)
- QR code flow (3 tests)
- Modal UI (3 tests)
Documentation
- Updated
NIP46_PORTAL_INTEGRATION.md with:
- Implementation status (now "Implemented")
- Security measures explanation
- Testing instructions
- Supported signer apps
Testing Results
Manual Testing
- nsec.app - Bunker URL with secret: Working
- Amber - Bunker URL with secret: Security check passed, connection attempted (timed out as expected without app open)
- Portal - Bunker URL with secret: Security check passed, connection attempted
E2E Tests
User Experience
When a bunker URL without a secret is entered, users see:
- "Connection Failed" warning
- "Security Protection" explanation
- Instructions for getting secure bunker URLs from different signer apps
- "Try Again" button
Compatibility Notes
Relay URL Formatting
Different signers use different formats:
- Amber: Unencoded URLs (
relay=wss://relay.nsec.app/)
- Portal: URL-encoded (
relay=wss%3A%2F%2Frelay.damus.io)
Both formats work correctly with our implementation.
Secret Formats
- Amber: Short hex (6 chars)
- nsec.app: 32-char hex
- Portal: UUID format (36 chars)
All formats are accepted as long as the secret is non-empty.
Related
Summary
Implemented security protection against the "Mike Dilger Attack" in NIP-46 remote signer authentication by requiring
secretparameter in all bunker:// URLs.Background
The Vulnerability
In the signer-initiated flow (bunker://), an attacker monitoring NIP-46 relays could:
nostrconnect://request from our appbunker://URL without a secretThe Fix
All bunker:// URLs must now include a
secretparameter. This is enforced inNostrConnectServiceNDK.js:Changes Made
Code
lib/nostr/NostrConnectServiceNDK.js- Added security check (~line 237)components/auth/NostrConnectModal.js- Added security rejection UITests
e2e/tests/auth/nip46-security.spec.tswith 11 comprehensive tests:Documentation
NIP46_PORTAL_INTEGRATION.mdwith:Testing Results
Manual Testing
E2E Tests
User Experience
When a bunker URL without a secret is entered, users see:
Compatibility Notes
Relay URL Formatting
Different signers use different formats:
relay=wss://relay.nsec.app/)relay=wss%3A%2F%2Frelay.damus.io)Both formats work correctly with our implementation.
Secret Formats
All formats are accepted as long as the secret is non-empty.
Related