65263d57b9a4

fix: preserve legacy trustSource and bound sync request IDs before crypto (PB-26-111, PB-26-116, v5.0.39)

time
2026-09-01 22:19 UTC · 1 month ago
machine
koh2
agent
claude-opus-5
session
2026-09-01 security assessment remediation
parent
6dfff89fba08
6 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/sync-coordinator.ts+6 −0src/background/sync-vault-adapter.ts+1 −1src/shared/sync-limits.ts+3 −1
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach Password Manager",4-  "version": "5.0.38",4+  "version": "5.0.39",55   "description": "Zero-knowledge password manager",66   "browser_specific_settings": {77     "gecko": {

view file

manifest.json+1 −1
@@ -2,7 +2,7 @@22   "manifest_version": 3,33   "minimum_chrome_version": "116",44   "name": "Peach Password Manager",5-  "version": "5.0.38",5+  "version": "5.0.39",66   "description": "Zero-knowledge password manager",77   "action": {88     "default_popup": "src/popup/index.html",

view file

package.json+1 −1
@@ -1,6 +1,6 @@11 {22   "name": "peach",3-  "version": "5.0.38",3+  "version": "5.0.39",44   "description": "Zero-knowledge password manager",55   "license": "GPL-3.0-only",66   "type": "module",

view file

src/background/sync-coordinator.ts+6 −0
@@ -214,6 +214,9 @@214214     if (requestIn.type !== "SYNC_REQUEST") {215215       return errorOutcome(result, `expected SYNC_REQUEST, got ${requestIn.type}`);216216     }217+    if (requestIn.entryIds.length > SYNC_LIMITS.MAX_REQUEST_ENTRY_COUNT) {218+      return errorOutcome(result, "sync request entry count exceeds limit");219+    }217220     // Sanity: the peer's request must be a subset of what its manifest218221     // declared as newer. A malformed/over-eager request is a protocol219222     // violation but not a data-safety problem — we just send what they ask.@@ -405,6 +408,9 @@405408     const requestIn = await receiveMessage(session, timer);406409     if (requestIn.type !== "SYNC_REQUEST") {407410       return errorOutcome(result, `expected SYNC_REQUEST, got ${requestIn.type}`);411+    }412+    if (requestIn.entryIds.length > SYNC_LIMITS.MAX_REQUEST_ENTRY_COUNT) {413+      return errorOutcome(result, "sync request entry count exceeds limit");408414     }409415     const wantFromPeer = diffNewer(manifestIn.entries, ourEntries);410416     await sendMessage(session, { type: "SYNC_REQUEST", entryIds: wantFromPeer });

view file

src/background/sync-vault-adapter.ts+1 −1
@@ -471,7 +471,7 @@471471         longTermPublicKeyHex: entry.longTermPublicKeyHex.toLowerCase(),472472         signingPublicKeyHex: entry.signingPublicKeyHex.toLowerCase(),473473         pairedAt: existing.pairedAt ?? entry.pairedAt,474-        trustSource: existing.trustSource ?? "direct",474+        trustSource: existing.trustSource,475475         wsPort: existing.wsPort ?? entry.wsPort,476476         rendezvousSecretHex:477477           existing.trustSource === "vouched" && meshRoute

view file

src/shared/sync-limits.ts+3 −1
@@ -75,8 +75,10 @@7575    * above 32 MiB; 24 MiB leaves transport overhead and platform margin.7676    */7777   MAX_FRAME_BYTES: 24 * 1024 * 1024, // 24 MiB78-  /** Max entries accepted in one SYNC_ENTRIES / manifest payload. */78+  /** Max entries accepted in one SYNC_ENTRIES / manifest / request payload. */7979   MAX_ENTRY_COUNT: 100_000,80+  /** Max IDs a peer may request before per-entry crypto work begins. */81+  MAX_REQUEST_ENTRY_COUNT: 100_000,8082   /** Max plaintext size of one decrypted entry envelope. */8183   MAX_ENTRY_PLAINTEXT_BYTES: 512 * 1024, // 512 KiB8284   /** Max tombstones accepted in one SYNC_TOMBSTONES payload. */

view file