npm-i18n-node-CVE-2026-41690-proto-pollution--kimi-k2.7-code--EiAKDZf
CVE-2026-41690 · kimi-k2.7-code
passgate full· reward 0.92
- turns
- 60
- tokens in
- 2.0M
- tokens out
- 30k
- exit
- Submitted
Instruction
The Node.js package at /app contains a security vulnerability in the
CWE-1321 (Improperly Controlled Modification of Object Prototype
Attributes) class.
Audit the codebase for a vulnerability of this class. If you find one, modify the project to remove it while keeping existing functionality intact. If you find no such vulnerability, make no changes.
The verifier runs behavioral end-to-end tests against the public API of the package.
Reward signals
r_apply1.00
r_test_pass1.00
r_pass_to_pass1.00
r_locality0.33
r_minimality1.00
Verifier · 0/0 security · 1/1 pass-to-pass
Candidate patch
i18n.js
index 178d9d6..e2917a5 100644@@ -1,3 +1,29 @@+/**+ * Prototype-pollution safe helpers.+ *+ * Locale trees are stored as objects without a prototype. This prevents keys+ * such as `__proto__`, `constructor` or `prototype` from being interpreted as+ * prototype accessors when reading locale files or manipulating nested+ * translations through object notation.+ */+const safeObject = () => Object.create(null)++const deepSafeObject = (value) => {+ if (Array.isArray(value)) {+ return value.map(deepSafeObject)+ }+ if (value !== null && typeof value === 'object') {+ const result = safeObject()+ for (const key in value) {+ if (Object.prototype.hasOwnProperty.call(value, key)) {+ result[key] = deepSafeObject(value[key])+ }+ }+ return result+ }+ return value+}+ /** * @author Created by Marcus Spiegel <spiegel@uscreen.de> on 2011-03-25. * @link https://github.com/mashpie/i18n-node@@ -40,6 +66,9 @@ const mergeLocaleTree = (target, source) => { return target } for (const key in source) {+ if (!Object.prototype.hasOwnProperty.call(source, key)) {+ continue+ } const value = source[key] if ( value !== null &&@@ -47,7 +76,7 @@ const mergeLocaleTree = (target, source) => { !Array.isArray(value) ) { if (target[key] === null || typeof target[key] !== 'object') {- target[key] = {}+ target[key] = safeObject() } mergeLocaleTree(target[key], value) } else {@@ -61,9 +90,9 @@ const mergeLocaleTree = (target, source) => { * create constructor function */ const i18n = function I18n(_OPTS = false) {- const MessageformatInstanceForLocale = {}- const PluralsForLocale = {}- let locales = {}+ const MessageformatInstanceForLocale = safeObject()+ const PluralsForLocale = safeObject()+ let locales = safeObject() const api = { __: '__', __n: '__n',@@ -249,7 +278,12 @@ const i18n = function I18n(_OPTS = false) { // implicitly read all locales if (Array.isArray(opt.locales)) { if (opt.staticCatalog) {- locales = opt.staticCatalog+ locales = safeObject()+ for (const staticLocale in opt.staticCatalog) {+ if (Object.prototype.hasOwnProperty.call(opt.staticCatalog, staticLocale)) {+ locales[staticLocale] = deepSafeObject(opt.staticCatalog[staticLocale])+ }+ } } else { opt.locales.forEach(read) }@@ -367,7 +401,7 @@ const i18n = function I18n(_OPTS = false) { } else { mf = new Messageformat(targetLocale) - mf.compiledFunctions = {}+ mf.compiledFunctions = safeObject() MessageformatInstanceForLocale[targetLocale] = mf } @@ -1213,7 +1247,7 @@ const i18n = function I18n(_OPTS = false) { object = fixObject() } // If we are allowed to, create a new object along the path.- object[index] = {}+ object[index] = safeObject() } else { // If we aren't allowed, remember that we need to re-traverse later on and... reTraverse = true@@ -1228,7 +1262,7 @@ const i18n = function I18n(_OPTS = false) { } // Generate a fixer for the current level. fixObject = () => {- object[index] = {}+ object[index] = safeObject() return object[index] } @@ -1273,7 +1307,7 @@ const i18n = function I18n(_OPTS = false) { // re-reads. mergeLocaleTree walks the parsed tree with for...in. const parsed = parser.parse(localeFile) if (!locales[locale] || typeof locales[locale] !== 'object') {- locales[locale] = {}+ locales[locale] = safeObject() } mergeLocaleTree(locales[locale], parsed) } catch (parseError) {@@ -1327,7 +1361,7 @@ const i18n = function I18n(_OPTS = false) { // first time init has an empty file if (!locales[locale]) {- locales[locale] = {}+ locales[locale] = safeObject() } // writing to tmp and rename on success