Encrypt Web Push subscriptions at rest #1108

Closed
opened 2026-08-19 02:20:31 +00:00 by timmy · 0 comments
Owner

Problem

push-subscriptions.sqlite3 currently persists Web Push endpoint capability URLs plus p256dh and auth credentials as plaintext. Owner-only file permissions do not protect copied volumes or backups, while other sensitive state already uses application-layer authenticated encryption.

Vertical slice

Encrypt each subscription payload with AES-256-GCM under an independently injected key, use a keyed blind index for endpoint uniqueness, and migrate legacy plaintext rows atomically without changing reminder/delivery semantics. Push-disabled deployments must still start without the key; push-enabled deployments must fail closed if the key is absent or invalid.

Acceptance tests

  • New databases contain no endpoint, p256dh, or auth canaries in SQLite or sidecars.
  • Same-key restarts preserve subscription lookup, replacement, preferences, leases, and dispatch.
  • Legacy plaintext rows migrate without resetting delivery checkpoints or reminder schedules.
  • Wrong-key, tampered, or cross-session-swapped ciphertext fails closed and cannot trigger delivery.
  • Endpoint uniqueness remains efficient through a keyed blind index.
  • Focused tests and full suite pass.

Non-duplication evidence

All 556 historical issue titles and recent commits were checked. #1096 covers Web Push DNS-rebinding/connection pinning; #1098/#1100 cover Draft encryption; #1106 covers worker-shared snapshot encryption. None protects persisted Web Push subscription credentials.

## Problem `push-subscriptions.sqlite3` currently persists Web Push endpoint capability URLs plus `p256dh` and `auth` credentials as plaintext. Owner-only file permissions do not protect copied volumes or backups, while other sensitive state already uses application-layer authenticated encryption. ## Vertical slice Encrypt each subscription payload with AES-256-GCM under an independently injected key, use a keyed blind index for endpoint uniqueness, and migrate legacy plaintext rows atomically without changing reminder/delivery semantics. Push-disabled deployments must still start without the key; push-enabled deployments must fail closed if the key is absent or invalid. ## Acceptance tests - New databases contain no endpoint, `p256dh`, or `auth` canaries in SQLite or sidecars. - Same-key restarts preserve subscription lookup, replacement, preferences, leases, and dispatch. - Legacy plaintext rows migrate without resetting delivery checkpoints or reminder schedules. - Wrong-key, tampered, or cross-session-swapped ciphertext fails closed and cannot trigger delivery. - Endpoint uniqueness remains efficient through a keyed blind index. - Focused tests and full suite pass. ## Non-duplication evidence All 556 historical issue titles and recent commits were checked. #1096 covers Web Push DNS-rebinding/connection pinning; #1098/#1100 cover Draft encryption; #1106 covers worker-shared snapshot encryption. None protects persisted Web Push subscription credentials.
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
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: stackchain/stackchain-dashboard#1108
No description provided.