For the last year, the JavaScript ecosystem has been on a collective mission to harden the software supply chain. We’ve adopted what many call the “Shai-Hulud” playbook: we pin every version in a lockfile, we audit for typosquatting, and most importantly, we run npm install –ignore-scripts in our CI/CD pipelines to prevent malicious post-install hooks from exfiltrating environment variables.
We thought we had closed the door. But as recent research into “PackageGate” reveals, if your project relies on Git-based dependencies, that door might still be unlatched.
The Shai-Hulud Baseline (And Why It’s Not Enough)
The “Shai-Hulud” mitigations were created after a surge of malware was found in preinstall and postinstall scripts. Disabling script execution during installation helped DevOps teams block the main way supply chain attacks happened. The idea was straightforward: if code does not run during npm install, it cannot steal your NPM_TOKEN or AWS_SECRET_KEY.
However, this approach assumes the package manager only downloads a static tarball from a registry. When you add Git dependencies by using a repository URL instead of a version number, the package manager acts differently. It is not just a downloader anymore; it also runs Git commands.
The Core Issue: When Git Becomes the Execution Engine
Research recently published by Koi highlights a significant blind spot in how package managers handle Git-based dependencies. This isn’t just about a malicious script inside a package.json. It’s about how the configuration of the dependency itself can influence the execution of the package manager on your machine or build server.
In the case of npm, researchers found that a malicious Git dependency could use a crafted .npmrc file to influence how Git is invoked. Because Git dependencies often require the package manager to clone, fetch, and sometimes “prepare” the source code, the toolchain may execute logic that falls outside the scope of –ignore-scripts.
Essentially, the trust boundary shifts. You aren’t just trusting the code in the package; you are trusting the package manager’s ability to safely interact with a remote Git binary while processing an untrusted repository. As BleepingComputer reported, these “PackageGate” vulnerabilities allow attackers to bypass standard defenses because the execution happens during the resolution and fetching phase, long before the “install” phase—where your security flags live—even begins.
The Ecosystem Response: pnpm, Bun, and vlt
While the research suggests that npm has been slow to address these specific Git-based vectors, other players in the ecosystem have moved quickly to close the gaps.
For example, pnpm recently addressed two critical vulnerabilities, CVE-2025-69264 and CVE-2025-69263. These vulnerabilities highlighted that even when scripts were disabled, certain Git dependency processing tasks could still lead to unintended command execution. By shipping these fixes, pnpm has signaled that Git-based fetching must be treated with the same “zero-trust” approach as install scripts.
Similarly, newer tools like Bun and vlt have implemented stricter controls over how sub-processes are spawned during dependency resolution to ensure that a malicious repository cannot “escape” the sandbox of a standard install.
Why This Bites in CI/CD
In a local development environment, these risks are high. In a CI/CD pipeline, they are catastrophic. Modern pipelines are often:
- Highly Privileged: They hold the keys to your production infrastructure and internal package registries.
- Ephemeral but Connected: While the runner disappears, it has a window of time to send secrets to a remote listener.
- Transitive Victims: You might not have a Git dependency in your package.json, but one of your dependencies might.
If an attacker can trigger a Git-based execution during the install phase of your build, they don’t need a “malicious package” in the traditional sense. They just need to point a dependency at a repo that messes with the package manager’s environment.
Defensive Signals: What to Look For
You cannot defend what you cannot see. If you are managing a platform or a CI/CD stack, start looking for these signals:
- Dependency Source Drift: Use a scanner or a simple grep on your lockfiles to find git+ssh://, git+https://, or raw GitHub URLs. These should be the exception, not the rule.
- Unexpected Git Invocations: In your build logs, monitor for Git activity during the dependency fetch phase. If a “standard” registry install is suddenly spawning git clone for a deep transitive dependency, that’s a red flag.
- Network Anomalies: Use CI providers that allow you to restrict network egress. Does your build runner really need to talk to a random IP over port 9418 (Git) or 443 during the install phase?
Layered Remediation for Engineering Teams
We recommend a “defense in depth” approach to close the PackageGate gap:
- Policy: Ban Git Dependencies by Default. Set a repository-wide policy that all dependencies must come from a named registry (public or private). If a team needs a Git dependency, it should require an explicit CODEOWNERS approval and a security review.
- Pin to SHAs, Not Branches. Never use main or develop as a Git dependency reference. Use a full commit SHA. This prevents an attacker from “force-pushing” a malicious update to a repository you thought was safe.
- Upgrade Your Tools. If you use pnpm, ensure you are on the latest version to mitigate CVE-2025-69264. If you use npm, be aware that the –ignore-scripts flag may not be the silver bullet you think it is for Git-based repos.
- Isolation. Run npm install in a container with restricted environment variables. Inject your production secrets after the installation phase is complete and the node_modules are locked down.
Compliance and Risk Mapping
For those navigating SOC 2 or ISO 27001, PackageGate falls squarely under Third-Party Risk Management and Secure Build Configuration.
- Change Control: Locking down Git URLs ensures that your dependency tree is immutable and auditable.
- Logging & Monitoring: Detecting unusual Git sub-processes satisfies the requirement for monitoring unauthorized changes in the build environment.
Closing Thoughts
The shift from registry tarballs to Git-based dependencies has introduced a layer of complexity that our current security flags weren’t fully prepared for. While “ignore-scripts” remains a vital tool, it is not a complete shield.
The lesson of PackageGate is clear: the package manager is a powerful execution engine. We need to treat it with the same caution we afford to the code we write ourselves.
Key Takeaways:
- The Git Bypass: Git dependencies can trigger executions via package manager logic that –ignore-scripts often misses.
- Ecosystem Fixes: pnpm has patched major Git-related vulnerabilities (CVE-2025-69264); ensure your version is current.
- CI/CD Hardening: Move secret injection to the “post-install” phase and audit your lockfiles for raw Git URLs.
- Zero Trust: Treat every Git-based dependency as a potential execution vector, regardless of your install flags.
If your team needs a comprehensive review of your CI/CD supply chain or help hardening your build pipelines against emerging dependency threats, reach out to us at SecurifyAI.
