Back to Blog
high SEVERITY7 min read

How Inherited Dependency Vulnerabilities Happen in Node.js and how to fix it

A vulnerability in the `tmp` Node.js package (CVE-2026-44705) was discovered lurking as a transitive dependency via `tmp-promise@3.0.3`, leaving applications exposed to unsafe temporary file handling. The fix pins `tmp` to version `0.2.7` using a pnpm override across `package.json`, `dist/cli.js`, and `pnpm-lock.yaml`, eliminating the vulnerable code path without affecting any valid application behavior.

O
By Orbis AppSec
Published August 26, 2026Reviewed August 26, 2026

Answer Summary

CVE-2026-44705 is a HIGH-severity vulnerability in the `tmp` Node.js package (versions prior to 0.2.6) that allows unsafe handling of temporary files and directories, potentially enabling symlink attacks or insecure temp file creation. The vulnerability surfaces as a transitive dependency through `tmp-promise@3.0.3`. The fix, aligned with CWE-377 (Insecure Temporary File), is to override the `tmp` dependency to version `0.2.7` in `package.json` and `pnpm-lock.yaml`, preventing the vulnerable version from being resolved anywhere in the dependency tree.

Vulnerability at a Glance

cweCWE-377
fixPin `tmp` to `0.2.7` via a pnpm override in `package.json` and `pnpm-lock.yaml`
riskAttackers may exploit unsafe temp file creation to perform symlink attacks, race conditions, or information disclosure
languageJavaScript / Node.js
root cause`tmp@0.2.5` (pulled in transitively by `tmp-promise@3.0.3`) contained unsafe temporary file handling logic
vulnerabilityInsecure Temporary File Creation (CVE-2026-44705)

How Inherited Dependency Vulnerabilities Happen in Node.js and How to Fix It

The pnpm-lock.yaml file in this project quietly contained a ticking clock: tmp@0.2.5, a transitive dependency pulled in by tmp-promise@3.0.3, carried CVE-2026-44705 — a HIGH-severity vulnerability in temporary file handling. No direct code change introduced it. No developer consciously chose it. It arrived as invisible cargo inside another package, and it would have stayed invisible without automated scanning.

This post walks through exactly what happened, why it matters, and how a targeted pnpm override resolved it across three files.


The Vulnerability Explained

What Is CVE-2026-44705?

tmp is a widely-used Node.js library for creating temporary files and directories. Prior to version 0.2.6, it contained unsafe temporary file creation logic — the kind of flaw covered by CWE-377: Insecure Temporary File.

Insecure temp file creation typically involves one or more of the following weaknesses:

  • Predictable file names that attackers can guess and pre-create as symlinks
  • Race conditions (TOCTOU) between checking whether a temp path exists and actually creating the file
  • Insufficient permission bits on created temp files, allowing other local users to read or write them

In the case of CVE-2026-44705 specifically, tmp versions before 0.2.6 did not adequately guard against these conditions, leaving any application that creates temporary files via this library open to local privilege escalation or information disclosure.

How It Arrived: The Transitive Dependency Chain

The project did not directly depend on tmp. It depended on tmp-promise@3.0.3, a promise-based wrapper around tmp. And tmp-promise@3.0.3 pulled in tmp@0.2.5 — the vulnerable version.

You can see this clearly in the lockfile snapshot before the fix:

# pnpm-lock.yaml (BEFORE)
tmp-promise@3.0.3:
  resolution: {integrity: sha512-RwM7MoPojPxs...}

tmp@0.2.5:
  resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/...}
  engines: {node: '>=14.14'}

And in the snapshots section:

# pnpm-lock.yaml snapshots (BEFORE)
tmp-promise@3.0.3:
  dependencies:
    tmp: 0.2.5

tmp@0.2.5: {}

This is a classic transitive dependency vulnerability: the vulnerable package is two levels deep in the dependency graph, invisible to a developer scanning only their package.json.

Attack Scenario

Imagine this application runs on a shared Linux server or inside a CI/CD pipeline where multiple processes share a filesystem. A component of the application uses tmp-promise to create a temporary file for intermediate processing — perhaps staging output from the esbuild build step or writing a temporary config file.

With tmp@0.2.5:

  1. The application calls tmp.file() or tmp.dir() to create a temp path.
  2. An attacker process (running as a different user on the same system) predicts the temp file name based on the predictable naming scheme.
  3. The attacker pre-creates a symlink at that path pointing to a sensitive file (e.g., /etc/passwd or an SSH key).
  4. When the application writes to the "temp file," it actually writes to the symlink target — overwriting a sensitive system file or leaking data.

This is a TOCTOU (Time-of-Check to Time-of-Use) race condition, and it's especially dangerous in automated build pipelines where temp files are created and destroyed rapidly.


The Fix

Strategy: pnpm Dependency Override

Since tmp is a transitive dependency (not a direct one), simply updating tmp-promise in package.json wouldn't help — tmp-promise@3.0.3 still resolves tmp@0.2.5. The correct fix is to use a pnpm override, which forces the entire dependency tree to use a specific version of a package regardless of what upstream packages request.

The fix added "tmp": "0.2.7" to the pnpm.overrides section in package.json:

Before:

"pnpm": {
  "overrides": {
    "sharp": "^0.34.5",
    "@img/sharp-libvips-darwin-arm64": "1.2.4"
  }
}

After:

"pnpm": {
  "overrides": {
    "sharp": "^0.34.5",
    "@img/sharp-libvips-darwin-arm64": "1.2.4",
    "tmp": "0.2.7"
  }
}

This single addition tells pnpm: no matter who asks for tmp, give them 0.2.7.

The Lockfile Update

The pnpm-lock.yaml reflects the resolved change. The resolution hash changes from the 0.2.5 integrity value to the 0.2.7 value:

# pnpm-lock.yaml (AFTER)
-  tmp@0.2.5:
-    resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==}
+  tmp@0.2.7:
+    resolution: {integrity: sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==}
     engines: {node: '>=14.14'}

And the snapshot for tmp-promise now correctly resolves to the safe version:

# snapshots (AFTER)
tmp-promise@3.0.3:
  dependencies:
-    tmp: 0.2.5
+    tmp: 0.2.7

The dist/cli.js Update

The compiled dist/cli.js also embeds the package configuration, so it received the same override addition:

// dist/cli.js (AFTER)
var pnpm = {
  overrides: {
    sharp: "^0.34.5",
    "@img/sharp-libvips-darwin-arm64": "1.2.4",
    tmp: "0.2.7"   // <-- added
  },
  ...
}

This ensures that any tooling consuming the compiled CLI bundle also reflects the correct dependency policy.

Why 0.2.7 Instead of 0.2.6?

The PR title references 0.2.6 as the minimum safe version (the first version to address CVE-2026-44705), but the actual fix pins to 0.2.7 — a patch release that includes additional hardening on top of the CVE fix. Pinning to the latest patch version is the safer choice when the API surface is unchanged.


Prevention & Best Practices

1. Audit Transitive Dependencies Regularly

Your direct dependencies are only the tip of the iceberg. Use lockfile-aware scanners that traverse the full dependency graph:

# Trivy (detected this issue)
trivy fs --scanners vuln .

# npm audit (works with pnpm via compatibility layer)
pnpm audit

# Snyk
snyk test

2. Use Package Manager Overrides for Transitive Fixes

When a vulnerability lives in a transitive dependency, overrides are the correct tool:

  • pnpm: pnpm.overrides in package.json
  • npm: overrides in package.json (npm 8.3+)
  • yarn: resolutions in package.json

3. Commit and Review Your Lockfile

The pnpm-lock.yaml file is security-critical. Always commit it, review changes to it in PRs, and treat unexpected version bumps as a potential supply chain concern.

4. Avoid Insecure Temp File Patterns in Your Own Code

If you write code that creates temporary files directly (without a library), follow these rules:

  • Use fs.mkstemp-equivalent APIs that atomically create files with restricted permissions
  • Never construct temp file paths by concatenating predictable strings
  • Always use O_EXCL flag when creating temp files to prevent TOCTOU races
  • Clean up temp files in finally blocks or use libraries that register cleanup handlers

5. Reference Standards


Key Takeaways

  • tmp@0.2.5 is vulnerable; the safe floor is 0.2.6, and 0.2.7 is the recommended pin — this specific version boundary is what CVE-2026-44705 is about.
  • tmp-promise@3.0.3 acts as a silent carrier — it resolves the vulnerable tmp version without any warning in your direct dependency list.
  • A pnpm override in package.json is the correct fix when you cannot update the direct dependent (tmp-promise) itself; it forces the safe version across the entire tree.
  • Lockfile integrity matters — the resolution hash in pnpm-lock.yaml changed from sha512-voyz6MA... to sha512-e0votIpp..., providing a cryptographic guarantee that the correct package is installed.
  • Compiled artifacts like dist/cli.js also embed dependency policy — forgetting to update them would leave the documented configuration inconsistent with the actual security posture.

How Orbis AppSec Detected This

  • Source: The pnpm-lock.yaml lockfile, which resolved tmp-promise@3.0.3's dependency to tmp@0.2.5
  • Sink: Any call site within the application that invokes tmp.file() or tmp.dir() via the tmp-promise wrapper, creating temporary files with unsafe guarantees
  • Missing control: No version override existed to prevent pnpm from resolving the vulnerable tmp@0.2.5 version, and no minimum-version constraint was enforced on the transitive dependency
  • CWE: CWE-377 — Insecure Temporary File
  • Fix: Added "tmp": "0.2.7" to the pnpm.overrides section in package.json and updated pnpm-lock.yaml and dist/cli.js to reflect the pinned safe version

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

CVE-2026-44705 is a reminder that your application's security posture is only as strong as its deepest dependency. The tmp package vulnerability didn't arrive through a developer mistake or a bad architectural decision — it arrived silently, two levels deep in the dependency graph, carried by a perfectly reasonable library choice (tmp-promise).

The fix is surgical and non-breaking: a single pnpm override pins tmp to 0.2.7 across the entire tree, closing the vulnerability without touching any application logic. Three files changed, zero behavior changed, one CVE eliminated.

The broader lesson: lockfile-aware vulnerability scanning isn't optional. Tools like Trivy that read your pnpm-lock.yaml and trace the full resolution graph are the only reliable way to catch vulnerabilities like this before they reach production.


References

Frequently Asked Questions

What is CVE-2026-44705?

CVE-2026-44705 is a HIGH-severity vulnerability in the `tmp` Node.js package before version 0.2.6 that involves insecure handling of temporary files and directories, potentially enabling symlink attacks or race conditions during temp file creation.

How do you prevent insecure temporary file vulnerabilities in Node.js?

Use patched versions of temp file libraries, prefer OS-level secure temp file APIs, and use dependency overrides in your package manager (npm, pnpm, yarn) to force safe versions of transitive dependencies.

What CWE is insecure temporary file creation?

CWE-377 — Insecure Temporary File. It describes situations where a program creates a temporary file in an insecure manner, exposing it to manipulation by other processes.

Is updating the direct dependency enough to prevent this vulnerability?

Not always. When the vulnerable package is a transitive dependency (pulled in by another library like `tmp-promise`), you must use a package manager override to force the safe version across the entire dependency tree.

Can static analysis detect insecure temporary file vulnerabilities?

Yes. Tools like Trivy, Snyk, and npm audit can identify known-vulnerable versions of packages in your dependency tree, including transitive dependencies. Trivy flagged this exact issue in `pnpm-lock.yaml`.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #1340

Related Articles

high

How Dependabot Missing Cooldown happens in GitHub Actions and how to fix it

A high-severity misconfiguration in `.github/dependabot.yml` left this Node.js library without a cooldown period, meaning Dependabot would immediately propose updates to newly published packages — including potentially malicious or unstable ones. The fix adds a `cooldown` block with `default-days: 7` to both the `npm` and `github-actions` package ecosystem entries, introducing a mandatory 7-day waiting period before any new package version is surfaced as an update candidate.

critical

How CSRF Protection Failures Happen in FastAPI and How to Fix Them

A critical CORS misconfiguration in `backend/main.py` allowed cookies to be sent alongside wildcard-origin requests, violating the CORS specification and opening the door to cross-site request forgery attacks. The fix conditionally disables `allow_credentials` when the allowed origins list contains a wildcard, bringing the configuration into compliance with browser security rules. This change closes a subtle but dangerous gap that could have let attackers on sibling subdomains forge authenticate

critical

How Missing Rate Limiting Happens in Node.js SSE Handlers and How to Fix It

A critical missing rate-limiting control in `src/sse/handlers/chat.js` allowed any caller to flood the SSE chat endpoint with unlimited requests, risking server resource exhaustion, denial of service, and runaway AI provider API costs. The fix introduces a per-IP sliding-window rate limiter that caps requests at 60 per minute and returns HTTP 429 on violations. Because the endpoint was publicly reachable and only validated API keys — not request frequency — exploitation required nothing more tha

medium

How Denial of Service via Catastrophic Backtracking happens in Node.js and how to fix it

CVE-2026-4867 is a Denial of Service vulnerability in path-to-regexp 0.1.12 where malformed URL parameters can trigger catastrophic backtracking in the library's regular expression engine, allowing an attacker to hang or crash a Node.js application with a single crafted request. The fix upgrades path-to-regexp to version 0.1.13, which patches the vulnerable regex patterns. This change was applied via a package-level override to ensure the patched version is used throughout the entire dependency

high

How Denial of Service via Exponential-Time Complexity happens in Node.js and how to fix it

CVE-2026-13149 is a high-severity Denial of Service vulnerability in the `brace-expansion` npm package, where crafted input strings trigger exponential-time processing that can freeze or crash a Node.js application. The fix upgrades `brace-expansion` from `2.0.2` to `2.1.4` and `minimatch` from `5.1.6` to `5.1.9`, along with npm `overrides` to ensure the patched versions are used throughout the entire dependency tree.

critical

How Unrestricted File Upload happens in Node.js/Express and how to fix it

A critical unrestricted file upload vulnerability was discovered in `mainsystem/routes/admin/profile.js`, where the avatar upload endpoint accepted any file type without validation. An authenticated attacker could upload a malicious server-side script to a web-accessible directory and execute arbitrary code on the server. The fix adds MIME type filtering, an allowlist of safe image formats, and a 2 MB file size limit to the multer middleware.