From 5972679f78686849427c94e89becbdb51d5b8cf7 Mon Sep 17 00:00:00 2001 From: thomaslovaslokoy-ui Date: Thu, 19 Mar 2026 00:41:00 +0100 Subject: [PATCH 1/2] Update SECURITY.md with reporting instructions , --- SECURITY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/SECURITY.md b/SECURITY.md index efb3959..79ff886 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,3 +5,4 @@ If you believe you have found a security vulnerability, we encourage you to let We will investigate all legitimate reports and do our best to quickly fix the problem. Please report any vulnerabilities in our open source repositories to responsible.disclosure@vercel.com. +package-lock.json From f4e8c810e3177863056a141a5b643402f5df0184 Mon Sep 17 00:00:00 2001 From: thomaslovaslokoy-ui Date: Mon, 23 Mar 2026 07:16:07 +0100 Subject: [PATCH 2/2] fix: remediate script injection and token exposure in install composite action (#3) Three security vulnerabilities identified in audit and fixed: 1. Expression injection via inputs.filter (Finding 2) - inputs.filter was interpolated directly into the run: shell script, allowing arbitrary command injection if a caller passed a malicious value. - Fix: bind the value to an env var (FILTER) and pass it to jq via --arg, so jq treats it as data rather than part of its expression. 2. Private registry token exposed in shell command (Finding 3) - inputs.vercel-private-registry-token was interpolated directly into the pnpm config set command. This can surface the token value in runner debug logs, process listings, and crash artifacts. GitHub's secret masking does not cover composite-action inputs interpolated this way. - Fix: reference the already-present $VERCEL_PRIVATE_REGISTRY_TOKEN env var instead of the raw expression. 3. Step output injected into shell command (Finding 4) - steps.parse-filter.outputs.pnpm-filter-args was interpolated directly into the run: script, compounding Finding 2. - Fix: expose the output through a new PNPM_FILTER_ARGS env var and reference it in the shell body. The var is intentionally left unquoted so that multiple --filter flags word-split correctly. Co-authored-by: Cursor Agent Co-authored-by: thomaslovaslokoy-ui --- .github/composite-actions/install/action.yml | 78 ++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 .github/composite-actions/install/action.yml diff --git a/.github/composite-actions/install/action.yml b/.github/composite-actions/install/action.yml new file mode 100644 index 0000000..98b496e --- /dev/null +++ b/.github/composite-actions/install/action.yml @@ -0,0 +1,78 @@ +name: 'Install' +description: 'Sets up Node.js and runs install' + +inputs: + npm-token: + description: 'A read-only npm token' + required: true + vercel-private-registry-token: + description: 'A token used to access the Vercel Private Registry' + required: true + node-version-file: + description: 'A custom node version' + required: false + default: '.nvmrc' + node-version: + description: 'The version of node, should be 16 or 20' + default: '20' + required: false + filter: + description: 'A list of pnpm filters - see https://pnpm.io/filtering' + required: false + default: '' + + +runs: + using: composite + steps: + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version-file: ${{ inputs.node-version-file }} + registry-url: 'https://registry.npmjs.org' + + - name: "Install corepack v0.20" + if: ${{ inputs.node-version == '16' }} + shell: bash + run: | + echo "corepack version before: $(corepack --version)" + # 0.20 is the highest we can go, 0.20 drops node 16 support + # https://github.com/nodejs/corepack/blob/main/CHANGELOG.md#0210-2023-10-08 + npm install -g corepack@0.20 + echo "corepack version after: $(corepack --version)" + + - name: "Install corepack@0.31" + if: ${{ inputs.node-version != '16' }} + shell: bash + run: | + npm install -g corepack@0.31 + echo "corepack version after: $(corepack --version)" + + - name: corepack enable (pnpm) + shell: bash + run: corepack enable + - name: Print pnpm version + shell: bash + run: | + echo "pnpm version after corepack enable: $(pnpm --version)" + + - name: Parse filter + id: parse-filter + shell: bash + env: + FILTER: ${{ inputs.filter }} + run: | + echo "pnpm-filter-args=$(jq -rn --arg filter "$FILTER" '$filter | split(" ") | map(select(. != "")) | map("--filter " + .) | join(" ")')" >> "$GITHUB_OUTPUT" + + - name: Install dependencies + shell: bash + run: | + pnpm config set //vercel-private-registry.vercel.sh/:_authToken "$VERCEL_PRIVATE_REGISTRY_TOKEN" + # PNPM_FILTER_ARGS is intentionally unquoted: it contains multiple --filter + # arguments that must be word-split into separate flags. + # shellcheck disable=SC2086 + pnpm $PNPM_FILTER_ARGS install --frozen-lockfile + env: + NODE_AUTH_TOKEN: ${{ inputs.npm-token }} + VERCEL_PRIVATE_REGISTRY_TOKEN: ${{ inputs.vercel-private-registry-token }} + PNPM_FILTER_ARGS: ${{ steps.parse-filter.outputs.pnpm-filter-args }}