Summary
@rolemodel/spider 0.0.10 pins pdfjs-dist: ^5.4.624 (package.json#L42), which is affected by GHSA-hq66-cqwq-w95j (high — arbitrary JS execution on opening a malicious PDF). The fix is in pdfjs-dist 6.2.108, a major bump the current caret range forbids.
This surfaces as an undismissable Dependabot alert in every downstream consumer. We hit it in RoleModel/fmi-atlas, where spider is the sole path to pdfjs-dist.
While digging in, I found a second, independent packaging bug that is the reason consumers can't remediate this on their own — and that already breaks <rm-pdf-viewer> at runtime. Details below; happy to split it into its own issue if you'd prefer.
1. Requested change
Bump pdfjs-dist to >= 6.2.108 and cut a release.
For what it's worth, I don't think the advisory's exploit path is actually reachable through spider today, so this doesn't look urgent from a security standpoint. enableScripting is an annotation-layer option (in pdfjs-dist's built pdf.mjs it's only ever read as AnnotationElement/AnnotationLayer params), and spider renders canvas-only — pdf-page.js#L69 calls page.render({ canvasContext, viewport }) with no annotation or text layer, and enableScripting never appears in src/. So the scripting sandbox is never constructed. The bump is mostly about clearing the alert for consumers.
2. Packaging bug: the pdf.js worker is inlined at an exact version
vite.config.js externalizes pdfjs-dist as an exact string:
rollupOptions: {
external: [/^lit/, /^@lit/, 'pdfjs-dist'],
}
That matches only the bare specifier. The ?url subpath imports in pdf-viewer.js#L5-L8 are not matched:
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.mjs?url'
import jbig2WasmUrl from 'pdfjs-dist/wasm/jbig2.wasm?url'
import openjpegWasmUrl from 'pdfjs-dist/wasm/openjpeg.wasm?url'
import qcmsWasmUrl from 'pdfjs-dist/wasm/qcms_bg.wasm?url'
So Vite inlines them into the published dist/ as base64 data: URIs (dist/node_modules/pdfjs-dist/build/pdf.worker.js, ~1.98 MB decoded), and GlobalWorkerOptions.workerSrc is pinned to that copy.
The consequence: the main-thread API stays external and floats across the ^5.4.624 range, while the worker is frozen at whatever exact version spider was built against. pdf.js hard-throws on any mismatch:
const workerVersion = "5.4.624";
if (apiVersion !== workerVersion) {
throw new Error(`The API version "${apiVersion}" does not match the Worker version "${workerVersion}".`);
}
This already breaks the viewer
In fmi-atlas the caret range resolved pdfjs-dist to 5.7.284, so the API sends apiVersion: "5.7.284" to an inlined worker hard-coded to "5.4.624" — every getDocument() throws. Any consumer resolving a pdfjs-dist newer than spider's exact build version gets a non-functional <rm-pdf-viewer>. (It went unnoticed for us only because we import the barrel and never instantiate the element.)
Reproduced against @rolemodel/spider@0.0.10 from the registry:
$ node -e '<decode the base64 data: URI in dist/node_modules/pdfjs-dist/build/pdf.worker.js>'
inlined worker bytes: 1978096
version literals: ["5.4.624"]
$ grep -n 'apiVersion' node_modules/pdfjs-dist/build/pdf.mjs
14826: apiVersion: "5.7.284",
It also blocks downstream remediation
A consumer-side resolutions/overrides override of pdfjs-dist cannot fix issue 1, because it only moves the external API module. The vulnerable 5.x worker — where PDF parsing actually happens — stays bundled in spider's dist/, and the override guarantees the version-mismatch throw above. So downstream has no workaround at all: we had to leave the alert open and document why.
Suggested fix
Externalize the subpaths too, so the worker and WASM resolve from the consumer's own pdfjs-dist:
external: [/^lit/, /^@lit/, /^pdfjs-dist/],
That keeps API and worker on the same version by construction, drops ~2 MB of base64 from dist/, and lets consumers override pdfjs-dist if they ever need to. It does mean consumers must resolve the ?url subpath imports, so it's worth confirming against a plain webpack consumer (fmi-atlas is webpack 5) before release. Pinning pdfjs-dist to an exact version would also make the mismatch impossible, but leaves the override problem and the bundle size in place.
Glad to open a PR for either part if that's useful.
Found while triaging Dependabot alerts in RoleModel/fmi-atlas (PR #513).
Summary
@rolemodel/spider0.0.10 pinspdfjs-dist: ^5.4.624(package.json#L42), which is affected by GHSA-hq66-cqwq-w95j (high — arbitrary JS execution on opening a malicious PDF). The fix is inpdfjs-dist6.2.108, a major bump the current caret range forbids.This surfaces as an undismissable Dependabot alert in every downstream consumer. We hit it in RoleModel/fmi-atlas, where spider is the sole path to
pdfjs-dist.While digging in, I found a second, independent packaging bug that is the reason consumers can't remediate this on their own — and that already breaks
<rm-pdf-viewer>at runtime. Details below; happy to split it into its own issue if you'd prefer.1. Requested change
Bump
pdfjs-distto>= 6.2.108and cut a release.For what it's worth, I don't think the advisory's exploit path is actually reachable through spider today, so this doesn't look urgent from a security standpoint.
enableScriptingis an annotation-layer option (inpdfjs-dist's builtpdf.mjsit's only ever read asAnnotationElement/AnnotationLayerparams), and spider renders canvas-only —pdf-page.js#L69callspage.render({ canvasContext, viewport })with no annotation or text layer, andenableScriptingnever appears insrc/. So the scripting sandbox is never constructed. The bump is mostly about clearing the alert for consumers.2. Packaging bug: the pdf.js worker is inlined at an exact version
vite.config.jsexternalizespdfjs-distas an exact string:That matches only the bare specifier. The
?urlsubpath imports inpdf-viewer.js#L5-L8are not matched:So Vite inlines them into the published
dist/as base64data:URIs (dist/node_modules/pdfjs-dist/build/pdf.worker.js, ~1.98 MB decoded), andGlobalWorkerOptions.workerSrcis pinned to that copy.The consequence: the main-thread API stays external and floats across the
^5.4.624range, while the worker is frozen at whatever exact version spider was built against. pdf.js hard-throws on any mismatch:This already breaks the viewer
In fmi-atlas the caret range resolved
pdfjs-distto 5.7.284, so the API sendsapiVersion: "5.7.284"to an inlined worker hard-coded to"5.4.624"— everygetDocument()throws. Any consumer resolving apdfjs-distnewer than spider's exact build version gets a non-functional<rm-pdf-viewer>. (It went unnoticed for us only because we import the barrel and never instantiate the element.)Reproduced against
@rolemodel/spider@0.0.10from the registry:It also blocks downstream remediation
A consumer-side
resolutions/overridesoverride ofpdfjs-distcannot fix issue 1, because it only moves the external API module. The vulnerable 5.x worker — where PDF parsing actually happens — stays bundled in spider'sdist/, and the override guarantees the version-mismatch throw above. So downstream has no workaround at all: we had to leave the alert open and document why.Suggested fix
Externalize the subpaths too, so the worker and WASM resolve from the consumer's own
pdfjs-dist:That keeps API and worker on the same version by construction, drops ~2 MB of base64 from
dist/, and lets consumers overridepdfjs-distif they ever need to. It does mean consumers must resolve the?urlsubpath imports, so it's worth confirming against a plain webpack consumer (fmi-atlas is webpack 5) before release. Pinningpdfjs-distto an exact version would also make the mismatch impossible, but leaves the override problem and the bundle size in place.Glad to open a PR for either part if that's useful.
Found while triaging Dependabot alerts in RoleModel/fmi-atlas (PR #513).