@blamejs/blamejs-shop 0.1.37 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/lib/admin.js +205 -42
  3. package/lib/asset-manifest.json +5 -5
  4. package/lib/storefront.js +428 -51
  5. package/lib/vendor/MANIFEST.json +2 -2
  6. package/lib/vendor/blamejs/CHANGELOG.md +12 -0
  7. package/lib/vendor/blamejs/README.md +2 -2
  8. package/lib/vendor/blamejs/SECURITY.md +1 -0
  9. package/lib/vendor/blamejs/api-snapshot.json +2 -2
  10. package/lib/vendor/blamejs/lib/ai-disclosure.js +2 -3
  11. package/lib/vendor/blamejs/lib/archive-gz.js +5 -3
  12. package/lib/vendor/blamejs/lib/archive-read.js +101 -35
  13. package/lib/vendor/blamejs/lib/archive-tar-read.js +86 -31
  14. package/lib/vendor/blamejs/lib/archive-tar.js +2 -3
  15. package/lib/vendor/blamejs/lib/auth/fal.js +12 -0
  16. package/lib/vendor/blamejs/lib/auth/jwt-external.js +15 -11
  17. package/lib/vendor/blamejs/lib/auth/jwt.js +2 -2
  18. package/lib/vendor/blamejs/lib/auth/oauth.js +7 -6
  19. package/lib/vendor/blamejs/lib/auth/oid4vci.js +3 -3
  20. package/lib/vendor/blamejs/lib/auth/saml.js +15 -12
  21. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +3 -3
  22. package/lib/vendor/blamejs/lib/backup/index.js +2 -3
  23. package/lib/vendor/blamejs/lib/calendar.js +9 -2
  24. package/lib/vendor/blamejs/lib/circuit-breaker.js +5 -4
  25. package/lib/vendor/blamejs/lib/cose.js +4 -3
  26. package/lib/vendor/blamejs/lib/crypto-hpke.js +1 -1
  27. package/lib/vendor/blamejs/lib/crypto-oprf.js +2 -2
  28. package/lib/vendor/blamejs/lib/crypto.js +2 -2
  29. package/lib/vendor/blamejs/lib/framework-error.js +2 -1
  30. package/lib/vendor/blamejs/lib/guard-jwt.js +3 -2
  31. package/lib/vendor/blamejs/lib/guard-smtp-command.js +2 -2
  32. package/lib/vendor/blamejs/lib/mail-auth.js +2 -2
  33. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +1 -1
  34. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +7 -7
  35. package/lib/vendor/blamejs/lib/mail-crypto.js +1 -1
  36. package/lib/vendor/blamejs/lib/mail-dav.js +5 -4
  37. package/lib/vendor/blamejs/lib/mail-deploy.js +3 -2
  38. package/lib/vendor/blamejs/lib/mail-server-imap.js +1 -1
  39. package/lib/vendor/blamejs/lib/mail-server-jmap.js +10 -10
  40. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +1 -1
  41. package/lib/vendor/blamejs/lib/mail-server-mx.js +142 -47
  42. package/lib/vendor/blamejs/lib/mail-server-submission.js +6 -5
  43. package/lib/vendor/blamejs/lib/mail-store.js +2 -2
  44. package/lib/vendor/blamejs/lib/mail.js +2 -2
  45. package/lib/vendor/blamejs/lib/mdoc.js +14 -14
  46. package/lib/vendor/blamejs/lib/network-dnssec.js +10 -8
  47. package/lib/vendor/blamejs/lib/network-tls.js +10 -7
  48. package/lib/vendor/blamejs/lib/safe-decompress.js +8 -6
  49. package/lib/vendor/blamejs/lib/safe-ical.js +12 -12
  50. package/lib/vendor/blamejs/lib/safe-mime.js +6 -6
  51. package/lib/vendor/blamejs/lib/safe-sieve.js +1 -1
  52. package/lib/vendor/blamejs/lib/safe-smtp.js +1 -1
  53. package/lib/vendor/blamejs/package.json +1 -1
  54. package/lib/vendor/blamejs/release-notes/v0.13.10.json +44 -0
  55. package/lib/vendor/blamejs/release-notes/v0.13.11.json +27 -0
  56. package/lib/vendor/blamejs/release-notes/v0.13.12.json +36 -0
  57. package/lib/vendor/blamejs/release-notes/v0.13.7.json +27 -0
  58. package/lib/vendor/blamejs/release-notes/v0.13.8.json +27 -0
  59. package/lib/vendor/blamejs/release-notes/v0.13.9.json +27 -0
  60. package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +82 -0
  61. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +4 -4
  62. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +31 -0
  63. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +188 -6
  64. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +26 -0
  65. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +5 -5
  66. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +1 -1
  67. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +166 -1
  68. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-cluster.test.js +25 -18
  69. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +2 -2
  70. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +12 -12
  71. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-exactly-once.test.js +15 -9
  72. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-channels.test.js +0 -6
  73. package/package.json +1 -1
@@ -1008,7 +1008,7 @@ function create(opts) {
1008
1008
  throw new OAuthError("auth-oauth/no-id-token", "verifyIdToken: idToken must be a string");
1009
1009
  }
1010
1010
  var parts = idToken.split(".");
1011
- // CVE-2026-29000 / CVE-2026-22817 / CVE-2026-23993 — mirror
1011
+ // CVE-2026-29000 / CVE-2026-22817 — mirror
1012
1012
  // jwt-external's 5-segment JWE refusal. A 5-segment compact
1013
1013
  // serialization is a JWE (RFC 7516); verifyIdToken is a JWS verifier
1014
1014
  // and a JWE shape reaching here is the confused-deputy class an OP
@@ -1023,7 +1023,7 @@ function create(opts) {
1023
1023
  }); } catch (_e) { /* drop-silent — observability sink */ }
1024
1024
  throw new OAuthError("auth-oauth/jwe-refused",
1025
1025
  "5-segment JWE id_token refused — verifyIdToken only handles JWS " +
1026
- "(CVE-2026-29000 / CVE-2026-23993 / CVE-2026-22817 / CVE-2026-34950 JWE-bypass class)");
1026
+ "(CVE-2026-29000 / CVE-2026-22817 / CVE-2026-34950 JWE-bypass class)");
1027
1027
  }
1028
1028
  if (parts.length !== 3) {
1029
1029
  throw new OAuthError("auth-oauth/malformed-jwt", "ID token does not have 3 parts");
@@ -1039,13 +1039,14 @@ function create(opts) {
1039
1039
  if (!header || typeof header.alg !== "string") {
1040
1040
  throw new OAuthError("auth-oauth/malformed-jwt", "ID token header missing 'alg'");
1041
1041
  }
1042
- // CVE-2026-23993 — refuse unknown alg BEFORE any key resolution.
1042
+ // Alg-allowlist gate (CWE-347 / CWE-757) — refuse unknown alg BEFORE
1043
+ // any key resolution.
1043
1044
  // The acceptedAlgorithms list is the operator's posture; an alg
1044
1045
  // outside it never reaches the JWKS lookup or node:crypto.verify.
1045
1046
  if (acceptedAlgorithms.indexOf(header.alg) === -1) {
1046
1047
  throw new OAuthError("auth-oauth/alg-not-accepted",
1047
1048
  "ID token signed with '" + header.alg + "' which is not in the accepted-algorithm list " +
1048
- "(CVE-2026-23993 — refused before key lookup)");
1049
+ "(alg-allowlist gate — refused before key lookup)");
1049
1050
  }
1050
1051
  // RFC 7515 §4.1.11 — refuse JWS with `crit` header. Every other
1051
1052
  // verifier in the framework (jwt.js, jwt-external.js, dpop.js)
@@ -1344,8 +1345,8 @@ function create(opts) {
1344
1345
  }
1345
1346
  var iss = u.searchParams.get("iss");
1346
1347
  var sid = u.searchParams.get("sid");
1347
- // RFC 0 invariant: `iss` MUST match the configured issuer when
1348
- // present (defends against an attacker-controlled IdP forging a
1348
+ // OpenID Connect Front-Channel Logout 1.0 §3: `iss` MUST match the
1349
+ // configured issuer when present (defends against an attacker-controlled IdP forging a
1349
1350
  // logout for a session at a different IdP). `sid` is required
1350
1351
  // when the RP registered with frontchannel_logout_session_required=true;
1351
1352
  // we surface it either way and let the operator decide.
@@ -108,14 +108,14 @@ function _verifyProofJwt(proofJwt, expectedAud, expectedCNonce, expectedClientId
108
108
  throw new AuthError("auth-oid4vci/wrong-proof-typ",
109
109
  "credential issuance: proof JWT typ must be \"openid4vci-proof+jwt\" (got \"" + header.typ + "\")");
110
110
  }
111
- // CVE-2026-23993 — refuse unknown / unsupported alg BEFORE any
112
- // verify-side work. The supportedAlgs list is the issuer's posture;
111
+ // Alg-allowlist gate (CWE-347 / CWE-757) — refuse unknown / unsupported
112
+ // alg BEFORE any verify-side work. The supportedAlgs list is the issuer's posture;
113
113
  // refusing here mirrors the discipline in oauth.verifyIdToken /
114
114
  // jwt-external.verifyExternal.
115
115
  if (!header.alg || supportedAlgs.indexOf(header.alg) === -1) {
116
116
  throw new AuthError("auth-oid4vci/unsupported-proof-alg",
117
117
  "credential issuance: proof JWT alg \"" + header.alg + "\" not in issuer-supported set " +
118
- "(CVE-2026-23993 — refused before key lookup)");
118
+ "(alg-allowlist gate — refused before key lookup)");
119
119
  }
120
120
  // AUTH-5 / RFC 7515 §4.1.11 — refuse non-empty `crit`. Pre-v0.9.x
121
121
  // silently ignored, letting an attacker-controlled wallet declare
@@ -453,12 +453,14 @@ function create(opts) {
453
453
 
454
454
  // XSW defense — refuse duplicate top-level security-critical
455
455
  // elements. SAML XML signature wrapping (XSW) attacks shuffle
456
- // signed elements alongside unsigned siblings; the parser's
457
- // first-match `_findChild` lookup combined with the signed-
458
- // element-ID check at L479 was vulnerable to a multi-Assertion
459
- // payload where the verifier signed one but the consumer read
460
- // attributes from another. Reject any Response with more than
461
- // one of these structural children (Audit 2026-05-11).
456
+ // signed elements alongside unsigned siblings; a first-match
457
+ // child lookup combined with a signed-element-ID check is
458
+ // vulnerable to a multi-Assertion payload where the verifier
459
+ // signs one element but the consumer reads attributes from
460
+ // another. This is the class behind CVE-2024-45409 (ruby-saml,
461
+ // CVSS 10.0, actively exploited) and CVE-2025-25291/25292
462
+ // (omniauth-saml / ruby-saml namespace-confusion XSW). Reject
463
+ // any Response with more than one of these structural children.
462
464
  var statusChildren = _findAllChildren(root, "Status", SAML_NS.protocol);
463
465
  if (statusChildren.length > 1) {
464
466
  throw new AuthError("auth-saml/duplicate-status",
@@ -1531,9 +1533,10 @@ function create(opts) {
1531
1533
  // http://www.w3.org/2009/xmlenc11#rsa-oaep (XMLEnc 1.1 §5.4.2)
1532
1534
  //
1533
1535
  // AES-CBC content encryption (xmlenc#aes128-cbc / aes256-cbc) is
1534
- // intentionally REFUSED: CVE-2011-1473 + the broader XML-Encryption
1535
- // padding-oracle research (Jager & Somorovsky 2011) demonstrate that
1536
- // CBC mode under XMLEnc is exploitable without per-content MAC.
1536
+ // intentionally REFUSED: the XML-Encryption padding-oracle research
1537
+ // (Jager & Somorovsky, "How to Break XML Encryption", CCS 2011)
1538
+ // demonstrates that CBC mode under XMLEnc is exploitable without per-
1539
+ // content MAC.
1537
1540
  // Operators integrating with IdPs that default to CBC (older ADFS /
1538
1541
  // Azure AD / Okta / Keycloak / OneLogin) MUST switch the IdP's
1539
1542
  // content-encryption setting to AES-128-GCM or AES-256-GCM. The
@@ -1543,7 +1546,7 @@ function create(opts) {
1543
1546
  //
1544
1547
  // SHA-1 anywhere (rsa-oaep-mgf1p with SHA-1 OAEP DigestMethod,
1545
1548
  // xmldsig#sha1 DigestMethod) is also refused — Bleichenbacher /
1546
- // collision risk plus CVE-2023-49141-class advisories outweigh
1549
+ // collision risk plus CVE-2023-49141 class advisories outweigh
1547
1550
  // "interop with stale IdPs". Operators upgrade the IdP's digest
1548
1551
  // algorithm to SHA-256+ rather than relax the framework defense.
1549
1552
  //
@@ -1606,7 +1609,7 @@ function _decryptEncryptedAssertion(encAssertion, spPrivateKeyPem) {
1606
1609
  }
1607
1610
  if (oaepHashName === "sha1") {
1608
1611
  throw new AuthError("auth-saml/encrypted-weak-oaep-digest",
1609
- "EncryptedKey OAEP DigestMethod is SHA-1 — refused (CVE-2023-49141-class). " +
1612
+ "EncryptedKey OAEP DigestMethod is SHA-1 — refused (CVE-2023-49141 class). " +
1610
1613
  "Require SHA-256+ on IdP side.");
1611
1614
  }
1612
1615
  var spKey;
@@ -1710,7 +1713,7 @@ function _decryptEncryptedAssertion(encAssertion, spPrivateKeyPem) {
1710
1713
  "(supported: W3C xmlenc11#aes128-gcm, xmlenc11#aes256-gcm, " +
1711
1714
  "framework-experimental urn:blamejs:experimental:xmlenc:xchacha20-poly1305). " +
1712
1715
  "AES-CBC content encryption is refused — switch the IdP to AES-128-GCM or AES-256-GCM " +
1713
- "(CVE-2011-1473 padding-oracle class).");
1716
+ "(XMLEnc CBC padding-oracle class, Jager & Somorovsky CCS 2011).");
1714
1717
  }
1715
1718
  return clearBytes.toString("utf8");
1716
1719
  }
@@ -441,15 +441,15 @@ async function verify(presentation, opts) {
441
441
  "verify: malformed JWT header: " + e.message);
442
442
  }
443
443
  var alg = headerObj.alg;
444
- // CVE-2026-23993 — refuse unknown / unsupported alg BEFORE any key
445
- // resolution. The shared `_assertAlgKtyMatch` helper repeats this
444
+ // Alg-allowlist gate (CWE-347 / CWE-757) — refuse unknown / unsupported
445
+ // alg BEFORE any key resolution. The shared `_assertAlgKtyMatch` helper repeats this
446
446
  // check after the issuer key is resolved; doing it here too closes
447
447
  // the gap where an issuerKeyResolver with side effects (network
448
448
  // fetch, audit emit) would run even when the alg is unsupported.
449
449
  if (typeof alg !== "string" || SUPPORTED_ALGS.indexOf(alg) === -1) {
450
450
  throw new AuthError("auth-sd-jwt-vc/unsupported-alg",
451
451
  "verify: header alg \"" + alg + "\" not in supported set " +
452
- "(CVE-2026-23993 — refused before key lookup)");
452
+ "(alg-allowlist gate — refused before key lookup)");
453
453
  }
454
454
  // draft-ietf-oauth-sd-jwt-vc §3.1 — typ MUST be `vc+sd-jwt` (or
455
455
  // `dc+sd-jwt` for digital-credential profile). Pre-v0.9.x the absent-
@@ -1028,9 +1028,8 @@ module.exports = {
1028
1028
  * Adapter-driven storage backend. Wraps the bundle directory's file
1029
1029
  * tree into per-file key-value pairs routed through an operator-
1030
1030
  * supplied byte-store adapter so backup bundles can land anywhere
1031
- * that exposes the contract (local fs is the v0.12.7 default; tar
1032
- * folding lands v0.12.8, tar.gz v0.12.9, S3/MinIO/Azure/GCS
1033
- * objectStore v0.12.11).
1031
+ * that exposes the contract: local fs (the default), tar / tar.gz
1032
+ * folding, and S3 / MinIO / Azure / GCS objectStore adapters.
1034
1033
  *
1035
1034
  * The adapter contract (small surface; an `fs` implementation is the
1036
1035
  * default + ships in `lib/backup/_adapter-fs.js`):
@@ -354,7 +354,14 @@ function validate(jsCal) {
354
354
  * // → { "@type":"Event", uid:"a@b", updated:"2026-05-21T10:00:00Z", ... }
355
355
  */
356
356
  function fromIcal(text, opts) {
357
- var ast = safeIcal.parse(text, opts || {});
357
+ // Forward parser options to b.safeIcal.parse. Accept BOTH the
358
+ // documented nested form (`{ safeIcalOpts: { profile, caps, ... } }`)
359
+ // AND the historically-working top-level form (`{ profile: "balanced" }`)
360
+ // so neither caller regresses; the nested form wins on conflict. The
361
+ // `safeIcalOpts` wrapper key itself is stripped before forwarding.
362
+ var icalOpts = Object.assign({}, opts || {}, (opts && opts.safeIcalOpts) || {});
363
+ delete icalOpts.safeIcalOpts;
364
+ var ast = safeIcal.parse(text, icalOpts);
358
365
  var events = (ast && ast.vcalendar && ast.vcalendar.vevent) || [];
359
366
  var todos = (ast && ast.vcalendar && ast.vcalendar.vtodo) || [];
360
367
  var journals = (ast && ast.vcalendar && ast.vcalendar.vjournal) || [];
@@ -515,7 +522,7 @@ function toIcal(jsCal, opts) {
515
522
  * timestamps in the operator's `[from, to]` window. Returns an array
516
523
  * of ISO 8601 UTC strings (`yyyy-mm-ddTHH:MM:SSZ`). Bounded by
517
524
  * `MAX_EXPAND_INSTANCES` (4096) + `MAX_EXPAND_SPAN_MS` (10 years) to
518
- * defend against CVE-2024-39687-class recurrence-bomb expansion.
525
+ * defend against the RRULE recurrence-bomb expansion class.
519
526
  *
520
527
  * v1 supports FREQ=DAILY/WEEKLY/MONTHLY/YEARLY with INTERVAL, COUNT,
521
528
  * UNTIL. BYDAY / BYMONTH / BYMONTHDAY / BYWEEKNO / BYYEARDAY /
@@ -42,10 +42,11 @@ var retryHelper = require("./retry");
42
42
  * with the framework's `create(opts)` vocabulary.
43
43
  *
44
44
  * The `CIRCUIT_OPEN` error code is a pre-v1 artifact — every other
45
- * framework error class uses namespaced codes (`retry/...`). The
46
- * rename is deferred to v0.10 with a deprecation cycle so existing
47
- * operators who match `err.code === "CIRCUIT_OPEN"` aren't broken
48
- * in a patch.
45
+ * framework error class uses namespaced codes (`retry/...`). It is
46
+ * kept through the pre-1.0 line so existing operators who match
47
+ * `err.code === "CIRCUIT_OPEN"` aren't broken in a patch; the rename
48
+ * to a namespaced code lands at v1.0 alongside the namespaced-error
49
+ * sweep, with a deprecation warning shipping a minor ahead.
49
50
  *
50
51
  * @opts
51
52
  * name: string, // identifier used in audit + state-change events
@@ -41,9 +41,10 @@
41
41
  * 2) listing a header label the verifier does not understand is
42
42
  * refused (RFC 9052 §3.1) — a crit-bypass defense.
43
43
  *
44
- * v1 ships COSE_Sign1 (single-signer) with an attached payload.
45
- * Detached payload, COSE_Sign (multi-signer), COSE_Mac0, and
46
- * COSE_Encrypt are deferred-with-condition (operator demand).
44
+ * Ships COSE_Sign1 (single-signer, attached payload), COSE_Mac0, and
45
+ * COSE_Encrypt0 (single-recipient AEAD). Detached payload, COSE_Sign
46
+ * (multi-signer), and COSE_Encrypt (multi-recipient) are
47
+ * deferred-with-condition (operator demand).
47
48
  *
48
49
  * @card
49
50
  * COSE_Sign1 sign / verify (RFC 9052) over the in-tree CBOR codec —
@@ -5,7 +5,7 @@
5
5
  * Suite (PQC-first per framework crypto policy):
6
6
  * KEM: ML-KEM-1024 (FIPS 203) — post-quantum encapsulation
7
7
  * KDF: HKDF-SHA3-512
8
- * AEAD: ChaCha20-Poly1305 (RFC 7539)
8
+ * AEAD: ChaCha20-Poly1305 (RFC 8439, obsoletes RFC 7539)
9
9
  *
10
10
  * The classical HPKE suites in RFC 9180 §7 (DHKEM with X25519 / P-256 /
11
11
  * P-384 / P-521 + HKDF-SHA256/384/512 + AES-GCM/ChaCha20) are NOT
@@ -30,14 +30,14 @@
30
30
  * <code>suite(name)</code> returns the suite for one of the RFC 9497
31
31
  * ciphersuites — <code>ristretto255-sha512</code> (the Privacy Pass
32
32
  * default), <code>p256-sha256</code>, <code>p384-sha384</code>, or
33
- * <code>p521-sha512</code> — each exposing the three modes. Group and
33
+ * <code>p521-sha512</code> — each exposing both shipped modes. Group and
34
34
  * hash-to-curve operations come from the vendored <code>@noble/curves</code>.
35
35
  * Byte arguments are <code>Uint8Array</code> / <code>Buffer</code>;
36
36
  * returned elements and outputs are <code>Uint8Array</code>.
37
37
  *
38
38
  * @card
39
39
  * RFC 9497 Oblivious PRFs — learn <code>F(key, input)</code> without the
40
- * server seeing the input (oprf / voprf / poprf modes; ristretto255 / P-256
40
+ * server seeing the input (oprf / voprf modes; ristretto255 / P-256
41
41
  * / P-384 / P-521 suites). The primitive behind Privacy Pass, password
42
42
  * hardening, and private set intersection.
43
43
  */
@@ -789,7 +789,7 @@ function toBase64Url(buf) {
789
789
  *
790
790
  * Strict mode (default) refuses non-canonical input — chars outside
791
791
  * the RFC 4648 §5 alphabet, length-mod-4-of-1, mixed `+/` from
792
- * standard base64, trailing garbage. Defends a CVE-2022-0235-class
792
+ * standard base64, trailing garbage. Defends a CVE-2022-0235 class
793
793
  * footgun where Node's permissive decoder silently tolerated
794
794
  * tampered JWT signatures. Operators with a documented lossy legacy
795
795
  * payload opt out per call via `{ strict: false }`.
@@ -817,7 +817,7 @@ function fromBase64Url(s, opts) {
817
817
  // OAuth `state` round-tripping) MUST reject non-canonical / malformed
818
818
  // input. The Node base64url decoder silently tolerates trailing
819
819
  // garbage, mixed `+/` from standard base64, missing padding errors,
820
- // and length-mod-4 shapes — CVE-2022-0235-class footgun. Strict mode
820
+ // and length-mod-4 shapes — CVE-2022-0235 class footgun. Strict mode
821
821
  // (the default) refuses anything outside the RFC 4648 §5 alphabet +
822
822
  // length rules. Operators with a known-lossy legacy payload pass
823
823
  // `{ strict: false }` to opt out per call.
@@ -290,7 +290,8 @@ var GuardTimeError = defineClass("GuardTimeError", { alwaysPermane
290
290
  var GuardMimeError = defineClass("GuardMimeError", { alwaysPermanent: true });
291
291
  // GuardJwtError covers JWT identifier violations: shape malformation
292
292
  // (not 3 base64url segments), alg=none refuse (canonical CVE-class —
293
- // CVE-2015-9235 jsonwebtoken / CVE-2018-0114 java-jwt), alg-allowlist
293
+ // CVE-2015-9235 jsonwebtoken alg:none / CVE-2018-0114 Cisco node-jose
294
+ // embedded-JWK key confusion), alg-allowlist
294
295
  // drift, kid path-traversal (operator keyResolver path-injection
295
296
  // class), typ confusion, oversized header / payload / signature,
296
297
  // exp / nbf / iat sanity, missing required claims, unknown crit
@@ -16,8 +16,9 @@
16
16
  *
17
17
  * Algorithm-confusion defense: `alg=none` is universally refused
18
18
  * at every profile (RFC 7518 §3.6 explicit-no-signature, the
19
- * canonical CVE-2015-9235 jsonwebtoken / CVE-2018-0114 java-jwt
20
- * class). The operator-supplied `allowedAlgs` allowlist defaults
19
+ * canonical CVE-2015-9235 jsonwebtoken alg:none / CVE-2018-0114
20
+ * Cisco node-jose embedded-JWK confusion class). The
21
+ * operator-supplied `allowedAlgs` allowlist defaults
21
22
  * to the framework's PQC-first set (ML-DSA-87 / ML-DSA-65 /
22
23
  * ML-DSA-44 / SLH-DSA-SHAKE-256{f,s} / SLH-DSA-SHA2-256{f,s} /
23
24
  * EdDSA / ES* / RS* / PS*) so HS256-against-RSA-public-key
@@ -493,7 +493,7 @@ function gate(opts) {
493
493
  *
494
494
  * Scan a DATA-body byte buffer for the SMTP smuggling shape per
495
495
  * CVE-2023-51764 (Postfix), CVE-2023-51765 (Sendmail), CVE-2023-51766
496
- * (Exim), CVE-2024-32178 (.NET System.Net.Mail). RFC 5321 §2.3.8
496
+ * (Exim). RFC 5321 §2.3.8
497
497
  * mandates canonical CRLF line termination; the smuggling exploit
498
498
  * relies on parsers that accept `\n.\n` (bare LF before / after the
499
499
  * dot) as an alternate body terminator and then resume parsing the
@@ -517,7 +517,7 @@ function detectBodySmuggling(buf) {
517
517
  throw new GuardSmtpCommandError("guard-smtp-command/bad-input",
518
518
  "detectBodySmuggling: input must be a Buffer");
519
519
  }
520
- // The CVE-2023-51764 / 51765 / 51766 / 2024-32178 class is any
520
+ // The CVE-2023-51764 / 51765 / 51766 class is any
521
521
  // dot-line whose line boundary is anything OTHER than canonical
522
522
  // \r\n on BOTH sides of the dot. The canonical-and-only terminator
523
523
  // is `\r\n.\r\n`. Every other shape that some receiver might honor
@@ -1858,8 +1858,8 @@ function dmarcParseAggregateReport(input, opts) {
1858
1858
  // "stream is malformed" (operator-level diagnostic) so audit/
1859
1859
  // alert wiring can react differently. Node surfaces the bomb
1860
1860
  // case with ERR_BUFFER_TOO_LARGE / "Output length exceeded the
1861
- // limit" / the explicit `maxOutputLength` code. CVE-class:
1862
- // CVE-2024-zlib decompression amplification.
1861
+ // limit" / the explicit `maxOutputLength` code. Defends the
1862
+ // decompression-amplification class (CWE-409 / CVE-2025-0725).
1863
1863
  var msg = (e && e.message) || String(e);
1864
1864
  var isBomb = (e && (e.code === "ERR_BUFFER_TOO_LARGE" ||
1865
1865
  e.code === "ERR_OUT_OF_RANGE")) ||
@@ -663,7 +663,7 @@ function _parseSignaturePacket(packetBytes) {
663
663
  if (hashAlg !== HASH_ALG_SHA256 && hashAlg !== HASH_ALG_SHA512) {
664
664
  throw new MailCryptoError("mail-crypto/pgp/bad-hash",
665
665
  "hash alg " + hashAlg + " refused; only SHA-256 (8) and SHA-512 (10) are accepted. " +
666
- "SHA-1 (id=2) refused per SHAttered (CVE-2017-9006-class).");
666
+ "SHA-1 (id=2) refused per SHAttered (2017 SHA-1 collision).");
667
667
  }
668
668
  var hashedSubLen = body.readUInt16BE(4);
669
669
  if (6 + hashedSubLen > body.length) {
@@ -21,9 +21,9 @@
21
21
  * second part as base64-encoded DER.
22
22
  *
23
23
  * Posture (when the surface lights up):
24
- * - Refuses SHA-1 as the signature hash (CVE-2017-9006-class
25
- * PKCS#7 collision attacks against legacy S/MIME) and as the
26
- * certificate signature algorithm.
24
+ * - Refuses SHA-1 as the signature hash (SHAttered, 2017 — practical
25
+ * SHA-1 collision; RFC 8551 §2.5 mandates SHA-256+ for S/MIME) and
26
+ * as the certificate signature algorithm.
27
27
  * - Refuses RSA keys < 2048 bits (RFC 8301 §3.1 — same posture
28
28
  * as the rest of the mail surface).
29
29
  * - Refuses MD5 anywhere (the historical S/MIME-v2 default; long
@@ -87,8 +87,8 @@
87
87
  * CVE citations:
88
88
  * - CVE-2017-17688 / CVE-2017-17689 (EFAIL — S/MIME variant; informs
89
89
  * the encrypt+decrypt deferral when that surface lights up)
90
- * - CVE-2017-9006 (PKCS#7 / S/MIME signature-validation bypass
91
- * classinforms the SHA-1 refusal posture)
90
+ * - SHAttered (2017 practical SHA-1 collision) + RFC 8551 §2.5 (SHA-256
91
+ * floor for S/MIME) inform the SHA-1 signature-hash refusal posture
92
92
  * - CVE-2018-5407 (PortSmash — informs the side-channel hardening
93
93
  * posture when private operations land in v2)
94
94
  */
@@ -109,7 +109,7 @@ var MailCryptoError = defineClass("MailCryptoError", { alwaysPermanent: true });
109
109
  // hand-copying strings. These reflect RFC 8551 §2.5 + RFC 8301 floors.
110
110
  var RSA_MIN_BITS = 2048; // allow:raw-byte-literal — RFC 8301 §3.1
111
111
  var ALLOWED_HASHES = ["sha256", "sha384", "sha512"];
112
- var REFUSED_HASHES = ["md5", "sha1"]; // allow:raw-byte-literal — CVE-2017-9006-class
112
+ var REFUSED_HASHES = ["md5", "sha1"]; // allow:raw-byte-literal — SHAttered / RFC 8551 §2.5
113
113
 
114
114
  // PROFILES + COMPLIANCE_POSTURES — the framework's standard cross-
115
115
  // primitive contract. sign() and verify() (live since v0.10.16) read
@@ -708,7 +708,7 @@ function checkCert(opts) {
708
708
  throw new MailCryptoError("mail-crypto/smime/refused-hash",
709
709
  "cert signature algorithm '" + sigAlgName +
710
710
  "' refused — SHA-1 / MD5 in cert signatures is forbidden " +
711
- "(CVE-2017-9006-class). Acceptable hashes: " + ALLOWED_HASHES.join(", "));
711
+ "(SHAttered SHA-1 collision; RFC 8551 §2.5). Acceptable hashes: " + ALLOWED_HASHES.join(", "));
712
712
  }
713
713
  }
714
714
 
@@ -62,7 +62,7 @@
62
62
  *
63
63
  * CVE citations:
64
64
  * - CVE-2017-17688 / CVE-2017-17689 (EFAIL)
65
- * - CVE-2017-9006 (PKCS#7 / S/MIME signature-validation bypass class)
65
+ * - SHAttered (2017 SHA-1 collision) + RFC 8551 §2.5 — SHA-1 signature-hash refusal
66
66
  */
67
67
 
68
68
  var pgp = require("./mail-crypto-pgp");
@@ -112,8 +112,9 @@
112
112
  * ## CVE defense composition
113
113
  *
114
114
  * - `b.safeIcal` rejects RRULE COUNT > 10000 / BYxxx list > 24 →
115
- * defends CVE-2024-39687 (ical4j RRULE recursion / Outlook
116
- * calendar bomb) on the PUT path.
115
+ * defends the ical4j RRULE-recursion / recurrence-expansion DoS
116
+ * class (unbounded RRULE expansion exhausts CPU/memory) on the
117
+ * PUT path.
117
118
  * - `b.xmlC14n.parse` rejects DOCTYPE / ENTITY in the
118
119
  * PROPFIND / REPORT body → defends XXE / billion-laughs on the
119
120
  * query path.
@@ -125,7 +126,7 @@
125
126
  * mount under their HTTP router. Composes b.safeIcal / b.safeVcard
126
127
  * for PUT-body validation, b.xmlC14n.parse for PROPFIND / REPORT
127
128
  * bodies. Per-principal URL isolation; operator-supplied storage
128
- * backend. Defends CVE-2024-39687 at the PUT boundary.
129
+ * backend. Defends the RRULE-recursion expansion-DoS class at the PUT boundary.
129
130
  */
130
131
 
131
132
  var lazyRequire = require("./lazy-require");
@@ -749,7 +750,7 @@ function create(opts) {
749
750
  return _refuseStatus(res, 400, "PUT requires a component path");
750
751
  }
751
752
  var bodyBuf = await _readBodyBytes(req);
752
- // Validate iCal body via safeIcal — defends CVE-2024-39687 at the
753
+ // Validate iCal body via safeIcal — defends the RRULE-recursion expansion-DoS class at the
753
754
  // ingest boundary.
754
755
  try {
755
756
  safeIcal.parse(bodyBuf, {
@@ -527,8 +527,9 @@ function autoDiscoverXml(opts) {
527
527
  // brotli or the in-progress UTA-draft requires it.
528
528
 
529
529
  // Hard caps — defensive against CVE-2025-0725 (libcurl/zlib
530
- // integer overflow), CVE-2024-zlib decompression amplification, and
531
- // the §5.2 community ceiling (receivers commonly cap at 10 MiB).
530
+ // integer overflow) and the decompression-amplification class
531
+ // (CWE-409), plus the §5.2 community ceiling (receivers commonly cap
532
+ // at 10 MiB).
532
533
  var TLSRPT_MAX_COMPRESSED_BYTES = C.BYTES.mib(4); // allow:raw-byte-literal — 4 MiB compressed cap per §5.2 community practice
533
534
  var TLSRPT_MAX_DECOMPRESSED_BYTES = C.BYTES.mib(32); // allow:raw-byte-literal — 32 MiB decompressed cap (operators override via opts)
534
535
  var TLSRPT_MAX_RATIO = 50; // allow:raw-byte-literal — 50:1 compression ratio refusal
@@ -53,7 +53,7 @@
53
53
  * pipelined command queued before TLS is refused with
54
54
  * `BAD Pipelined post-STARTTLS not permitted`.
55
55
  *
56
- * - **Literal-injection (CVE-2018-19518 INC IMAP class)** —
56
+ * - **Literal-injection / command-continuation smuggling** —
57
57
  * `{n}` literal continuation MUST come on a line of its own
58
58
  * (per `b.guardImapCommand.detectLiteralSmuggling`); oversize
59
59
  * literals refused (default 64 MiB); LITERAL+ (RFC 7888) non-
@@ -95,18 +95,18 @@
95
95
  * - `urn:ietf:params:jmap:error:accountNotFound`
96
96
  * - `urn:ietf:params:jmap:error:serverFail` (opaque last-resort)
97
97
  *
98
+ * ## Beyond Core + Mail, this also ships
99
+ *
100
+ * - **Push channel (RFC 8887)** — `eventSourceHandler` (SSE) and
101
+ * `webSocketHandler` (WebSocket, with `StateChange` push).
102
+ * - **Blob upload/download (RFC 8620 §6)** — `uploadHandler` /
103
+ * `downloadHandler`, routing uploads through the guard-* family.
104
+ * - **EmailSubmission/set (RFC 8621 §7.5)** — `emailSubmissionSetHandler`,
105
+ * composing `b.mail.send.deliver`.
106
+ *
98
107
  * ## What v1 does NOT ship
99
108
  *
100
- * - **Push channel (SSE + WebSocket per RFC 8887)** — operator wires
101
- * `b.sse` or `b.websocket` to the `pushSubscribe` hook. v1.5
102
- * bundles a turnkey push handler.
103
- * - **Blob upload/download endpoints** — operator wires their own
104
- * `/jmap/upload` / `/jmap/download` handlers; the framework
105
- * supplies `b.storage` + `b.objectStore` + the guard-* family
106
- * for the actual upload path.
107
- * - **EmailSubmission (RFC 8621 §7)** — operator wires the bridge
108
- * to `b.mail.server.submission`'s outbound agent.
109
- * - **Calendars / Contacts (RFC 9610)**, **Sieve (RFC 9404)**,
109
+ * - **Calendars / Contacts (RFC 9610)**, **Sieve (RFC 9661)**,
110
110
  * **MDN (RFC 9007)** — opt-in capabilities.
111
111
  *
112
112
  * @card
@@ -95,7 +95,7 @@
95
95
  *
96
96
  * - **CHECKSCRIPT** (RFC 5804 §2.12) — parse-only verb. Operators
97
97
  * who want it compose `b.safeSieve.validate` directly via JMAP
98
- * `SieveScript/validate` (RFC 9404). The MTA-side ManageSieve
98
+ * `SieveScript/validate` (RFC 9661). The MTA-side ManageSieve
99
99
  * surface is `PUTSCRIPT` + `HAVESPACE`; CHECKSCRIPT adds a third
100
100
  * entry point with no operator demand yet.
101
101
  * - **UNAUTHENTICATE** (RFC 5804 §2.14) — exotic. Operators close