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
•Technically reviewed by Anupam Mediratta•Published September 7, 2026•Reviewed 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.


Prevention and further reading

Frequently Asked Questions

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.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #118

Related Articles

high

js-yaml 5.2.1 DoS: Exponential Parsing in Flow Collections

A denial-of-service vulnerability in js-yaml 5.2.1 allows an attacker to crash the parser by supplying deeply nested flow collections that trigger exponential parsing behavior. The fix in version 5.2.2 improves the parser's handling of these structures, preventing the algorithmic complexity attack. This is critical for any service accepting user-controlled YAML input.

high

Anthropic API Adapter Prototype Pollution in parseToolCallInput

The `parseToolCallInput` function in the Anthropic API adapter used `JSON.parse` without protecting against prototype pollution keys. An attacker who could manipulate API responses—through a man-in-the-middle attack, compromised Codex backend, or DNS spoofing—could inject `__proto__`, `constructor`, or `prototype` properties to pollute JavaScript's Object prototype and affect extension runtime behavior.

high

load_localStorage.js JSON Parse: Prototype Pollution via __proto__

The load_localStorage.js utility parsed JSON configuration without validating keys, permitting prototype pollution through malicious `__proto__`, `constructor`, or `prototype` properties. An attacker with filesystem access could poison downstream JavaScript execution by injecting these special keys into the loaded data structure.

critical

How Arbitrary Code Execution Happens in protobufjs and How to Fix It

CVE-2026-41242 is a critical vulnerability in protobufjs versions 8.0.0 and earlier that allows attackers to execute arbitrary code by injecting malicious type fields into protobuf definitions. The fix upgrades the dependency from `^8.0.0` to `^8.6.6` in `core/package.json`, eliminating the unsafe code path that processed attacker-controlled type metadata without validation.

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.

critical

JdbcSinkFunction.invoke() SQL Injection via Unvalidated Identifiers

The `JdbcSinkFunction.invoke()` method in Lacus's RTC engine built SQL INSERT statements with `String.format()`, placing database name, table name, and column names directly into the query string without validation. Although the actual row values used parameterized `?` placeholders, the identifiers themselves were injectable, letting a crafted sink configuration break out of the intended INSERT statement. The fix adds a strict allowlist regex that rejects any identifier containing characters out