Skip to content

harden(prebuild): keep caller token off disk + ignore-scripts on untrusted install#12

Merged
gmaclennan merged 1 commit into
mainfrom
fix/prebuild-untrusted-npm-token-exposure
Jun 11, 2026
Merged

harden(prebuild): keep caller token off disk + ignore-scripts on untrusted install#12
gmaclennan merged 1 commit into
mainfrom
fix/prebuild-untrusted-npm-token-exposure

Conversation

@gmaclennan

Copy link
Copy Markdown
Member

Follow-up to the security review on #10. Closes the one real supply-chain exposure that review surfaced (pre-existing, not introduced by #10).

The exposure

The prebuild jobs (prebuild.yml, prebuild-all.yml) check out the caller repo with actions/checkout's default persist-credentials: true, which writes the caller's GITHUB_TOKEN into $GITHUB_WORKSPACE/.git/config. The composite action then runs npm install on the untrusted third-party target module (sodium-native, better-sqlite3, …) with lifecycle scripts enabled — so a malicious or compromised version of that module, or any transitive dep, gets arbitrary code execution in a job where that token is readable off disk.

In the sibling repos' release runs that token is write-capable, and those jobs publish the release artifacts that get downloaded and shipped inside the CoMapeo apps. This is the tj-actions/ultralytics pattern: untrusted build-time code reaching a privileged token.

The fix (belt and suspenders)

  • persist-credentials: false on the caller checkout in both prebuild workflows. That checkout exists only so patches_dir resolves against the workspace — it needs no token. No token on disk ⇒ nothing for an install script to steal.
  • npm install --ignore-scripts for the target module. bare-make drives the native build from CMakeLists afterwards, so no install-time lifecycle script is required — the better-sqlite3-nodejs-mobile workflow already builds this exact way, so this is proven, not speculative.

Validation

ci.yml runs the real prebuild → emulator-test pipeline on this PR (quickbit-native), so a green check confirms --ignore-scripts still produces a working, loadable .node.

Out of scope

The test workflows' assemble-test-project also npm installs the module (to fetch its test runner), but those jobs carry no release-write token — lower priority, can follow separately.

🤖 Generated with Claude Code

…usted install

Closes the supply-chain exposure flagged in the #10 security review: the
prebuild jobs check out the caller repo (default persist-credentials:
true) and then run `npm install` on the untrusted third-party target
module, whose lifecycle scripts could read the caller's GITHUB_TOKEN
from $GITHUB_WORKSPACE/.git/config — write-capable in the sibling repos'
release runs, which publish the artifacts shipped in the CoMapeo apps.

- persist-credentials: false on the caller checkout in prebuild.yml and
  prebuild-all.yml (it only exists to resolve patches_dir; needs no
  token). Belt: no token on disk to steal.
- npm install --ignore-scripts for the target module. bare-make drives
  the native build from CMakeLists, so no install-time script is needed
  (the better-sqlite3 workflow already builds this way). Suspenders.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gmaclennan
gmaclennan merged commit 7127512 into main Jun 11, 2026
7 of 8 checks passed
@gmaclennan
gmaclennan deleted the fix/prebuild-untrusted-npm-token-exposure branch June 11, 2026 08:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant