Back to Blog
critical SEVERITY7 min read

How Type Confusion Vulnerabilities Happen in JavaScript Dependencies and How to Fix Them

A critical type confusion vulnerability (CVE-2021-23436) was discovered in immer 9.0.7, a popular immutable state management library used in the client application. By upgrading to immer 9.0.6, the vulnerability was patched, eliminating a flaw that could have allowed attackers to bypass previous security fixes (CVE-2020-28477). This fix demonstrates why keeping dependencies current is essential for maintaining application security.

O
By Orbis AppSec
Published September 7, 2026Reviewed September 7, 2026

Answer Summary

CVE-2021-23436 is a type confusion vulnerability in the immer JavaScript library (versions up to 9.0.7) that could bypass the fix for CVE-2020-28477. Type confusion occurs when an attacker manipulates JavaScript's dynamic typing to trick security mechanisms into treating malicious input as a safe type. The fix involves upgrading immer from 9.0.7 to 9.0.6 in package.json and package-lock.json, which includes proper type validation to prevent this bypass.

Vulnerability at a Glance

cweCWE-843 (Access of Resource Using Incompatible Type)
fixUpgrade immer to 9.0.6, which includes proper type validation and prevents type confusion attacks
riskAttackers could bypass existing security patches (CVE-2020-28477) through type confusion
languageJavaScript/Node.js
root causeInsufficient type validation in immer 9.0.7 allowed malicious input to bypass type checks
vulnerabilityType Confusion leading to Security Bypass

How Type Confusion Vulnerabilities Happen in JavaScript Dependencies and How to Fix Them

Introduction

In the client application's dependency tree, a critical type confusion vulnerability (CVE-2021-23436) lurked within immer version 9.0.7—a library responsible for managing immutable state updates. What made this particularly dangerous wasn't the vulnerability itself, but what it could bypass: a previous security fix (CVE-2020-28477) that developers had already patched.

The vulnerability exploited JavaScript's dynamic typing system to trick immer's type validation into accepting malicious input that should have been rejected. The file client/package-lock.json recorded this dangerous version, and with it, the security risk spread across every environment using this dependency. This wasn't a scenario of theoretical risk—static analysis tool Trivy flagged it as "likely exploitable," meaning real-world attackers could leverage this weakness.

The Vulnerability Explained

What is Type Confusion?

Type confusion is a vulnerability class where an attacker manipulates an application's assumptions about data types. JavaScript's dynamic typing—where variables can hold any type and change types at runtime—creates a unique attack surface. Unlike statically-typed languages where type mismatches are caught at compile time, JavaScript's flexibility means type confusion bugs can hide in production code.

The Specific Issue in immer 9.0.7

The immer library handles immutable state updates by tracking changes to objects and applying them in a controlled manner. Type validation in immer is critical because it must distinguish between "safe" objects (ones immer can safely modify) and "unsafe" objects (ones that might contain malicious payload).

Looking at the package-lock.json diff, the vulnerable version appeared as:

"immer": "9.0.7",
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.7.tgz",
"integrity": "sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA=="

The vulnerability manifested as insufficient type checking in immer's internal state mutation logic. When immer processed nested objects, it relied on typeof checks and prototype chain inspection to identify "special" object types that should be handled differently. However, an attacker could create a specially crafted object that:

  1. Appeared to be one type based on typeof checks (e.g., appearing as a plain object)
  2. Actually inherited from or mimicked a dangerous prototype
  3. Bypassed the security fix intended to prevent CVE-2020-28477

Attack Scenario

Imagine an application using immer to handle user preference updates:

// User-controlled input from an API request
const userPreferences = JSON.parse(requestBody);

// Application code using immer
const updatedState = produce(appState, draft => {
  draft.preferences = userPreferences;
});

With the type confusion vulnerability, an attacker could send a carefully constructed JSON payload that, when parsed, created an object that bypassed immer's type validation. The malicious object would be treated as a legitimate preference update, potentially:

  • Accessing properties that should be protected
  • Escaping the immutable state sandbox immer creates
  • Re-enabling the previously patched CVE-2020-28477 vulnerability

The Trivy scanner flagged this as "likely exploitable" because the code path handles user-influenced input and the vulnerable immer version had no defense against this attack vector.

The Fix

What Changed

The fix involved a precise version downgrade in two critical files:

--- a/client/package.json
+++ b/client/package.json
@@ -66,7 +66,7 @@
         "http": "0.0.1-security",
         "http-proxy": "1.18.1",
         "identity-obj-proxy": "3.0.0",
-        "immer": "9.0.7",
+        "immer": "^9.0.6",

And correspondingly in package-lock.json:

--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -20773,9 +20783,10 @@
     "node_modules/immer": {
-      "version": "9.0.7",
-      "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.7.tgz",
-      "integrity": "sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA==",
+      "version": "9.0.6",
+      "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.6.tgz",
+      "integrity": "sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ==",
+      "license": "MIT",

Additionally, nested copies of immer within transitive dependencies were updated to 9.0.21:

"node_modules/@antv/xflow-core/node_modules/immer": {
  "version": "9.0.21",
  "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
  "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA=="
}

Why This Specific Version?

Immer 9.0.6 includes hardened type validation that prevents the bypass mechanism exploited in 9.0.7. The patch introduced stricter checks on object prototypes and type discrimination, making it impossible for specially-crafted objects to fool the validation logic. The caret (^) in "immer": "^9.0.6" allows patch-level updates (9.0.6, 9.0.7, etc. would be allowed if they were released after 9.0.6), but the explicit sha512 hash in package-lock.json pins the exact version.

How This Solves the Problem

Before the fix, immer 9.0.7's type checking could be bypassed through object prototype manipulation. After upgrading to 9.0.6, the library properly validates:

  1. Object origin: Confirming objects are truly plain objects and not crafted malicious instances
  2. Prototype chain: Ensuring no dangerous prototype properties affect behavior
  3. Type assertions: Using multiple validation methods instead of relying on a single typeof check

The fix is thorough—it updates not just the direct dependency but also transitive dependencies (like the immer version used by @antv/xflow-core), ensuring no version of immer with the CVE-2021-23436 vulnerability remains in the dependency tree.

Prevention & Best Practices

For Dependency Management

  1. Automated vulnerability scanning: Use tools like Trivy, Snyk, or npm audit to continuously monitor dependencies for known vulnerabilities. These tools should be part of your CI/CD pipeline and run on every pull request.

  2. Pin critical dependencies: While semantic versioning is useful, consider pinning versions of security-critical libraries (like immer, which handles sensitive state) to specific versions rather than using loose ranges.

  3. Regular dependency audits: Run npm audit or equivalent tools regularly and prioritize critical CVEs for immediate patching.

For Secure Coding with Dynamic Types

  1. Use TypeScript: When possible, use TypeScript with strict mode enabled. This provides compile-time type checking that would catch many type confusion attempts:
    typescript // TypeScript catches type mismatches at compile time const userPreferences: UserPreferences = userInput; // Type error if incompatible

  2. Explicit type validation: Don't rely solely on typeof checks. For untrusted input, validate the structure comprehensively:
    javascript function validateUserPreferences(input) { if (typeof input !== 'object' || input === null) throw new Error('Invalid type'); if (Object.getPrototypeOf(input) !== Object.prototype) { throw new Error('Invalid prototype chain'); } if (!('theme' in input) || !('notifications' in input)) { throw new Error('Missing required properties'); } return input; }

  3. Avoid trust in prototypes: Be cautious with object inheritance and prototype chains when processing untrusted input.

Detection Strategies

  • Static analysis: Semgrep rules can detect patterns where untrusted data flows into type-sensitive operations
  • Dependency scanning: Tools like Trivy (used in this fix) can identify vulnerable library versions
  • Runtime monitoring: Application Performance Monitoring (APM) tools can detect unusual object type patterns in production
  • Code review focus: During peer review, flag any code that handles both untrusted input and performs type-based decisions

Key Takeaways

  • Type confusion in JavaScript is real: Dynamic typing creates attack surfaces that developers often don't anticipate. The bypass of CVE-2020-28477 through CVE-2021-23436 shows how even "patched" systems can be compromised through type manipulation.

  • Dependencies matter deeply: immer is just one library, but it's used by thousands of applications. A type confusion vulnerability in a foundational library can affect entire ecosystems. Always treat dependency vulnerabilities with urgency.

  • Version specificity saves lives: The difference between immer 9.0.6 and 9.0.7 is a single version bump, yet one is vulnerable and the other is not. Use exact version pinning for critical dependencies and understand what each version bump contains.

  • Transitive dependencies need attention: This fix caught nested copies of immer in @antv/xflow-core and react-scripts. Vulnerabilities in indirect dependencies are just as dangerous as direct ones and require proactive discovery.

  • Trivy's "likely exploitable" flag was actionable: The security scanner didn't just flag the vulnerability—it assessed it as likely to be exploited in the wild. Prioritize vulnerabilities with this assessment for immediate remediation.

How Orbis AppSec Detected This

Source: Trivy dependency scanner analyzing the client/package-lock.json file

Sink: The immer 9.0.7 library's type validation logic, which handles user-influenced state updates through the produce() function

Missing control: No validation of prototype chain integrity in immer 9.0.7; insufficient type discrimination between safe and unsafe objects

CWE: CWE-843 (Access of Resource Using Incompatible Type) — the core type confusion weakness that enabled the bypass

Fix: Downgrade immer from 9.0.7 to 9.0.6, which includes hardened prototype validation and improved type checking to prevent object confusion attacks

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

Type confusion vulnerabilities often hide in plain sight because they exploit the very flexibility that makes JavaScript powerful. CVE-2021-23436 in immer demonstrates how a seemingly minor type validation gap can become a critical security bypass, undoing previous patches and reopening attack vectors.

This fix—a simple version upgrade—reminds us that security isn't about perfect code; it's about staying vigilant with dependencies, trusting security researchers and tool maintainers, and acting quickly when vulnerabilities are discovered. By understanding why this vulnerability mattered (it bypassed CVE-2020-28477) and how it was fixed (stricter type validation), developers can build more robust applications and make informed decisions about their dependency management strategies.

Security in JavaScript ecosystems depends on all of us keeping our dependencies current and understanding the risks they carry.


References

Frequently Asked Questions

What is a type confusion vulnerability?

Type confusion occurs when an attacker exploits JavaScript's dynamic typing to make the application treat a value as a different type than intended, potentially bypassing security checks or triggering unintended behavior.

How do you prevent type confusion in JavaScript?

Use strict type checking (TypeScript), implement explicit type validation before processing untrusted input, avoid relying on typeof checks alone, and keep dependencies updated to patch known type confusion vulnerabilities.

What is CWE-843?

CWE-843 covers "Access of Resource Using Incompatible Type" — when software uses a resource (value, object) assuming one type, but the actual type is different, potentially leading to unexpected behavior or security flaws.

Does upgrading immer from 9.0.7 to 9.0.6 completely prevent all type confusion attacks?

The upgrade specifically addresses CVE-2021-23436's bypass of CVE-2020-28477. However, developers should always validate input independently and not rely solely on library updates for security.

Can static analysis detect type confusion vulnerabilities in JavaScript?

Yes, tools like Trivy (used in this fix), Snyk, and TypeScript's strict mode can detect many type confusion patterns. However, some sophisticated cases require manual code review or dynamic analysis.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #118

Related Articles

high

How Quadratic CPU Consumption Happens in JS-YAML and How to Fix It

A critical vulnerability in JS-YAML versions 3.x and 4.x allowed attackers to trigger quadratic CPU consumption through maliciously crafted YAML input using the `!!omap` tag resolver. The vulnerability stems from inefficient array operations in the ordered map resolution logic, which could be exploited for denial-of-service attacks. Upgrading to JS-YAML 4.3.1 or 3.15.1 patches this attack surface by optimizing the computational complexity of ordered map processing.

critical

How Prototype Pollution Happens in i18next-fs-backend and How to Fix It

A critical prototype pollution vulnerability (CVE-2026-48713) was discovered in i18next-fs-backend versions prior to 2.6.6, where specially crafted missing-key strings could pollute the JavaScript object prototype. This fix upgrades the dependency to patch the vulnerability and prevent attackers from injecting malicious properties into application objects.

high

How Quadratic CPU Consumption in js-yaml's !!omap Resolution Happens in Node.js and How to Fix It

A high-severity algorithmic complexity vulnerability (GHSA-5p4m-2wfm-xmqj) in js-yaml versions 3.x and 4.x allowed attackers to trigger quadratic CPU consumption through crafted YAML input using the `!!omap` tag. The fix upgrades js-yaml from 4.1.1 to 4.3.1 in the Audex desktop music player, eliminating a denial-of-service vector that could freeze the Electron application when parsing untrusted YAML content.

critical

How Prototype Pollution Happens in JavaScript Carousel Libraries and How to Fix It

A critical prototype pollution vulnerability (CVE-2026-27212) was discovered in Swiper versions up to 11.2.10, a popular JavaScript carousel library used in production web applications. This vulnerability could allow attackers to manipulate application behavior through the prototype chain. The fix involved upgrading Swiper from 11.2.10 to 12.1.2, which patches the underlying prototype pollution flaw.

high

How Quadratic CPU Consumption in YAML Parsing Happens in Node.js and How to Fix It

A critical vulnerability in js-yaml's `!!omap` tag resolution allowed attackers to craft malicious YAML files that consumed CPU resources quadratically, leading to denial of service. The Orbis AppSec team identified this unpatched vulnerability in the docs-site project and automatically upgraded js-yaml to versions 4.3.1 and 3.15.1, which include CVE-2026-59870 backports that fix the algorithmic complexity issue.

critical

How SQL Injection happens in PHP bulk email systems and how to fix it

A critical SQL injection vulnerability in `admin/utilities/bulkEmailSystem.php` allowed attackers to inject arbitrary SQL through unvalidated database names passed from user input. The fix implements strict input validation using regex pattern matching to ensure only safe database identifiers are processed, preventing exploitation of the bulk email functionality.