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
Published September 3, 2026Reviewed 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.


Prevention & Best Practices

1. Never Use * or latest in Published Package Dependencies

For any package you publish to npm, treat * and latest as red flags in your dependencies and peerDependencies. Use explicit semver ranges. Tools like npm-check and depcheck can help audit your constraints.

2. Commit and Verify Lockfiles

For applications (not libraries), commit your package-lock.json or yarn.lock. In CI, use npm ci instead of npm install — it installs exclusively from the lockfile and fails if the lockfile doesn't match package.json.

3. Enable npm audit in CI Pipelines

Add npm audit --audit-level=high as a CI step. This catches known vulnerabilities in resolved dependencies before they reach production.

4. Consider Subresource Integrity and Package Provenance

For high-security contexts, explore npm's provenance attestations and tools like Socket.dev that analyze package behavior — not just known CVEs — to detect suspicious new versions of dependencies.

5. Use Dependabot or Renovate for Automated Dependency Updates

Automated tools like GitHub Dependabot or Renovate Bot will open PRs when new versions of your dependencies are released, keeping you on known-good versions without requiring manual monitoring.

Relevant Standards

  • OWASP A06:2021 – Vulnerable and Outdated Components: Directly addresses the risk of uncontrolled third-party dependency versions.
  • CWE-829: Inclusion of Functionality from Untrusted Control Sphere — the CWE that most precisely describes this vulnerability pattern.
  • SLSA (Supply-chain Levels for Software Artifacts): A framework for improving supply chain integrity, including dependency pinning practices.

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.


References

Frequently Asked Questions

What is a wildcard npm dependency vulnerability?

A wildcard (`*`) version constraint in `package.json` tells npm to accept any published version of a package. If that package is ever compromised or a malicious version is published, it will be automatically installed by anyone running `npm install`, with no version gating.

How do you prevent supply chain attacks via npm in Node.js?

Pin dependencies to specific semver ranges (e.g., `^4.0.4`), use a lockfile (`package-lock.json` or `yarn.lock`), enable npm audit in CI, and consider tools like Socket.dev or Dependabot to monitor for suspicious package updates.

What CWE is a wildcard npm dependency vulnerability?

CWE-829 (Inclusion of Functionality from Untrusted Control Sphere) most directly applies, as the application includes third-party code without sufficient version controls. CWE-1104 (Use of Unmaintained Third-Party Components) is also relevant.

Is a lockfile enough to prevent supply chain attacks from wildcard dependencies?

A lockfile helps in single-project contexts by recording resolved versions, but it does not protect downstream consumers of a published library — they generate their own lockfile from your `package.json` constraints. Wildcard constraints remain dangerous for published packages even with a lockfile present.

Can static analysis detect wildcard npm dependency vulnerabilities?

Yes. Tools like Semgrep, Snyk, Socket.dev, and npm audit can flag wildcard or overly permissive version constraints in `package.json`. Orbis AppSec's multi-agent AI scanner flagged this exact pattern in `package.json:1`.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #28

Related Articles

critical

How dependency confusion attacks happen in Node.js package.json and how to fix it

The avim-chrome browser extension used caret (^) version ranges in package.json devDependencies, allowing automatic installation of newer minor/patch versions without review. This created a supply chain attack vector where compromised versions of htmlclean, jshint, terser, or yazl could be automatically pulled into the build process. The fix pins all devDependencies to exact versions, preventing unauthorized code from entering the build pipeline.

critical

How Supply Chain Attacks Happen via pnpm Workspace Configuration and How to Fix Them

A pnpm workspace configuration was missing the `minimumReleaseAge` setting, leaving the project vulnerable to supply chain attacks from newly published malicious or compromised npm packages. By adding `minimumReleaseAge: 10080` (seven days in minutes), the fix ensures that only packages that have survived community scrutiny for at least a week are resolved during installation. This defensive hardening is especially critical for web applications where a compromised dependency could introduce XSS,

critical

How Server-Side Request Forgery happens in Python FastAPI and how to fix it

A critical Server-Side Request Forgery (SSRF) vulnerability was discovered in app.py where the `/parse` and `/parse-video` endpoints accepted user-supplied URLs with only substring validation. The application checked if 'doubao.com' appeared anywhere in the URL string, allowing attackers to bypass this check and access internal services, cloud metadata endpoints, or scan the internal network. The fix implemented proper hostname parsing with an allowlist of legitimate domains.

critical

How a vulnerable websocket-driver dependency happens in Node.js lockfiles and how to fix it

A Trivy scan flagged `websocket-driver@0.7.4` in this repository's `bun.lock` as affected by CVE-2026-54466, a critical issue in a WebSocket protocol handler that parses untrusted HTTP upgrade requests and frame data. The fix upgrades the package to `0.7.5` and adds an explicit `websocket-driver` entry to the lockfile's override block so every transitive consumer — webpack-dev-server, sockjs, faye-websocket — resolves to the patched build instead of the pinned vulnerable one.

high

How Dependabot Missing Cooldown Periods Enable Supply Chain Attacks and How to Fix It

A critical security vulnerability in `.github/dependabot.yml` was exposing a Node.js library to supply chain attacks by automatically updating to newly published packages without a safety delay. By adding a 7-day cooldown period to each package ecosystem configuration, the project now protects against malicious or unstable package versions that could affect downstream consumers.

critical

How Missing Authentication on DELETE Endpoints Happens in Node.js Express and How to Fix It

A critical authentication bypass vulnerability was discovered in the skill-cabinet server where the DELETE /api/skills/:id endpoint allowed any unauthenticated user to delete arbitrary skills from the filesystem. The fix implements loopback origin validation to ensure only requests from localhost can perform destructive operations, while also consolidating delete functionality into a single, protected endpoint.