Compare commits
7
Commits
1a5338e876
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f3c6f30a9 | ||
|
|
2eb5d74f59 | ||
|
|
bef1b99c78 | ||
|
|
5980e2caba | ||
|
|
27a6d98d0c | ||
|
|
59f169e32d | ||
|
|
bbb163c25c |
No files matched your search
@@ -4,6 +4,14 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
# One deploy at a time: `surfer deploy` swaps the site atomically, so two runs
|
||||
# racing each other is not corruption, but it is a wasted build and the last
|
||||
# swap wins.
|
||||
concurrency:
|
||||
group: surfer-datacontroller-io
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
Build-and-publish:
|
||||
@@ -18,8 +26,44 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci --legacy-peer-deps
|
||||
|
||||
# Blocking gate. `npm audit --audit-level=<x>` is all-or-nothing and this
|
||||
# tree cannot pass a flat gate at any level: the Gatsby 5 build toolchain
|
||||
# carries ~100 advisories with no non-breaking fix, so gating on the tree
|
||||
# as a whole stops publishing permanently. scripts/audit-gate.mjs instead
|
||||
# accepts the known set (scripts/audit-baseline.json, with an owner and a
|
||||
# reason) and FAILS on any new critical/high advisory.
|
||||
- name: Audit for new critical/high advisories
|
||||
run: node scripts/audit-gate.mjs
|
||||
|
||||
# The prettier and type checks used to live in a GitHub workflow that
|
||||
# never ran on this forge; keep them ahead of the build so a type or
|
||||
# formatting error blocks the deploy rather than shipping.
|
||||
- name: Typecheck
|
||||
run: npm run typecheck
|
||||
|
||||
- name: Check prettier offences
|
||||
run: npm run lint
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
# Deploy tooling pinned to an exact version: the workflow publishes
|
||||
# whatever is committed, and an unpinned `latest` would let a breaking or
|
||||
# compromised upstream release ship straight to the live site.
|
||||
#
|
||||
# `deploy` (v7) replaces the site atomically - it extracts to a staging
|
||||
# folder and swaps it in, so a failed upload leaves the current site
|
||||
# serving. The v6 `put` this replaces was token authenticated and is
|
||||
# gone; v7 takes the Cloudron username plus an app password for this app.
|
||||
- name: Publish
|
||||
run: npx surfer put --token ${{ secrets.SURFER_TOKEN }} --server datacontroller.io public/* /
|
||||
env:
|
||||
SURFER_PASSWORD: ${{ secrets.SURFER_PASSWORD }}
|
||||
REF_NAME: ${{ gitea.ref_name }}
|
||||
COMMIT_SHA: ${{ gitea.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
npx --yes @cloudron/surfer@7.2.0 deploy public \
|
||||
--server datacontroller.io \
|
||||
--username allan \
|
||||
--password "$SURFER_PASSWORD" \
|
||||
--message "Build from ${REF_NAME} @ ${COMMIT_SHA:0:8}"
|
||||
@@ -1,30 +0,0 @@
|
||||
name: Gatsby Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Use Node.js from .nvmrc
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --legacy-peer-deps
|
||||
|
||||
- name: Check prettier offences
|
||||
run: npm run lint
|
||||
|
||||
- uses: enriikke/gatsby-gh-pages-action@v2
|
||||
with:
|
||||
access-token: ${{ secrets.DCSITE }}
|
||||
deploy-branch: gh-pages
|
||||
gatsby-args: --prefix-paths
|
||||
@@ -0,0 +1,12 @@
|
||||
# Secret scanning for staged content, so a credential is caught before it is
|
||||
# committed rather than after it has been pushed and published.
|
||||
#
|
||||
# gitleaks is pinned to an exact tag: a floating rev would pull whatever the
|
||||
# hook's upstream does next into every contributor's commit path.
|
||||
#
|
||||
# Install once per clone: `pre-commit install`.
|
||||
repos:
|
||||
- repo: https://github.com/gitleaks/gitleaks
|
||||
rev: v8.30.1
|
||||
hooks:
|
||||
- id: gitleaks
|
||||
Generated
+15
-1120
File diff suppressed because it is too large.
Load diff
@@ -55,7 +55,6 @@
|
||||
"@types/react": "^18.3.31",
|
||||
"@types/react-dom": "^18.3.7",
|
||||
"bootstrap": "^5.0.0-beta3",
|
||||
"cloudron-surfer": "^6.4.1",
|
||||
"jquery": "^3.6.0",
|
||||
"typescript": "^7.0.2"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,940 @@
|
||||
{
|
||||
"$comment": "Advisories at critical/high accepted for this tree. scripts/audit-gate.mjs fails the build on anything not listed here, so removing an entry re-arms the gate for that advisory. Regenerate with: node scripts/audit-gate.mjs --write-baseline",
|
||||
"owner": "Site maintainers (allan@4gl.io)",
|
||||
"reason": "Gatsby 5 build toolchain: no non-breaking fix available upstream, and these are build-time dependencies of a statically generated site. Re-check on each Gatsby major bump.",
|
||||
"accepted": [
|
||||
{
|
||||
"pkg": "@ardatan/relay-compiler",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@babel/plugin-transform-modules-systemjs",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-fv7c-fp4j-7gwp",
|
||||
"title": "@babel/plugin-transform-modules-systemjs generates arbitrary code when compiling malicious input",
|
||||
"range": ">=7.12.0 <=7.29.3"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-codegen/add",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-codegen/core",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-codegen/plugin-helpers",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-codegen/schema-ast",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-codegen/typescript-operations",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-codegen/typescript",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-codegen/visitor-plugin-common",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-tools/code-file-loader",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-tools/graphql-tag-pluck",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-tools/load",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-tools/merge",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-tools/relay-operation-optimizer",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-tools/schema",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "@graphql-tools/utils",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-7mx3-vvmw-hjmv",
|
||||
"title": "GraphQL Tools has prototype pollution in well-established utility function `mergeDeep`",
|
||||
"range": "<=12.0.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-35jp-ww65-95wh",
|
||||
"title": "axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `config.proxy`",
|
||||
"range": ">=1.0.0 <1.16.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-3g43-6gmg-66jw",
|
||||
"title": "axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollution Gadget in Config Merge",
|
||||
"range": ">=1.0.0 <1.15.2"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-3p68-rc4w-qgx5",
|
||||
"title": "Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF",
|
||||
"range": ">=1.0.0 <1.15.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-3pq3-5fj3-cg6v",
|
||||
"title": "Axios: HTTP/2 adapter bypasses configured DNS lookup and proxy controls",
|
||||
"range": ">=1.13.0 <1.20.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-3w6x-2g7m-8v23",
|
||||
"title": "Axios: Invisible JSON Response Tampering via Prototype Pollution Gadget in `parseReviver`",
|
||||
"range": ">=1.0.0 <1.15.2"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-42h9-826w-cgv3",
|
||||
"title": "Axios: Excessive recursion in formDataToJSON can cause denial of service",
|
||||
"range": ">=1.0.0 <1.18.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-43fc-jf86-j433",
|
||||
"title": "Axios is Vulnerable to Denial of Service via __proto__ Key in mergeConfig",
|
||||
"range": ">=1.0.0 <=1.13.4"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-445q-vr5w-6q77",
|
||||
"title": "Axios: CRLF Injection in multipart/form-data body via unsanitized blob.type in formDataToStream",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-4hqw-qxg8-jxx2",
|
||||
"title": "Axios: Fetch Adapter Header Injection via Inherited FormData getHeaders",
|
||||
"range": ">=1.12.0 <1.20.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-542g-h47m-68v8",
|
||||
"title": "Axios: Denial of Service via Unhandled 'error' Event in HTTP/2 ClientHttp2Session Initialization",
|
||||
"range": ">=1.13.0 <1.20.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-5c9x-8gcm-mpgx",
|
||||
"title": "Axios' HTTP adapter-streamed uploads bypass maxBodyLength when maxRedirects: 0",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-62hf-57xw-28j9",
|
||||
"title": "Axios: unbounded recursion in toFormData causes DoS via deeply nested request data",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-6chq-wfr3-2hj9",
|
||||
"title": "Axios: Header Injection via Prototype Pollution",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-777c-7fjr-54vf",
|
||||
"title": "Allocation of Resources Without Limits or Throttling in Axios",
|
||||
"range": ">=1.7.0 <1.16.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-7q8q-rj6j-mhjq",
|
||||
"title": "Axios: Nested axios option objects can consume polluted prototype values",
|
||||
"range": ">=1.0.0 <1.18.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-898c-q2cr-xwhg",
|
||||
"title": "axios has DoS & Header Injection via Prototype Pollution Read-Side Gadgets in axios merge functions",
|
||||
"range": ">=1.0.0 <1.16.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-9fr6-4gfg-395g",
|
||||
"title": "Axios: Prototype-Pollution Gadget in the Default Instance Allows Inherited Object.prototype.method to Override HTTP Method",
|
||||
"range": ">=1.0.0 <1.20.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-fvcv-3m26-pcqx",
|
||||
"title": "Axios has Unrestricted Cloud Metadata Exfiltration via Header Injection Chain",
|
||||
"range": ">=1.0.0 <1.15.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-hfxv-24rg-xrqf",
|
||||
"title": "Axios: Regular Expression Denial of Service (ReDoS) via Cookie Name Injection",
|
||||
"range": ">=1.0.0 <1.16.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-j5f8-grm9-p9fc",
|
||||
"title": "Axios: Proxy-Authorization header leaks to redirect target when proxy is re-evaluated to direct connection",
|
||||
"range": ">=1.0.0 <1.16.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-j8rh-479h-cp32",
|
||||
"title": "Axios: Header Injection via Inherited headers After Minimal Interceptor",
|
||||
"range": ">=1.0.0 <1.20.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-jqh4-m9w3-8hp9",
|
||||
"title": "Axios: Fetch adapter `ReadableStream` uploads bypass `maxBodyLength`",
|
||||
"range": ">=1.7.0 <1.18.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-m7pr-hjqh-92cm",
|
||||
"title": "Axios: no_proxy bypass via IP alias allows SSRF",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-mmx7-hfxf-jppx",
|
||||
"title": "Axios: Prototype pollution gadgets can alter axios request construction",
|
||||
"range": ">=1.0.0 <1.18.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-mwf2-3pr3-8698",
|
||||
"title": "Axios: HTTP/2 streamed uploads bypass `maxBodyLength`",
|
||||
"range": ">=1.13.0 <1.18.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-p92q-9vqr-4j8v",
|
||||
"title": "Axios: Proxy-Authorization Credential Leak to Origin Server Across HTTP-to-HTTPS Redirect in Axios Node.js HTTP Adapter",
|
||||
"range": ">=1.0.0 <1.16.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-pf86-5x62-jrwf",
|
||||
"title": "Axios: Prototype Pollution Gadgets - Response Tampering, Data Exfiltration, and Request Hijacking",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-pmv8-rq9r-6j72",
|
||||
"title": "Axios: Deep formToJSON Key Recursion Can Cause Denial of Service",
|
||||
"range": ">=1.0.0 <1.18.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-pmwg-cvhr-8vh7",
|
||||
"title": "Axios: Incomplete Fix for CVE-2025-62718 — NO_PROXY Protection Bypassed via RFC 1122 Loopback Subnet (127.0.0.0/8) in Axios 1.15.0",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-q8qp-cvcw-x6jj",
|
||||
"title": "Axios has prototype pollution read-side gadgets in HTTP adapter that allow credential injection and request hijacking",
|
||||
"range": ">=1.0.0 <1.15.2"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-vf2m-468p-8v99",
|
||||
"title": "Axios: HTTP adapter streamed responses bypass maxContentLength",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-vh66-26gq-q6x8",
|
||||
"title": "Axios: Prototype pollution gadget in fetch adapter can alter outbound requests",
|
||||
"range": ">=1.7.0 <1.20.0"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-w9j2-pvgh-6h63",
|
||||
"title": "Axios: Authentication Bypass via Prototype Pollution Gadget in `validateStatus` Merge Strategy",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-xhjh-pmcv-23jw",
|
||||
"title": "Axios: Null Byte Injection via Reverse-Encoding in AxiosURLSearchParams",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "axios",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-xx6v-rp6x-q39c",
|
||||
"title": "Axios: XSRF Token Cross-Origin Leakage via Prototype Pollution Gadget in `withXSRFToken` Boolean Coercion",
|
||||
"range": ">=1.0.0 <1.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "body-parser",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-27r3-jxmh-p828",
|
||||
"title": "body-parser vulnerable to Denial of Service via trailing bytes after a compressed request body",
|
||||
"range": "<1.20.9"
|
||||
},
|
||||
{
|
||||
"pkg": "body-parser",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-qwcr-r2fm-qrc7",
|
||||
"title": "body-parser vulnerable to denial of service when url encoding is enabled",
|
||||
"range": "<1.20.3"
|
||||
},
|
||||
{
|
||||
"pkg": "body-parser",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-v422-hmwv-36x6",
|
||||
"title": "body-parser vulnerable to denial of service when invalid limit value silently disables size enforcement",
|
||||
"range": "<1.20.6"
|
||||
},
|
||||
{
|
||||
"pkg": "brace-expansion",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-3jxr-9vmj-r5cp",
|
||||
"title": "brace-expansion: DoS via exponential-time expansion of consecutive non-expanding {} groups",
|
||||
"range": "<1.1.16"
|
||||
},
|
||||
{
|
||||
"pkg": "brace-expansion",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-6j4f-fj2g-mc7p",
|
||||
"title": "brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion",
|
||||
"range": "<1.1.19"
|
||||
},
|
||||
{
|
||||
"pkg": "brace-expansion",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-f886-m6hf-6m8v",
|
||||
"title": "brace-expansion: Zero-step sequence causes process hang and memory exhaustion",
|
||||
"range": "<1.1.13"
|
||||
},
|
||||
{
|
||||
"pkg": "brace-expansion",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-mh99-v99m-4gvg",
|
||||
"title": "brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash",
|
||||
"range": "<1.1.17"
|
||||
},
|
||||
{
|
||||
"pkg": "brace-expansion",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-q2hr-2g5m-vwhr",
|
||||
"title": "brace-expansion: Quadratic-time expansion of the `{a},b}` rewrite causes CPU denial of service",
|
||||
"range": "<1.1.21"
|
||||
},
|
||||
{
|
||||
"pkg": "brace-expansion",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-qhr7-859c-m2p7",
|
||||
"title": "brace-expansion: DoS via uncontrolled recursion on nested brace groups causing stack exhaustion",
|
||||
"range": "<1.1.20"
|
||||
},
|
||||
{
|
||||
"pkg": "brace-expansion",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-rgw5-rvv9-x895",
|
||||
"title": "brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-14257 mitigation",
|
||||
"range": "<1.1.18"
|
||||
},
|
||||
{
|
||||
"pkg": "brace-expansion",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-v6h2-p8h4-qcjw",
|
||||
"title": "brace-expansion Regular Expression Denial of Service vulnerability",
|
||||
"range": ">=1.0.0 <=1.1.11"
|
||||
},
|
||||
{
|
||||
"pkg": "browserslist",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-73wf-gq98-2v4g",
|
||||
"title": "Browserslist: Uncaught crash / prototype write via untrusted browserslist-stats.json custom stats (normalizeStats)",
|
||||
"range": "<=4.28.6"
|
||||
},
|
||||
{
|
||||
"pkg": "browserslist",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-c83g-rgw3-j3cx",
|
||||
"title": "Browserslist: Unbounded memory growth (no cache eviction) via distinct query results, leading to eventual OOM",
|
||||
"range": "<=4.28.6"
|
||||
},
|
||||
{
|
||||
"pkg": "compression",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-vc2v-76pw-4v95",
|
||||
"title": "compression vulnerable to Denial of Service via memory leak on premature response close",
|
||||
"range": "<1.8.2"
|
||||
},
|
||||
{
|
||||
"pkg": "cross-spawn",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-3xgq-45jj-v275",
|
||||
"title": "Regular Expression Denial of Service (ReDoS) in cross-spawn",
|
||||
"range": ">=7.0.0 <7.0.5"
|
||||
},
|
||||
{
|
||||
"pkg": "engine.io",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-2gc4-cqfq-p2gv",
|
||||
"title": "Socket.IO: Engine.IO Protocol Revision Mismatch DoS",
|
||||
"range": ">=6.6.0 <6.6.10"
|
||||
},
|
||||
{
|
||||
"pkg": "engine.io",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-gr94-w7qr-f4j3",
|
||||
"title": "Socket.IO: Engine.IO WebTransport SID DoS",
|
||||
"range": ">=6.5.0 <6.6.7"
|
||||
},
|
||||
{
|
||||
"pkg": "engine.io",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-r635-g3xr-vw7x",
|
||||
"title": "Socket.IO: Engine.IO Polling Transport Connection Exhaustion",
|
||||
"range": ">=4.1.0 <6.6.7"
|
||||
},
|
||||
{
|
||||
"pkg": "express",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-qw6h-vgh9-j6wx",
|
||||
"title": "express vulnerable to XSS via response.redirect()",
|
||||
"range": "<4.20.0"
|
||||
},
|
||||
{
|
||||
"pkg": "flatted",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-25h7-pfq9-p65f",
|
||||
"title": "flatted vulnerable to unbounded recursion DoS in parse() revive phase",
|
||||
"range": "<3.4.0"
|
||||
},
|
||||
{
|
||||
"pkg": "flatted",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-rf6f-7fwh-wjgh",
|
||||
"title": "Prototype Pollution via parse() in NodeJS flatted",
|
||||
"range": "<=3.4.1"
|
||||
},
|
||||
{
|
||||
"pkg": "form-data",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-hmw2-7cc7-3qxx",
|
||||
"title": "form-data: CRLF injection in form-data via unescaped multipart field names and filenames",
|
||||
"range": ">=4.0.0 <4.0.6"
|
||||
},
|
||||
{
|
||||
"pkg": "gatsby-plugin-manifest",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "gatsby-plugin-sharp",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "gatsby-plugin-utils",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "gatsby-sharp",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "gatsby-transformer-sharp",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "gatsby",
|
||||
"severity": "high",
|
||||
"advisory": "transitive"
|
||||
},
|
||||
{
|
||||
"pkg": "http-cache-semantics",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-ch52-4w7c-c8xp",
|
||||
"title": "http-cache-semantics max-stale handling can disclose cross-user cached responses",
|
||||
"range": "<=4.2.0"
|
||||
},
|
||||
{
|
||||
"pkg": "immutable",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-v56q-mh7h-f735",
|
||||
"title": "Immutable.js `List` 32-bit trie overflow → unrecoverable DoS",
|
||||
"range": "<3.8.4"
|
||||
},
|
||||
{
|
||||
"pkg": "immutable",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-wf6x-7x77-mvgw",
|
||||
"title": "Immutable is vulnerable to Prototype Pollution",
|
||||
"range": "<3.8.3"
|
||||
},
|
||||
{
|
||||
"pkg": "immutable",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-xvcm-6775-5m9r",
|
||||
"title": "Immutable: Hash-collision algorithmic complexity denial of service in Immutable.Map/Set",
|
||||
"range": "<3.8.4"
|
||||
},
|
||||
{
|
||||
"pkg": "joi",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-6h2x-m376-mqjq",
|
||||
"title": "joi: Quadratic regular-expression backtracking in `Joi.string().isoDate()`",
|
||||
"range": ">=17.2.0 <17.13.7"
|
||||
},
|
||||
{
|
||||
"pkg": "joi",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-6w3j-5fw6-r9vr",
|
||||
"title": "joi: Prototype pollution via a `__proto__` language key in custom messages",
|
||||
"range": ">=17.2.0 <17.13.6"
|
||||
},
|
||||
{
|
||||
"pkg": "joi",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-gg4h-3hg2-grpc",
|
||||
"title": "joi: object().rename() with a template target can set the validated object's prototype",
|
||||
"range": ">=16.0.0 <17.13.5"
|
||||
},
|
||||
{
|
||||
"pkg": "joi",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-wr44-6hxh-3jwq",
|
||||
"title": "joi messages compilation allows prototype replacement through __proto__ error codes",
|
||||
"range": "<17.13.8"
|
||||
},
|
||||
{
|
||||
"pkg": "js-yaml",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-2883-xcg3-v3hh",
|
||||
"title": "js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources",
|
||||
"range": ">=3.0.0 <3.15.2"
|
||||
},
|
||||
{
|
||||
"pkg": "js-yaml",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-52cp-r559-cp3m",
|
||||
"title": "js-yaml: YAML merge-key chains can force quadratic CPU consumption",
|
||||
"range": ">=3.0.0 <3.15.0"
|
||||
},
|
||||
{
|
||||
"pkg": "js-yaml",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-5p4m-2wfm-xmqj",
|
||||
"title": "JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026-59870 fix not backported",
|
||||
"range": ">=3.0.0 <3.15.1"
|
||||
},
|
||||
{
|
||||
"pkg": "js-yaml",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-h67p-54hq-rp68",
|
||||
"title": "JS-YAML: Quadratic-complexity DoS in merge key handling via repeated aliases",
|
||||
"range": "<3.15.0"
|
||||
},
|
||||
{
|
||||
"pkg": "js-yaml",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-mh29-5h37-fv8m",
|
||||
"title": "js-yaml has prototype pollution in merge (<<)",
|
||||
"range": "<3.14.2"
|
||||
},
|
||||
{
|
||||
"pkg": "lodash",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-f23m-r3pf-42rh",
|
||||
"title": "lodash vulnerable to Prototype Pollution via array path bypass in `_.unset` and `_.omit`",
|
||||
"range": "<=4.17.23"
|
||||
},
|
||||
{
|
||||
"pkg": "lodash",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-r5fr-rjxr-66jc",
|
||||
"title": "lodash vulnerable to Code Injection via `_.template` imports key names",
|
||||
"range": ">=4.0.0 <=4.17.23"
|
||||
},
|
||||
{
|
||||
"pkg": "lodash",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-xxjr-mmjv-4gpg",
|
||||
"title": "Lodash has Prototype Pollution Vulnerability in `_.unset` and `_.omit` functions",
|
||||
"range": ">=4.0.0 <=4.17.22"
|
||||
},
|
||||
{
|
||||
"pkg": "minimatch",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-23c5-xmqv-rm74",
|
||||
"title": "minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regular expressions",
|
||||
"range": "<3.1.4"
|
||||
},
|
||||
{
|
||||
"pkg": "minimatch",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-3ppc-4f35-3m26",
|
||||
"title": "minimatch has a ReDoS via repeated wildcards with non-matching literal in pattern",
|
||||
"range": "<3.1.3"
|
||||
},
|
||||
{
|
||||
"pkg": "minimatch",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-7r86-cg39-jmmj",
|
||||
"title": "minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adjacent GLOBSTAR segments",
|
||||
"range": "<3.1.3"
|
||||
},
|
||||
{
|
||||
"pkg": "multer",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-3p4h-7m6x-2hcm",
|
||||
"title": "Multer vulnerable to Denial of Service via incomplete cleanup of aborted uploads",
|
||||
"range": ">=2.0.0-alpha.1 <2.2.0"
|
||||
},
|
||||
{
|
||||
"pkg": "multer",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-535w-7cp7-47q4",
|
||||
"title": "multer vulnerable to Denial of Service via oversized array index in field names",
|
||||
"range": "<2.3.0"
|
||||
},
|
||||
{
|
||||
"pkg": "multer",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-5528-5vmv-3xc2",
|
||||
"title": "Multer Vulnerable to Denial of Service via Uncontrolled Recursion",
|
||||
"range": "<2.1.1"
|
||||
},
|
||||
{
|
||||
"pkg": "multer",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-72gw-mp4g-v24j",
|
||||
"title": "Multer vulnerable to Denial of Service via deeply nested field names",
|
||||
"range": ">=1.0.0 <2.2.0"
|
||||
},
|
||||
{
|
||||
"pkg": "multer",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-q7qp-rjg7-q26m",
|
||||
"title": "multer vulnerable to Denial of Service via a pending asynchronous fileFilter after request teardown",
|
||||
"range": ">=2.0.0 <2.5.0"
|
||||
},
|
||||
{
|
||||
"pkg": "multer",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-qvfw-j98x-7q72",
|
||||
"title": "multer vulnerable to file size limit bypass via async fileFilter race condition",
|
||||
"range": "<2.3.0"
|
||||
},
|
||||
{
|
||||
"pkg": "multer",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-v52c-386h-88mc",
|
||||
"title": "Multer vulnerable to Denial of Service via resource exhaustion",
|
||||
"range": "<2.1.0"
|
||||
},
|
||||
{
|
||||
"pkg": "multer",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-wc9g-mqfw-jrwm",
|
||||
"title": "multer vulnerable to Denial of Service via crafted multipart field names",
|
||||
"range": "<2.3.0"
|
||||
},
|
||||
{
|
||||
"pkg": "multer",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-xf7r-hgr6-v32p",
|
||||
"title": "Multer vulnerable to Denial of Service via incomplete cleanup",
|
||||
"range": "<2.1.0"
|
||||
},
|
||||
{
|
||||
"pkg": "nanoid",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-28wg-ghj8-5hjv",
|
||||
"title": "nanoid: non-secure generators can loop indefinitely with negative size",
|
||||
"range": "<3.3.16"
|
||||
},
|
||||
{
|
||||
"pkg": "nanoid",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-2v37-7h3g-55p8",
|
||||
"title": "nanoid: custom generators can loop indefinitely when size is zero",
|
||||
"range": "<3.3.18"
|
||||
},
|
||||
{
|
||||
"pkg": "nanoid",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-mwcw-c2x4-8c55",
|
||||
"title": "Predictable results in nanoid generation when given non-integer values",
|
||||
"range": "<3.3.8"
|
||||
},
|
||||
{
|
||||
"pkg": "nanoid",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-xwg4-73v4-xw9w",
|
||||
"title": "nanoid: Integer Overflow or Wraparound",
|
||||
"range": "<3.3.12"
|
||||
},
|
||||
{
|
||||
"pkg": "path-to-regexp",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-37ch-88jc-xwx2",
|
||||
"title": "path-to-regexp vulnerable to Regular Expression Denial of Service via multiple route parameters",
|
||||
"range": "<0.1.13"
|
||||
},
|
||||
{
|
||||
"pkg": "path-to-regexp",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-9wv6-86v2-598j",
|
||||
"title": "path-to-regexp outputs backtracking regular expressions",
|
||||
"range": "<0.1.10"
|
||||
},
|
||||
{
|
||||
"pkg": "path-to-regexp",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-rhx6-c78j-4q9w",
|
||||
"title": "path-to-regexp contains a ReDoS",
|
||||
"range": "<0.1.12"
|
||||
},
|
||||
{
|
||||
"pkg": "picomatch",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-3v7f-55p6-f55p",
|
||||
"title": "Picomatch: Method Injection in POSIX Character Classes causes incorrect Glob Matching",
|
||||
"range": "<2.3.2"
|
||||
},
|
||||
{
|
||||
"pkg": "picomatch",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-c2c7-rcm5-vvqj",
|
||||
"title": "Picomatch has a ReDoS vulnerability via extglob quantifiers",
|
||||
"range": "<2.3.2"
|
||||
},
|
||||
{
|
||||
"pkg": "postcss",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-6g55-p6wh-862q",
|
||||
"title": "PostCSS: Arbitrary file read and information disclosure via attacker-controlled sourceMappingURL in CSS comments",
|
||||
"range": "<=8.5.11"
|
||||
},
|
||||
{
|
||||
"pkg": "postcss",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-fxqj-rqcc-2cmp",
|
||||
"title": "PostCSS: incomplete fix of GHSA-6g55-p6wh-862q — attacker-controlled sourceMappingURL reads arbitrary .map files when `from` is unset",
|
||||
"range": "<=8.5.22"
|
||||
},
|
||||
{
|
||||
"pkg": "postcss",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-qx2v-qp2m-jg93",
|
||||
"title": "PostCSS has XSS via Unescaped </style> in its CSS Stringify Output",
|
||||
"range": "<8.5.10"
|
||||
},
|
||||
{
|
||||
"pkg": "postcss",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-r28c-9q8g-f849",
|
||||
"title": "PostCSS: Path Traversal in Previous Source Map Auto-Loading (sourceMappingURL) leads to Arbitrary .map File Disclosure",
|
||||
"range": "<=8.5.17"
|
||||
},
|
||||
{
|
||||
"pkg": "probe-image-size",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-gjj5-9665-rwrc",
|
||||
"title": "probe-image-size: Quadratic-time Denial of Service in the SVG Parser",
|
||||
"range": "<=7.3.0"
|
||||
},
|
||||
{
|
||||
"pkg": "serialize-javascript",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-5c6j-r48x-rmvq",
|
||||
"title": "Serialize JavaScript is Vulnerable to RCE via RegExp.flags and Date.prototype.toISOString()",
|
||||
"range": "<=7.0.2"
|
||||
},
|
||||
{
|
||||
"pkg": "serialize-javascript",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-m5mm-p8h7-m29v",
|
||||
"title": "Serialize JavaScript: Cross-site scripting (XSS) via unescaped </script at the end of a serialized function body",
|
||||
"range": "<7.1.3"
|
||||
},
|
||||
{
|
||||
"pkg": "serialize-javascript",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-qj8w-gfj5-8c6v",
|
||||
"title": "Serialize JavaScript has CPU Exhaustion Denial of Service via crafted array-like objects",
|
||||
"range": ">=5.0.0 <7.0.5"
|
||||
},
|
||||
{
|
||||
"pkg": "sharp",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-f88m-g3jw-g9cj",
|
||||
"title": "sharp inherited vulnerabilities in libvips: CVE-2026-33327, CVE-2026-33328, CVE-2026-35590, CVE-2026-35591",
|
||||
"range": "<0.35.0"
|
||||
},
|
||||
{
|
||||
"pkg": "sharp",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-rgj7-g3m4-5g8c",
|
||||
"title": "sharp: Vulnerabilities in libheif: GHSA-g89c-p67h-r497 and GHSA-2jg2-4ch7-h545",
|
||||
"range": "<0.35.4"
|
||||
},
|
||||
{
|
||||
"pkg": "sharp",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-wq5f-xc86-pv6w",
|
||||
"title": "sharp : Vulnerability in librsvg dependency CVE-2026-96889",
|
||||
"range": "<0.35.5"
|
||||
},
|
||||
{
|
||||
"pkg": "socket.io-parser",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-2m8v-j782-fhvr",
|
||||
"title": "Socket.IO: Zero-attachment Memory Exhaustion",
|
||||
"range": ">=4.0.0 <4.2.7"
|
||||
},
|
||||
{
|
||||
"pkg": "socket.io-parser",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-677m-j7p3-52f9",
|
||||
"title": "socket.io allows an unbounded number of binary attachments",
|
||||
"range": ">=4.0.0 <4.2.6"
|
||||
},
|
||||
{
|
||||
"pkg": "source-map-js",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-68fv-2mgg-jv7q",
|
||||
"title": "source-map-js allows event-loop denial of service through indexed source-map section offsets",
|
||||
"range": ">=1.0.0 <1.2.2"
|
||||
},
|
||||
{
|
||||
"pkg": "svgo",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-2p49-hgcm-8545",
|
||||
"title": "SVGO removeScripts plugin leaves some executable scripts intact",
|
||||
"range": ">=1.0.0 <2.8.3"
|
||||
},
|
||||
{
|
||||
"pkg": "svgo",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-4vpr-x523-8j87",
|
||||
"title": "SVGO: removeScripts incompletely sanitizes executable HTML in SVG foreignObject elements",
|
||||
"range": ">=1.0.0 <2.8.4"
|
||||
},
|
||||
{
|
||||
"pkg": "svgo",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-w27v-7q3p-w38r",
|
||||
"title": "SVGO: removeScripts allows executable links through namespace and control-character bypasses",
|
||||
"range": ">=1.0.0 <2.8.4"
|
||||
},
|
||||
{
|
||||
"pkg": "svgo",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-xpqw-6gx7-v673",
|
||||
"title": "SVGO DoS through entity expansion in DOCTYPE (Billion Laughs)",
|
||||
"range": ">=2.1.0 <2.8.1"
|
||||
},
|
||||
{
|
||||
"pkg": "tmp",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-52f5-9888-hmc6",
|
||||
"title": "tmp allows arbitrary temporary file / directory write via symbolic link `dir` parameter",
|
||||
"range": "<=0.2.3"
|
||||
},
|
||||
{
|
||||
"pkg": "tmp",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-ph9p-34f9-6g65",
|
||||
"title": "tmp has Path Traversal via unsanitized prefix/postfix that enables directory escape",
|
||||
"range": "<0.2.6"
|
||||
},
|
||||
{
|
||||
"pkg": "webpack-dev-middleware",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-g84c-rxfj-3j2c",
|
||||
"title": "webpack-dev-middleware vulnerable to Path Traversal via non-slash-terminated publicPath",
|
||||
"range": "<7.4.5"
|
||||
},
|
||||
{
|
||||
"pkg": "ws",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-58qx-3vcg-4xpx",
|
||||
"title": "ws: Uninitialized memory disclosure",
|
||||
"range": ">=8.0.0 <8.20.1"
|
||||
},
|
||||
{
|
||||
"pkg": "ws",
|
||||
"severity": "high",
|
||||
"advisory": "GHSA-96hv-2xvq-fx4p",
|
||||
"title": "ws: Memory exhaustion DoS from tiny fragments and data chunks",
|
||||
"range": ">=8.0.0 <8.21.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Audit gate: fail the build on any advisory that is not a tracked exception.
|
||||
*
|
||||
* `npm audit --audit-level=<x>` is all-or-nothing, and this tree cannot pass a
|
||||
* flat gate: the Gatsby 5 build toolchain carries ~100 advisories at
|
||||
* low/moderate/high with no non-breaking fix, because gatsby is a runtime
|
||||
* dependency of the build. Blocking on any of those stops publishing
|
||||
* permanently; ignoring the tree lets a genuinely new advisory through. So the
|
||||
* known set is committed to audit-baseline.json with an owner and a reason,
|
||||
* and this script fails only when something NEW appears at or above the
|
||||
* threshold.
|
||||
*
|
||||
* Usage: node scripts/audit-gate.mjs [--write-baseline]
|
||||
*/
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||||
const BASELINE = join(HERE, 'audit-baseline.json');
|
||||
const BLOCKING = new Set(['critical', 'high']);
|
||||
|
||||
/** npm audit exits non-zero when it finds anything, so ignore the status. */
|
||||
function auditReport() {
|
||||
let out;
|
||||
try {
|
||||
out = execFileSync('npm', ['audit', '--json', '--omit=optional'], {
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
maxBuffer: 32 * 1024 * 1024
|
||||
});
|
||||
} catch (err) {
|
||||
out = err.stdout;
|
||||
if (!out) throw err;
|
||||
}
|
||||
return JSON.parse(out);
|
||||
}
|
||||
|
||||
/** Flatten the report to one key per package/severity/advisory triple. */
|
||||
function currentFindings(report) {
|
||||
const findings = new Map();
|
||||
for (const [pkg, v] of Object.entries(report.vulnerabilities ?? {})) {
|
||||
if (!BLOCKING.has(v.severity)) continue;
|
||||
const advisories = (v.via ?? []).filter((x) => typeof x === 'object');
|
||||
if (advisories.length === 0) {
|
||||
// via is a chain of parent package names - attribute to the package.
|
||||
findings.set(`${pkg}|${v.severity}|transitive`, { pkg, severity: v.severity, advisory: 'transitive' });
|
||||
continue;
|
||||
}
|
||||
for (const a of advisories) {
|
||||
const id = (a.url ?? '').split('/').pop() || a.title || 'unknown';
|
||||
findings.set(`${pkg}|${v.severity}|${id}`, { pkg, severity: v.severity, advisory: id, title: a.title, range: a.range });
|
||||
}
|
||||
}
|
||||
return findings;
|
||||
}
|
||||
|
||||
const report = auditReport();
|
||||
const current = currentFindings(report);
|
||||
|
||||
if (process.argv.includes('--write-baseline')) {
|
||||
const accepted = [...current.values()].sort((a, b) => `${a.pkg}${a.advisory}`.localeCompare(`${b.pkg}${b.advisory}`));
|
||||
writeFileSync(
|
||||
BASELINE,
|
||||
JSON.stringify(
|
||||
{
|
||||
$comment:
|
||||
'Advisories at critical/high accepted for this tree. scripts/audit-gate.mjs fails the build on anything not listed here, so removing an entry re-arms the gate for that advisory. Regenerate with: node scripts/audit-gate.mjs --write-baseline',
|
||||
owner: 'Site maintainers (allan@4gl.io)',
|
||||
reason:
|
||||
'Gatsby 5 build toolchain: no non-breaking fix available upstream, and these are build-time dependencies of a statically generated site. Re-check on each Gatsby major bump.',
|
||||
accepted
|
||||
},
|
||||
null,
|
||||
2
|
||||
) + '\n'
|
||||
);
|
||||
console.log(`wrote ${accepted.length} accepted advisories to ${BASELINE}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const baseline = JSON.parse(readFileSync(BASELINE, 'utf8'));
|
||||
const accepted = new Set((baseline.accepted ?? []).map((a) => `${a.pkg}|${a.severity}|${a.advisory}`));
|
||||
|
||||
const fresh = [...current.entries()].filter(([key]) => !accepted.has(key));
|
||||
const resolved = [...accepted].filter((key) => !current.has(key));
|
||||
|
||||
for (const [, f] of fresh) {
|
||||
console.error(`NEW ${f.severity.toUpperCase()}: ${f.pkg} - ${f.title ?? f.advisory} (${f.advisory})`);
|
||||
}
|
||||
|
||||
if (resolved.length > 0) {
|
||||
// Not a failure: a bumped or removed dependency closes advisories, and the
|
||||
// baseline should be trimmed in the same change that closes them.
|
||||
console.log(`${resolved.length} baseline entries no longer present - consider re-running with --write-baseline:`);
|
||||
for (const key of resolved) console.log(` stale: ${key}`);
|
||||
}
|
||||
|
||||
if (fresh.length > 0) {
|
||||
console.error(`\n${fresh.length} untracked advisory/ies at critical or high.`);
|
||||
console.error('Fix it, or add it to scripts/audit-baseline.json with a reason and an owner.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`audit gate: no new critical/high advisories (${current.size} tracked in baseline)`);
|
||||
+1
-1
@@ -14,7 +14,7 @@ const NotFound: React.FC<PageProps<unknown, PageContext>> = ({
|
||||
pageContext
|
||||
}) => (
|
||||
<Layout location={location} heroSection={false}>
|
||||
<Section color="black" bgColor="white" bottomArrow={false}>
|
||||
<Section color="black" bgColor="white" bottomArrow={false}>
|
||||
<SideBar
|
||||
pageContext={pageContext}
|
||||
location={location}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ const About: React.FC<PageProps<unknown>> = ({ location }) => {
|
||||
heading="Behind Data Controller"
|
||||
desc="Data Controller is a product of 4GL, a brand of Bowe IO Ltd"
|
||||
>
|
||||
<Section color="black" bgColor="white">
|
||||
<Section color="black" bgColor="white">
|
||||
<div className="row">
|
||||
<div className="offset-md-2 col-md-8">
|
||||
<SectionHeading center="no">About Data Controller</SectionHeading>
|
||||
|
||||
@@ -58,7 +58,7 @@ const Contact: React.FC<PageProps<unknown>> = ({ location }) => {
|
||||
heading="Book a Demo"
|
||||
desc="Schedule a demonstration of the Data Controller to see our latest features and explore use cases"
|
||||
>
|
||||
<Section color="black" bgColor="white" bottomArrow={false}>
|
||||
<Section color="black" bgColor="white" bottomArrow={false}>
|
||||
<div className="row">
|
||||
<div className="col-md-6">
|
||||
<SectionHeading center="no">Schedule a Call</SectionHeading>
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ const Faq: React.FC<PageProps<unknown>> = ({ location }) => {
|
||||
heading="Data Controller – FAQ"
|
||||
desc="Most common user questions and answers regarding the Data Controller"
|
||||
>
|
||||
<Section color="black" bgColor="white">
|
||||
<Section color="black" bgColor="white">
|
||||
<div className="row">
|
||||
<div className="col-md-8">
|
||||
<FAQ
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ const Home: React.FC<PageProps<IndexPageData>> = ({ data, location }) => {
|
||||
heading="Flexible and Secure Data Modification"
|
||||
desc="Data Controller for SAS® enables business users to update IT owned source tables, secured by review / approve workflow and full audit trail."
|
||||
>
|
||||
<Section color="black" bgColor="white">
|
||||
<Section color="black" bgColor="white">
|
||||
<div className="row">
|
||||
<div className="col-md-3">
|
||||
<Art src={leftArt} info="Business Owner" />
|
||||
|
||||
@@ -69,7 +69,7 @@ const BlogListTemplate: React.FC<PageProps<BlogListData, PageContext>> = ({
|
||||
heading="Data Controller’s Knowledge Base"
|
||||
desc="A section dedicated to news, updates and educational pieces."
|
||||
>
|
||||
<Section color="black" bgColor="white" bottomArrow={false}>
|
||||
<Section color="black" bgColor="white" bottomArrow={false}>
|
||||
<div className="row">
|
||||
<div className="col-md-7">
|
||||
<div className="row">
|
||||
|
||||
@@ -71,7 +71,7 @@ const BlogSearchTemplate: React.FC<PageProps<SearchData, PageContext>> = ({
|
||||
heading="Data Controller’s Knowledge Base"
|
||||
desc="A section dedicated to news, updates and educational pieces."
|
||||
>
|
||||
<Section color="black" bgColor="white" bottomArrow={false}>
|
||||
<Section color="black" bgColor="white" bottomArrow={false}>
|
||||
<div className="row">
|
||||
<div className="col-md-7">
|
||||
<div className="row">
|
||||
|
||||
@@ -68,7 +68,7 @@ const FeedListTemplate: React.FC<PageProps<FeedListData, PageContext>> = ({
|
||||
heading="Data Controller’s Feed"
|
||||
desc="Announcements and social media style updates from the Data Controller team."
|
||||
>
|
||||
<Section color="black" bgColor="white" bottomArrow={false}>
|
||||
<Section color="black" bgColor="white" bottomArrow={false}>
|
||||
<div className="row">
|
||||
<div className="col-md-7">
|
||||
<div className="row">
|
||||
|
||||
Reference in new issue
Block a user