Please report suspected vulnerabilities privately via GitHub Security Advisories rather than opening a public issue.
CI runs actions/dependency-review-action on
every pull request (.github/workflows/dependency-review.yml). It fails a PR that introduces a
dependency with a known high-or-worse advisory in the runtime scope.
Two deliberate choices are worth explaining, because they differ from a plain npm audit gate.
pnpm audit reports the absolute state of the whole tree. That makes an unrelated PR fail for a
transitive advisory it did not introduce and cannot fix, which trains everyone to ignore the check.
Dependency Review compares the base and head of the PR, so it only speaks up about what the PR
actually changed.
This is also what Docusaurus itself does: none of its CI workflows run npm/yarn/pnpm audit.
Docusaurus is a build tool. It produces static HTML, CSS and JS; there is no server runtime. A CVE
in webpack-dev-server or image-size describes a threat model that requires access to a
developer's machine at build time, not to anything a visitor to your site can reach.
fail-on-scopes therefore stays at its default of runtime, and this repo classifies Docusaurus
accordingly:
- published packages declare host-owned framework packages such as
@docusaurus/coreand@docusaurus/theme-commonas peerDependencies; directly imported build helpers remain runtime dependencies - the demo website declares them as devDependencies
This is the remedy the Docusaurus maintainers themselves recommend — see facebook/docusaurus#5501 and the canonical create-react-app#11174.
Sometimes an advisory has no patched version at any release, or the fix is blocked upstream. Two current examples in the Docusaurus tree:
image-size— two high advisories, no patched version published; a hard dependency of@docusaurus/mdx-loaderserialize-javascriptviacopy-webpack-plugin— blocked on a Node version bump, resolved in Docusaurus v4 (facebook/docusaurus#11801)
When one of these lands in the runtime scope and blocks a PR:
- Confirm it is genuinely unfixable — check whether a patched version exists and whether the range that reaches it can accept the patch.
- Confirm it is not reachable from anything we ship to a browser.
- Add the GHSA id to
allow-ghsasin.github/workflows/dependency-review.yml, with a comment naming the package and why it is accepted. - Re-check the list at every Docusaurus upgrade and delete entries once a patch ships. The allowlist is meant to shrink.
Do not raise fail-on-severity to work around a single advisory — that silently accepts every
future one at that level too.
.github/dependabot.yml runs weekly with grouped updates and a cooldown window (5 days by default,
30 for majors). The cooldown is deliberate: it gives the ecosystem time to catch a compromised
release before we pull it in. Security updates bypass it.
A stale lockfile is itself a security problem. In November 2025 this repo accumulated 71 advisories, and almost every one was a transitive dependency whose patched version was already inside the declared semver range — they were simply never re-resolved. Regenerating the lockfile cleared 68 of them.
Yarn Classic resolutions are unscoped: an entry for foo collapses every requested range for
foo into a single version across the whole tree. An entry like "js-yaml": "^3.14.2" will happily
downgrade a package that asked for ^4.1.0. This repo hit exactly that, and the resolutions block
ended up creating advisories rather than fixing them.
If you must add one, scope it (**/pkg@^1) and pin an exact minimum, never an open-ended >=,
which --frozen-lockfile will freeze at whatever satisfied it on the day it was added.