Back to Blog
critical SEVERITY7 min read

How Wildcard Dependency Constraints Happen in Node.js and how to fix them

A critical supply chain vulnerability was discovered in the `package.json` of the `bpmn-js-task-resize` library, where wildcard (`*`) version constraints for `bpmn-js` and `diagram-js` allowed any version of those packages to be installed — including a maliciously compromised one. By pinning these dependencies to specific semver ranges (`^4.0.4` and `^4.0.3` respectively), the attack surface is dramatically reduced. This fix protects downstream consumers of the library from unknowingly executing

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published September 3, 2026•Reviewed September 3, 2026

Answer Summary

This vulnerability is a supply chain attack risk (CWE-1104: Use of Unmaintained Third-Party Components / CWE-829: Inclusion of Functionality from Untrusted Control Sphere) in the Node.js `package.json` manifest of `bpmn-js-task-resize`. Wildcard (`*`) version constraints for `bpmn-js` and `diagram-js` meant that `npm install` could resolve to any published version, including a future malicious release. The fix pins these dependencies to `^4.0.4` and `^4.0.3` respectively, ensuring only known-good minor/patch updates are accepted and eliminating the unbounded version resolution window exploited in supply chain attacks.

Vulnerability at a Glance

cweCWE-829 (Inclusion of Functionality from Untrusted Control Sphere)
fixPinned both dependencies to specific semver ranges (`bpmn-js@^4.0.4`, `diagram-js@^4.0.3`)
riskMalicious npm package version automatically installed and executed in downstream consumers' browsers
languageJavaScript / Node.js
root causeWildcard (`*`) version constraints in `package.json` for `bpmn-js` and `diagram-js` impose no upper or lower bound on resolved package versions
vulnerabilityUnpinned/Wildcard npm Dependency (Supply Chain Risk)

The Risk Hidden in a Single Character: * in Your package.json

The package.json file is the beating heart of any Node.js project — it declares what your project is, how to build it, and critically, what it depends on. In the bpmn-js-task-resize library, two lines in this file contained a single character that quietly opened a supply chain attack vector affecting every downstream consumer of the package:

"bpmn-js": "*",
"diagram-js": "*"

That * is a wildcard version constraint. It tells npm: "I'll take any version of this package." And in a world where npm package hijacking and dependency confusion attacks are increasingly common, that's an open invitation for trouble.


The Vulnerability Explained

What Does * Actually Mean?

When npm resolves a * version constraint, it fetches the latest published version of the package at the time of installation. There is no floor and no ceiling — no minimum version required, no maximum version blocked. Every npm install is a fresh roll of the dice.

Here's the vulnerable section of package.json before the fix:

"dependencies": {
  "bpmn-js": "*",
  "diagram-js": "*"
}

For a library like bpmn-js-task-resize — which is itself a published npm package consumed by other projects — this is especially dangerous. When a downstream developer adds bpmn-js-task-resize to their own project and runs npm install, npm will also resolve bpmn-js and diagram-js using the * constraint. Their lockfile is generated from scratch based on what's currently published on the npm registry.

The Attack Scenario

Consider this realistic attack chain:

  1. An attacker gains publish access to the bpmn-js or diagram-js npm package — either by compromising maintainer credentials, exploiting a typosquatting opportunity, or through a dependency confusion attack targeting private package namespaces.

  2. The attacker publishes bpmn-js@99.0.0 containing malicious code — a cryptominer, a credential stealer, or a script that exfiltrates diagram data (which may contain sensitive business process information) to an external server.

  3. A developer working on a downstream project runs npm install bpmn-js-task-resize. Because the constraint is *, npm happily resolves bpmn-js to 99.0.0 — the latest available version.

  4. The malicious code is now bundled into the downstream application and executes in end-user browsers during BPMN diagram rendering or editing. BPMN diagrams often model sensitive business workflows, making this data particularly valuable.

  5. The downstream developer has no idea anything is wrong. Their package.json only references bpmn-js-task-resize, not bpmn-js directly.

Why This Is Especially Risky for a Library Package

If this were a standalone application with a committed package-lock.json, the lockfile would pin the resolved version and partially mitigate the risk (though the lockfile itself could be tampered with). But bpmn-js-task-resize is a library — a package consumed by others. Downstream consumers generate their own lockfiles. The * constraint in this library's package.json propagates directly into those consumers' dependency resolution, with no protection from the library's own lockfile.

This is precisely why npm's own documentation and security best practices explicitly warn against wildcard constraints in published packages.


The Fix

The fix is surgical and precise — two lines changed in package.json:

 "dependencies": {
-  "bpmn-js": "*",
-  "diagram-js": "*"
+  "bpmn-js": "^4.0.4",
+  "diagram-js": "^4.0.3"
 }

What This Change Does

By replacing * with ^4.0.4 and ^4.0.3, the fix establishes a semver floor and a bounded ceiling:

  • ^4.0.4 means: accept bpmn-js versions >=4.0.4 and <5.0.0. This allows bug fixes and non-breaking feature additions, but blocks major version jumps that could introduce breaking or malicious changes.
  • ^4.0.3 means: accept diagram-js versions >=4.0.3 and <5.0.0. Same protection applies.

This is the npm community's recommended constraint style for library dependencies — it balances security (bounded range) with maintainability (automatic patch/minor updates).

Before vs. After: Security Impact

Before After
Accepted versions Any version ever published >=4.0.4 <5.0.0 / >=4.0.3 <5.0.0
Malicious v99.0.0 accepted? ✅ Yes ❌ No
Patch updates accepted? ✅ Yes ✅ Yes
Breaking major version accepted? ✅ Yes ❌ No
Downstream consumers protected? ❌ No ✅ Yes

The fix also implicitly documents the known-good version of these dependencies — 4.0.4 and 4.0.3 — giving future maintainers a clear baseline to reason about compatibility.


Key Takeaways

  • Wildcard * constraints in a published library's package.json are not just sloppy — they're a security vulnerability that affects every downstream consumer who runs npm install.
  • bpmn-js and diagram-js are rendering engines that execute in user browsers; a compromised version of either could silently exfiltrate sensitive BPMN diagram data or execute arbitrary JavaScript.
  • Lockfiles do not protect library consumers — only the constraints in package.json govern what versions downstream projects resolve.
  • Pinning to ^4.0.4 and ^4.0.3 is the minimal correct fix — it preserves the ability to receive safe patch updates while blocking the unbounded version window that enabled the attack.
  • One character (*) in a manifest file can create a supply chain risk affecting an entire ecosystem of downstream users — dependency constraints deserve the same security scrutiny as application code.

How Orbis AppSec Detected This

  • Source: The dependencies block in package.json, specifically the version constraint fields for bpmn-js and diagram-js.
  • Sink: The npm registry resolution process — any npm install invocation by a downstream consumer would resolve these fields against all publicly published package versions, including future malicious ones.
  • Missing control: No version floor or ceiling was specified. The * wildcard imposed zero constraints on which package version would be fetched and executed.
  • CWE: CWE-829 — Inclusion of Functionality from Untrusted Control Sphere.
  • Fix: Replaced "bpmn-js": "*" with "bpmn-js": "^4.0.4" and "diagram-js": "*" with "diagram-js": "^4.0.3", establishing a bounded semver range that prevents resolution of unknown future versions.

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

Supply chain attacks via npm have become one of the most impactful and underappreciated attack vectors in modern software development. The bpmn-js-task-resize vulnerability is a textbook example of how a single permissive character — * — in a dependency manifest can expose an entire ecosystem of downstream users to arbitrary code execution in their users' browsers.

The fix is simple, non-breaking, and immediately effective: pin bpmn-js to ^4.0.4 and diagram-js to ^4.0.3. But the broader lesson is that dependency constraints in published packages are a security boundary, not just a compatibility hint. Treat them accordingly — audit them, pin them, and monitor them with the same rigor you'd apply to your application code.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #28

Related Articles

high

CWE-778: Tribute WebHookHandler Logs No Subscription Events

The Tribute payment webhook handler verified request signatures and then mutated subscription state — granting new subscriptions and cancelling existing ones — while logging nothing on success. Only error paths and a no-op test hook produced log lines, so a forged or replayed `NewSubscription` event that passed signature verification left no record of which `TelegramUserID` was affected. The fix adds structured `slog.Info` records at signature verification and at both state-changing branches.

medium

path-to-regexp 0.1.12 DoS: Catastrophic Backtracking on Malformed URL

path-to-regexp version 0.1.12 contains a regular expression engine vulnerability where maliciously crafted URL parameters trigger exponential backtracking, causing CPU exhaustion and service unavailability. Upgrading to version 0.1.13 eliminates the vulnerable pattern from the parsing logic.

critical

CVE-2026-59873: node-tar 7.5.11 DoS via Crafted Gzip Bomb

node-tar versions 7.5.11 through 7.5.18 are vulnerable to a denial-of-service attack through maliciously crafted gzip archives that decompress to disproportionately large sizes. An attacker can exploit this to exhaust memory and CPU resources by submitting a small, highly compressed archive that expands beyond configured limits during extraction.

high

MapManager.get() Race Condition Duplicates API Requests

The MapManager's `get(mapUid, cache)` method used a check-then-act pattern that permitted multiple concurrent requests to pass the cache miss check simultaneously, triggering redundant API calls and risking cache corruption. The fix introduces a `_pending` promise map to deduplicate in-flight fetches for identical map UIDs.

critical

Lampa Desktop Auto-Update Heuristic Bypass: Execution of Unverified

Lampa Desktop's auto-update mechanism downloaded JavaScript and CSS from `raw.githubusercontent.com` using only heuristic validation—file size thresholds and string pattern matching—that attackers could trivially satisfy. The fix introduces cryptographic integrity verification by cross-referencing Git blob hashes from the GitHub Contents API, ensuring downloaded code matches the repository's authoritative state before execution.

high

adm-zip 0.6.0 Preserves SUID Bits From ZIPs: CVE-2026-102282

The `adm-zip` dependency resolved to 0.6.0 in this project's dependency tree, a version affected by CVE-2026-102282: during extraction it applies the Unix permission bits stored in each ZIP entry's external file attributes verbatim, including the setuid (`04000`), setgid (`02000`), and sticky bits. An attacker who controls an archive passed to `extractAllTo()` or `extractEntryTo()` can therefore have the extractor create a setuid binary owned by whatever user the extraction process runs as. The