{"id":"GHSA-76mc-f452-cxcm","revision":null,"records":[{"revision":"666bebbbd77649aeabd6ec03d9a07e5f","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-65902","aliases":[],"title":"DOMPurify before 3.4.7 Hook Mutation Pollution via allowedTags","description":"DOMPurify before 3.4.7 (affected versions <= 3.4.5) passes direct references to the module-level DEFAULT_ALLOWED_TAGS and DEFAULT_ALLOWED_ATTR sets to the uponSanitizeElement and uponSanitizeAttribute hooks via data.allowedTags / data.allowedAttributes when sanitize is called without an explicit cfg.ALLOWED_TAGS / cfg.ALLOWED_ATTR array. A hook that mutates these fields permanently widens the default allow-lists for the lifetime of the DOMPurify instance, so all subsequent default-config sanitize calls inherit the widened defaults and attacker payloads using the poisoned tag/attribute name survive sanitization. removeAllHooks(), clearConfig(), and passing a fresh cfg do not recover the state; only constructing a new DOMPurify instance does.","state":0,"publishedAt":"2026-07-23T13:16:20.528+00:00","modifiedAt":"2026-07-24T21:35:25.085+00:00","affected":[{"ecosystem":"Vendor product","name":"DOMPurify","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"cure53\",\n                    \"product\": \"DOMPurify\",\n                    \"defaultStatus\": \"unaffected\",\n                    \"packageURL\": \"pkg:npm/dompurify\",\n                    \"versions\": [\n                        {\n                            \"version\": \"0\",\n                            \"status\": \"affected\",\n                            \"versionType\": \"semver\",\n                            \"lessThan\": \"3.4.7\"\n                        },\n                        {\n                            \"version\": \"3.4.7\",\n                            \"status\": \"unaffected\",\n                            \"versionType\": \"semver\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 4.0","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N","score":5.3,"severity":"MEDIUM"},{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N","score":6.1,"severity":"MEDIUM"}],"references":["https://github.com/cure53/DOMPurify/security/advisories/GHSA-76mc-f452-cxcm","https://github.com/cure53/DOMPurify/commit/7996f1dc78eb8b7922388aed75d94a9f8fad9a36","https://www.vulncheck.com/advisories/dompurify-before-hook-mutation-pollution-via-allowedtags"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-65902","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-65902","identifiers":["CVE-2026-65902"]},"retained":false,"historicalAffected":[]},{"revision":"b0d69ee0405e4ecea549139cea8a1e39","observedAt":"2026-10-25T15:18:51.467+00:00","statement":{"source":"nvd","id":"CVE-2026-65902","aliases":[],"title":"DOMPurify before 3.4.7 (affected versions <= 3.4.5) passes direct references to the module-level DEFAULT_ALLOWED_TAGS and DEFAULT_ALLOWED_ATTR sets to the uponSanitizeElement and uponSanitizeAttribute hooks via data.allowedTags / data.allow…","description":"DOMPurify before 3.4.7 (affected versions <= 3.4.5) passes direct references to the module-level DEFAULT_ALLOWED_TAGS and DEFAULT_ALLOWED_ATTR sets to the uponSanitizeElement and uponSanitizeAttribute hooks via data.allowedTags / data.allowedAttributes when sanitize is called without an explicit cfg.ALLOWED_TAGS / cfg.ALLOWED_ATTR array. A hook that mutates these fields permanently widens the default allow-lists for the lifetime of the DOMPurify instance, so all subsequent default-config sanitize calls inherit the widened defaults and attacker payloads using the poisoned tag/attribute name survive sanitization. removeAllHooks(), clearConfig(), and passing a fresh cfg do not recover the state; only constructing a new DOMPurify instance does.","state":0,"publishedAt":"2026-07-23T14:18:05.453+00:00","modifiedAt":"2026-10-24T13:10:00.147+00:00","affected":[],"metrics":[{"system":"CVSS 4.0 · disclosure@vulncheck.com · Secondary","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","score":5.3,"severity":"MEDIUM"},{"system":"CVSS 3.1 · disclosure@vulncheck.com · Primary","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N","score":6.1,"severity":"MEDIUM"}],"references":["https://github.com/cure53/DOMPurify/commit/7996f1dc78eb8b7922388aed75d94a9f8fad9a36","https://github.com/cure53/DOMPurify/security/advisories/GHSA-76mc-f452-cxcm","https://www.vulncheck.com/advisories/dompurify-before-hook-mutation-pollution-via-allowedtags"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-65902","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Analyzed","weaknesses":["CWE-501"],"productCriteria":["cpe:2.3:a:cure53:dompurify:*:*:*:*:*:*:*:*"],"sourceDates":{"published":"2026-07-23T14:18:05.453","lastModified":"2026-10-24T13:10:00.147"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-65902","identifiers":["CVE-2026-65902"]},"retained":false,"historicalAffected":[]},{"revision":"06ba76c58fe04c87a7aab13fa173a840","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-76mc-f452-cxcm","aliases":["CVE-2026-65902"],"title":"DOMPurify: Hook mutation of `data.allowedTags` / `data.allowedAttributes` permanently pollutes `DEFAULT_ALLOWED_TAGS` / `DEFAULT_ALLOWED_ATTR`","description":"# Hook mutation of `data.allowedTags` / `data.allowedAttributes` permanently pollutes `DEFAULT_ALLOWED_TAGS` / `DEFAULT_ALLOWED_ATTR`\n\n**CWE**: CWE-501 (Trust Boundary Violation — hook-scoped mutation leaks to global default sets) via CWE-693 (Protection Mechanism Failure — the default allow-list is silently widened for all subsequent sanitize calls)\n\n## Summary\n\nThe `data.allowedTags` and `data.allowedAttributes` fields passed to `uponSanitizeElement` and `uponSanitizeAttribute` hooks are **direct references** to the library's live `ALLOWED_TAGS` / `ALLOWED_ATTR` sets. For sanitize calls that don't supply an explicit `cfg.ALLOWED_TAGS` / `cfg.ALLOWED_ATTR` array, those live sets are themselves direct references to the module-level `DEFAULT_ALLOWED_TAGS` / `DEFAULT_ALLOWED_ATTR` constants. A hook that mutates these fields — a natural-looking pattern for \"allow `X` for this iteration\" — permanently writes new entries into the default constants for the DOMPurify instance's lifetime. Every subsequent sanitize call that doesn't override the config inherits the widened defaults, so an attacker payload that uses the poisoned tag/attribute name survives sanitization. `removeAllHooks()`, `clearConfig()`, and even passing a fresh `cfg: {}` do not recover; only constructing a new DOMPurify instance does.\n\nThe maintainer's existing defense at `src/purify.ts:696-700` explicitly clones `DEFAULT_ALLOWED_TAGS` before mutating it via `cfg.ADD_TAGS` (array form), demonstrating awareness of this exact class. The hook path remained uncovered.\n\n## Affected\n\n- DOMPurify ≤ 3.4.5, including `main` at `7996f1dc78eb8b7922388aed75d94a9f8fad9a36`\n- Any application that installs a hook on `uponSanitizeElement` or `uponSanitizeAttribute` that writes to `data.allowedTags[...] = true` or `data.allowedAttributes[...] = true` and later sanitizes attacker-influenced content with default config (no explicit `cfg.ALLOWED_TAGS` / `cfg.ALLOWED_ATTR` array)\n\n## Vulnerability details\n\n### [A] — `data.allowedTags` is a reference to `ALLOWED_TAGS`\n\n`src/purify.ts:1206-1209`:\n\n```ts\n_executeHooks(hooks.uponSanitizeElement, currentNode, {\n  tagName,\n  allowedTags: ALLOWED_TAGS,         // [A] direct reference; hook mutation\n                                      //     mutates the very ALLOWED_TAGS the\n                                      //     library checks on the next element\n});\n```\n\n`src/purify.ts:1494-1500` (the matching attribute hook):\n\n```ts\nconst hookEvent = {\n  attrName: '',\n  attrValue: '',\n  keepAttr: true,\n  allowedAttributes: ALLOWED_ATTR,    // [A'] same pattern\n  forceKeepAttr: undefined,\n};\n```\n\n### [B] — `ALLOWED_TAGS = DEFAULT_ALLOWED_TAGS` for default-cfg sanitize calls\n\n`src/purify.ts:527-531`:\n\n```ts\nALLOWED_TAGS =\n  objectHasOwnProperty(cfg, 'ALLOWED_TAGS') &&\n  arrayIsArray(cfg.ALLOWED_TAGS)\n    ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc)\n    : DEFAULT_ALLOWED_TAGS;            // [B] reference assignment; ALLOWED_TAGS\n                                       //     IS the DEFAULT_ALLOWED_TAGS object\n```\n\n(The `ALLOWED_ATTR = DEFAULT_ALLOWED_ATTR` path at `:532-536` is symmetric.)\n\n### The mismatch\n\nA hook author who writes `data.allowedTags['script'] = true` reasonably expects per-call scope — the API name is *\"data\"*, suggesting per-event payload. But [A] makes this a direct reference, and [B] makes that reference equal to the module-level default for the common default-cfg path. The hook's mutation therefore writes to a *constant* that every subsequent default-cfg sanitize call rebinds to.\n\nThe maintainer already recognized this class for the `ADD_TAGS` array path — `src/purify.ts:696-700`:\n\n```ts\n} else if (arrayIsArray(cfg.ADD_TAGS)) {\n  if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n    ALLOWED_TAGS = clone(ALLOWED_TAGS);   // explicitly clone DEFAULT before\n                                          // mutating to avoid this pollution\n  }\n  addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n}\n```\n\nThe same defensive clone is missing from the hook code paths.\n\n## Proof of concept\n\n```js\n// 1) fresh DOMPurify, default config — script is blocked\nDOMPurify.sanitize('<svg><script>alert(1)</script></svg>');\n// → \"<svg></svg>\"\n\n// 2) install a hook that mutates data.allowedTags (natural-looking pattern)\nDOMPurify.addHook('uponSanitizeElement', (node, data) => {\n  data.allowedTags['script'] = true;\n});\n\n// 3) one sanitize call WITH the hook — script survives (expected during the hook)\nDOMPurify.sanitize('<svg><script>alert(1)</script></svg>');\n// → \"<svg><script>alert(1)</script></svg>\"\n\n// 4) remove the hook\nDOMPurify.removeAllHooks();\nDOMPurify.clearConfig();\n\n// 5) sanitize attacker content with default config — POLLUTION PERSISTS\nDOMPurify.sanitize('<svg><script>alert(1)</script></svg>');\n// → \"<svg><script>alert(1)</script></svg>\"  ← script survived without any hook\n\n// 6) the only recovery: create a fresh DOMPurify instance\nconst fresh = DOMPurify(window);\nfresh.sanitize('<svg><script>alert(1)</script></svg>');\n// → \"<svg></svg>\"  ← clean\n```\n\nObserved (Chromium 148.0.7778.96, DOMPurify HEAD `7996f1d`):\n\n| step | input | output | bypass? |\n|---|---|---|---|\n| 1 fresh baseline | `<svg><script>__</script></svg>` | `<svg></svg>` | no |\n| 1b fresh baseline | `<a onclick=__>x</a>` | `<a>x</a>` | no |\n| 2 with hook (script) | `<svg><script>__</script></svg>` | `<svg><script>__</script></svg>` | yes (expected) |\n| 2b with hook (onclick) | `<a onclick=__>x</a>` | `<a onclick=\"__\">x</a>` | yes (expected) |\n| 3 after `removeAllHooks()` | same | `<svg><script>__</script></svg>` | **YES (pollution)** |\n| 3b after `removeAllHooks()` | same | `<a onclick=\"__\">x</a>` | **YES (pollution)** |\n| 4 after `clearConfig()` | same | `<svg><script>__</script></svg>` | **YES** |\n| 4b after `clearConfig()` | same | `<a onclick=\"__\">x</a>` | **YES** |\n| 5 explicit restrictive `cfg.ALLOWED_TAGS=['svg']` | same | `<svg></svg>` | no (cloned set) |\n| 6 back to no cfg | same | `<svg><script>__</script></svg>` | **YES** |\n| 6b back to no cfg | same | `<a onclick=\"__\">x</a>` | **YES** |\n| 7 fresh `DOMPurify(window)` instance | same | `<svg></svg>` | no |\n| 7b fresh instance | `<a onclick=__>x</a>` | `<a>x</a>` | no |\n\n## Impact\n\n### Direct\n\nAny application using `DOMPurify` that has any registered hook with the pattern `data.allowedTags[...] = true` or `data.allowedAttributes[...] = true`. The hook need not be designed to be permissive — it might be intended to *temporarily* allow a custom tag for one specific element shape. After the hook has executed even once, every subsequent default-config sanitize call carries the widened defaults, including:\n\n- attacker content rendered via separate code paths (e.g., the same library serving a comments section and a profile bio, where the bio uses the hook and the comments use plain `DOMPurify.sanitize(text)`)\n- third-party libraries that call `DOMPurify.sanitize` on the same instance\n\nThe bypass survives `DOMPurify.removeAllHooks()` and `DOMPurify.clearConfig()` — the obvious \"reset\" calls a dev would reach for. Detection requires reading the `DEFAULT_ALLOWED_TAGS` / `DEFAULT_ALLOWED_ATTR` sets directly, which are not part of the public API.\n\n### Indirect / second-order\n\n- **Editor / preview libraries** that compose with DOMPurify — if any consumer registers a hook that mutates `data.allowedTags`, every other consumer's sanitize calls inherit the widening.\n- **Test suites** that exercise multiple sanitize configurations — once a test's hook pollutes the defaults, later tests that assume default behavior may pass with widened defaults and miss real regressions.\n- **Long-running servers** (SSR, edge functions) that reuse a single DOMPurify instance — pollution accumulates over the process lifetime.\n\n### Why the existing maintainer defense for `ADD_TAGS` doesn't catch this\n\n`src/purify.ts:696-700` already documents awareness:\n\n```ts\n} else if (arrayIsArray(cfg.ADD_TAGS)) {\n  if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n    ALLOWED_TAGS = clone(ALLOWED_TAGS);\n  }\n  addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n}\n```\n\nThe clone-before-mutate pattern is exactly what's needed at the hook callsites (`:1206-1209` and `:1494-1500`) but was not extended there. The new entries this report's bypass adds to the defaults survive the same way `ADD_TAGS` array entries would have survived before that fix landed.\n\n## Suggested fix\n\nThree minimal-impact options, in order of preference:\n\n1. **Hand the hook a defensive copy** (most surgical):\n\n   ```ts\n   _executeHooks(hooks.uponSanitizeElement, currentNode, {\n     tagName,\n     allowedTags: { ...ALLOWED_TAGS },     // shallow copy; mutations stay scoped\n   });\n   ```\n\n   Doc note: \"`data.allowedTags` is a snapshot; to widen the live set, use `cfg.ADD_TAGS` or set the value to true in the snapshot and check the snapshot from a subsequent attribute hook.\" Hooks that read it for inspection still work; hooks that intended cross-call mutation must be rewritten to use a proper config path (which is the correct API anyway).\n\n2. **Clone-on-write inside the hook path**, mirroring the existing `ADD_TAGS` defense at `:696-700`: detect that `ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS` after the hook returns, and if so, replace it with a clone for subsequent processing. This preserves the live-mutation semantics for in-call effects while preventing cross-call leakage.\n\n3. **Lazy-clone `ALLOWED_TAGS`/`ALLOWED_ATTR` from defaults on first mutation**: install a Proxy or accessor that triggers a clone before mutation. Largest surface area, but bulletproof.\n\nOption (1) is the cleanest API contract: hook event objects should be event-local, never references to library-internal state.","state":0,"publishedAt":"2026-06-15T19:59:09+00:00","modifiedAt":"2026-09-10T03:50:48.6715639+00:00","affected":[{"ecosystem":"npm","name":"dompurify","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"3.4.7"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"MODERATE"}],"references":["https://github.com/cure53/DOMPurify/security/advisories/GHSA-76mc-f452-cxcm","https://github.com/cure53/DOMPurify"],"sourceUrl":"https://github.com/advisories/GHSA-76mc-f452-cxcm","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-76mc-f452-cxcm","identifiers":["GHSA-76mc-f452-cxcm","CVE-2026-65902"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-10-26T05:26:56.6538334+00:00","complete":true,"records":1756,"lastAttemptAt":"2026-10-26T05:26:56.6538334+00:00","lastSuccessAt":"2026-10-26T05:26:56.7986454+00:00","error":null,"lastVerifiedAt":"2026-10-26T05:26:56.7986482+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-5ba1945314e042c2ced14b33f3680fa71692812d925544312b218f5eb8a26e71-bc703d32c448acb7291b43dd467a47b987ad86f105a430a0e30b03cf6e038792","complete":true,"records":414069,"lastAttemptAt":"2026-10-26T05:25:21.6088408+00:00","lastSuccessAt":"2026-10-26T05:25:21.5943862+00:00","error":null,"lastVerifiedAt":"2026-10-26T05:25:21.6088408+00:00","snapshotPublishedAt":"2026-10-26T04:31:21+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-43321610382942b8ad8c85917eab1546","complete":false,"records":4735,"lastAttemptAt":"2026-10-26T05:26:59.285199+00:00","lastSuccessAt":"2026-10-24T23:18:49.862+00:00","error":"InvalidDataException","lastVerifiedAt":"2026-10-24T23:18:49.862+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":4764,"expectedIdentifiers":13474},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-10-26T05:26:56.6538334+00:00","complete":true,"records":1093,"lastAttemptAt":"2026-10-26T05:26:56.6538334+00:00","lastSuccessAt":"2026-10-26T05:26:56.7998442+00:00","error":null,"lastVerifiedAt":"2026-10-26T05:26:56.799845+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-204a3fb93a00487e8f7f36db01dc851d","complete":true,"records":13413,"lastAttemptAt":"2026-10-26T05:26:57.2787164+00:00","lastSuccessAt":"2026-10-25T16:19:28.681+00:00","error":null,"lastVerifiedAt":"2026-10-25T16:19:28.681+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13474,"expectedIdentifiers":13474},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-2375a4e597279abf92e8747e140fe8da9d421877cd49cae3ac69a2cb78469b2c","complete":true,"records":9779,"lastAttemptAt":"2026-10-26T05:26:56.2433127+00:00","lastSuccessAt":"2026-10-24T13:19:53.1346702+00:00","error":null,"lastVerifiedAt":"2026-10-26T05:26:56.2433127+00:00","snapshotPublishedAt":"2026-10-24T03:03:12+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-16ad89dfea13ab9e9b0108e63a759d63bd4559cc68b58491107d62ee35bbbaf2","complete":true,"records":1965,"lastAttemptAt":"2026-10-26T05:25:21.7989429+00:00","lastSuccessAt":"2026-10-23T16:01:26.4487605+00:00","error":null,"lastVerifiedAt":"2026-10-26T05:25:21.7989429+00:00","snapshotPublishedAt":"2026-10-21T12:18:07+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-7da67a15aa6e56a0e3081a7646dc74d537e6ef974afc593c2b1794ed01970648","complete":true,"records":2969,"lastAttemptAt":"2026-10-26T05:26:56.6198554+00:00","lastSuccessAt":"2026-10-24T13:19:59.1145547+00:00","error":null,"lastVerifiedAt":"2026-10-26T05:26:56.6198554+00:00","snapshotPublishedAt":"2026-10-24T08:47:51+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-f936be991545888acd70d1c7b6fcb3da4be35405bbec4bff46b924c2832f41b1","complete":true,"records":230802,"lastAttemptAt":"2026-10-26T05:26:56.1119243+00:00","lastSuccessAt":"2026-10-26T05:26:54.9585845+00:00","error":null,"lastVerifiedAt":"2026-10-26T05:26:56.1119243+00:00","snapshotPublishedAt":"2026-10-26T04:48:14+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null}]}