Summary
This action uses npx @datadog/datadog-ci@latest at runtime to install and execute the Datadog CI package. This means every dependency (and transitive dependency) is resolved fresh from npm on each workflow run, with no lockfile or integrity verification. This recently resulted in a real-world supply chain compromise affecting users of this action.
What happened
A malicious version of axios (1.14.1) was published to npm. Because @datadog/datadog-ci declares "axios": "^1.13.5" as a dependency, npm resolved it to the compromised version at install time. The attack chain was:
npx @datadog/datadog-ci@latest
→ @datadog/datadog-ci@5.10.0
→ axios@^1.13.5 → resolved to axios@1.14.1 (malicious)
→ plain-crypto-js@4.2.1 (postinstall RAT dropper)
→ C2 callback to sfrclak.com
Why pinning doesn't help
Even if users pin this action by SHA and set datadog-ci-version to a specific version like 5.10.0, it doesn't help. The transitive dependencies are still resolved via semver ranges at runtime. There is no lockfile involved when using npx, so users have no way to protect themselves from this class of attack.
Suggested fix
Bundle the action's dependencies at build time instead of installing them at runtime. Specifically:
- Use
@vercel/ncc (or similar) to compile @datadog/datadog-ci and all its dependencies into a single dist/index.js
- Change the action type from
composite (with a bash npx call) to node24 (with a pre-built entry point)
- Check in the bundled output and a
package-lock.json so that dependency versions are locked at publish time, not resolved at runtime
This is the standard approach used by most GitHub Actions (e.g., actions/checkout, actions/setup-node) and eliminates runtime dependency resolution entirely.
References
Summary
This action uses
npx @datadog/datadog-ci@latestat runtime to install and execute the Datadog CI package. This means every dependency (and transitive dependency) is resolved fresh from npm on each workflow run, with no lockfile or integrity verification. This recently resulted in a real-world supply chain compromise affecting users of this action.What happened
A malicious version of
axios(1.14.1) was published to npm. Because@datadog/datadog-cideclares"axios": "^1.13.5"as a dependency, npm resolved it to the compromised version at install time. The attack chain was:Why pinning doesn't help
Even if users pin this action by SHA and set
datadog-ci-versionto a specific version like5.10.0, it doesn't help. The transitive dependencies are still resolved via semver ranges at runtime. There is no lockfile involved when usingnpx, so users have no way to protect themselves from this class of attack.Suggested fix
Bundle the action's dependencies at build time instead of installing them at runtime. Specifically:
@vercel/ncc(or similar) to compile@datadog/datadog-ciand all its dependencies into a singledist/index.jscomposite(with a bashnpxcall) tonode24(with a pre-built entry point)package-lock.jsonso that dependency versions are locked at publish time, not resolved at runtimeThis is the standard approach used by most GitHub Actions (e.g.,
actions/checkout,actions/setup-node) and eliminates runtime dependency resolution entirely.References