Back to Blog
high SEVERITY6 min read

How Prototype Pollution Happens in Vue I18n's handleFlatJson and How to Fix It

CVE-2025-27597 is a prototype pollution vulnerability in @intlify/core-base's `handleFlatJson` function that could allow attackers to pollute the JavaScript prototype chain through maliciously crafted internationalization data. The fix upgrades @intlify/core-base from version 9.1.9 to 11.1.10, which implements stricter input handling to prevent untrusted data from modifying object prototypes.

O
By Orbis AppSec
•Published August 15, 2026•Reviewed August 15, 2026

Answer Summary

CVE-2025-27597 is a prototype pollution vulnerability in Vue I18n's @intlify/core-base library (versions prior to 9.1.11), specifically in the `handleFlatJson` function. The vulnerability allows attackers to inject malicious keys like `__proto__`, `constructor`, or `prototype` into the object prototype chain through crafted i18n message data. The fix upgrades @intlify/core-base to version 11.1.10, which implements proper input validation and sanitization to reject dangerous property names before they can pollute the prototype.

Vulnerability at a Glance

cweCWE-1321 (Improperly Controlled Modification of Object Prototype Attributes in JavaScript)
fixUpgrade @intlify/core-base from 9.1.9 to 11.1.10 with enhanced input validation
riskRemote code execution, denial of service, authentication bypass through prototype chain manipulation
languageJavaScript/TypeScript (Vue.js ecosystem)
root causeUnsafe assignment of user-controlled keys to objects without validating for prototype-polluting properties
vulnerabilityPrototype Pollution in handleFlatJson

How Prototype Pollution Happens in Vue I18n's handleFlatJson and How to Fix It

Introduction

In the unibestX project, Trivy security scanning detected a high-severity prototype pollution vulnerability (CVE-2025-27597) lurking in the dependency tree within pnpm-lock.yaml. The vulnerability exists in @intlify/core-base version 9.1.9, specifically in the handleFlatJson function—a critical component that processes internationalization (i18n) message data.

This matters because Vue I18n applications worldwide handle user-influenced translation data, and if that data contains maliciously crafted keys, it could allow attackers to inject properties into JavaScript's prototype chain. For developers building multilingual applications, this represents a silent threat that bypasses traditional input validation because it operates at the prototype level, affecting every object in the application.

The Vulnerability Explained

What is Prototype Pollution?

Prototype pollution is a JavaScript-specific vulnerability where an attacker modifies the prototype of built-in objects (like Object.prototype) by injecting special property names. In JavaScript, when you access a property on an object, the engine searches up the prototype chain. If an attacker pollutes Object.prototype.__proto__ or Object.prototype.constructor, they can:

  • Override application logic
  • Bypass security checks
  • Inject malicious code into unexpected locations
  • Cause denial of service

The Vulnerable Code Pattern

The handleFlatJson function in @intlify/core-base 9.1.9 processes flat JSON structures used for i18n messages. Here's the problematic pattern:

// Vulnerable pattern in @intlify/core-base 9.1.9
// When processing i18n message data like:
const messageData = {
  "greeting": "Hello",
  "__proto__": { "isAdmin": true },  // Malicious key!
  "farewell": "Goodbye"
};

// The handleFlatJson function would iterate through keys and assign them:
for (const key in messageData) {
  targetObject[key] = messageData[key];  // VULNERABLE: No validation!
}

The vulnerability occurs because handleFlatJson accepts user-controlled keys from i18n message data without validating whether they're dangerous prototype-polluting properties.

Attack Scenario

Imagine an attacker crafts a malicious i18n translation file:

{
  "messages": {
    "welcome": "Welcome to our app",
    "__proto__": {
      "isAuthenticated": true,
      "isAdmin": true,
      "permissions": ["delete", "write"]
    }
  }
}

When the Vue I18n application loads this translation data through handleFlatJson, the __proto__ key gets processed, and suddenly:

// After prototype pollution:
const user = {};
console.log(user.isAdmin);           // true (polluted!)
console.log(user.isAuthenticated);   // true (polluted!)
console.log(user.permissions);       // ["delete", "write"] (polluted!)

An attacker could bypass authentication checks, escalate privileges, or manipulate application state across the entire application without modifying a single legitimate property.

Real-World Impact

For applications using @intlify/core-base 9.1.9:

  • Remote Translation Services: If i18n messages come from a CDN or API, an attacker could compromise that source
  • User-Generated Content: If users can upload or provide translation files, malicious actors could inject prototype pollution
  • Supply Chain Risk: Third-party translation management tools could be compromised, distributing polluted message files

The Fix

The fix upgrades @intlify/core-base from version 9.1.9 to 11.1.10, which implements proper input validation in the handleFlatJson function.

Changes Made

Looking at the PR diff, two critical files were updated:

1. package.json

- "vue": "^3.5.13"
+ "vue": "^3.5.13",
+ "@intlify/core-base": "11.1.10"

The explicit dependency pinning ensures the patched version is used.

2. pnpm-lock.yaml

- '@intlify/core-base@9.1.9':
-   resolution: {integrity: sha512-x5T0p/Ja0S8hs5xs+ImKyYckVkL4CzcEXykVYYV6rcbXxJTe2o58IquSqX9bdncVKbRZP7GlBU1EcRaQEEJ+vw==}
-   engines: {node: '>= 10'}

+ '@intlify/core-base@11.1.10':
+   resolution: {integrity: sha512-JhRb40hD93Vk0BgMgDc/xMIFtdXPHoytzeK6VafBNOj6bb6oUZrGamXkBKecMsmGvDQQaPRGG2zpa25VCw8pyw==}
+   engines: {node: '>= 16'}

Notice the engine requirement increased from Node 10+ to Node 16+, indicating substantial internal changes for security.

How Version 11.1.10 Fixes the Issue

The patched version implements a property name allowlist approach:

// Fixed pattern in @intlify/core-base 11.1.10 (conceptual)
const DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype'];

function handleFlatJson(messageData, targetObject) {
  for (const key in messageData) {
    // VALIDATION: Check if key is dangerous
    if (DANGEROUS_KEYS.includes(key)) {
      console.warn(`Skipping dangerous key: ${key}`);
      continue;  // Skip prototype-polluting keys
    }

    // SAFE: Only assign validated keys
    targetObject[key] = messageData[key];
  }
}

The fix ensures that:
- ✅ Legitimate i18n keys like greeting, farewell, welcome still work
- ✅ Dangerous keys like __proto__, constructor, prototype are rejected
- ✅ The prototype chain remains unpolluted
- ✅ No valid translations are lost

Prevention & Best Practices

For Your Own Code

  1. Never Trust User-Controlled Keys: When building object assignment operations, always validate property names:
    ```javascript
    // BAD: Direct assignment without validation
    const config = {};
    Object.assign(config, userInput);

// GOOD: Validate keys first
const SAFE_KEYS = ['theme', 'language', 'notifications'];
const config = {};
for (const key of Object.keys(userInput)) {
if (SAFE_KEYS.includes(key)) {
config[key] = userInput[key];
}
}
```

  1. Use Object.create(null): When possible, create objects without a prototype:
    javascript // More resistant to prototype pollution const safeObject = Object.create(null);

  2. Freeze Prototypes: In security-critical code, freeze prototypes:
    javascript Object.freeze(Object.prototype); Object.freeze(Array.prototype);

  3. Keep Dependencies Updated: Prototype pollution vulnerabilities are discovered regularly. Use tools like npm audit and pnpm audit:
    bash pnpm audit pnpm update

  4. Use Static Analysis: Enable Trivy, Semgrep, or similar tools in your CI/CD pipeline to catch prototype pollution patterns before deployment.

Security Standards

  • CWE-1321: Improperly Controlled Modification of Object Prototype Attributes in JavaScript
  • OWASP: Prototype Pollution in the OWASP Attack Database

Key Takeaways

  • Prototype pollution in handleFlatJson could inject properties into Object.prototype through malicious i18n message keys like __proto__, silently affecting every object in the application.

  • The @intlify/core-base 9.1.9 vulnerability specifically affects applications that load i18n messages from untrusted sources (APIs, user uploads, third-party CDNs).

  • Upgrading to @intlify/core-base 11.1.10 adds validation that rejects dangerous property names before they reach object assignment, preventing prototype pollution while preserving legitimate translations.

  • Always validate property names when assigning user-controlled data to objects—don't rely on input validation alone; specifically reject __proto__, constructor, and prototype.

  • Prototype pollution is invisible to traditional security testing because it operates at the prototype level; automated tools like Trivy are essential for catching these vulnerabilities.

How Orbis AppSec Detected This

Source: I18n message data loaded from external sources or user-provided translation files in the @intlify/core-base handleFlatJson function

Sink: Unsafe property assignment operations in handleFlatJson that don't validate property names before adding them to the target object

Missing control: No validation to reject prototype-polluting keys (__proto__, constructor, prototype) before object assignment

CWE: CWE-1321 (Improperly Controlled Modification of Object Prototype Attributes in JavaScript)

Fix: Upgrade @intlify/core-base from 9.1.9 to 11.1.10, which implements property name validation in handleFlatJson to reject dangerous keys before they can pollute the prototype chain.

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

Prototype pollution in Vue I18n's handleFlatJson represents a subtle but dangerous vulnerability that could compromise applications handling multilingual content from untrusted sources. By upgrading @intlify/core-base to version 11.1.10, you're not just closing a security hole—you're ensuring that your application's prototype chain remains protected against a class of attacks that traditional input validation often misses.

The lesson here extends beyond this specific vulnerability: in JavaScript, always validate property names when processing user-controlled data, especially when that data will be assigned to objects. Prototype pollution is a reminder that security must operate at multiple levels—and that keeping dependencies up-to-date is a critical part of your defense strategy.

Make the upgrade today, and ensure your i18n pipeline remains secure.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #3

Related Articles

high

@xmldom/xmldom 0.9.10 ReDoS: CVE-2026-83606 in PI Parsing

The dependency tree pinned `@xmldom/xmldom` at 0.9.10, a version vulnerable to CVE-2026-83606: a regular expression in the processing-instruction (`<?target data?>`) parsing path backtracks catastrophically on crafted input, so a single XML document can consume CPU for seconds or minutes. Because Node.js runs application code on one thread, that stall blocks every other request in flight. The lockfile was updated to resolve `@xmldom/xmldom` 0.9.12, which carries the fix.

high

Unbounded Map in createLoginRateLimiter Exhausts API Memory

The console API's `createLoginRateLimiter` and `createMutationRateLimiter` stored one `Map` entry per client key with no upper bound and no expiry sweep, so an attacker rotating source addresses or identifiers could grow those maps until the Node process hit an out-of-memory crash. The fix introduces a `maxTrackedKeys` option (default 5000), a `trackedEntryLimit` sanitizer, and an `evictOldestIfFull` helper that drops the oldest tracked key while protecting the shared global counter. The rate li

high

js-yaml 4.3.1 Denial of Service: Malformed Input Hangs YAML Parser

A denial of service vulnerability in js-yaml versions 4.3.1 and earlier allows attackers to hang the YAML parser indefinitely by providing specially crafted malformed input. The fix, released in versions 4.3.2 and 3.15.2, patches the parsing logic to prevent unbounded processing. Upgrading is recommended for all applications parsing untrusted YAML data.

high

Express `app.get('*')` Wildcard Handler Path Traversal in watch.js

A first-party Express server's wildcard route handler used `req.url.indexOf('font.woff2')` to gate access to a font file, allowing attackers to bypass the substring check with crafted paths. The fix replaces the catch-all handler with explicit route registration.

critical

Updater.parseUpdate() CWE-494: Unsigned Metadata Download

The parseUpdate function in the Updater component extracted download URLs from remote server responses without cryptographic verification, enabling supply chain attacks via compromised or spoofed update servers. The fix adds strict URL validation requiring HTTPS and a trusted hostname before accepting any update metadata.

high

brace-expansion DoS: Exponential Backtracking in Nested Brace Patterns

A critical vulnerability in brace-expansion allows attackers to cause denial of service by submitting specially crafted patterns with nested braces. The exponential-time complexity in pattern expansion creates a computationally expensive path that can freeze applications processing user-controlled input.