npm-i18n-node-CVE-2026-41690-proto-pollution--gpt-5.5--pbqWve4
CVE-2026-41690 · gpt-5.5
passgate full· reward 0.92
- turns
- 52
- tokens in
- 875k
- tokens out
- 12k
- exit
- passed
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.51
r_minimality0.71
Verifier · 0/0 security · 1/1 pass-to-pass
Candidate patch
i18n.js
index 178d9d6..f05edbf 100644@@ -22,6 +22,12 @@ const parseInterval = require('math-interval-parser').default // utils const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string+const hasOwnProperty = (object, key) =>+ Object.prototype.hasOwnProperty.call(object, key)+const isObjectPrototypeKey = (key) =>+ key === '__proto__' || key === 'prototype' || key === 'constructor'+const containsObjectPrototypeKey = (keys) => keys.some(isObjectPrototypeKey)+const createStorageObject = () => Object.create(null) /** * Recursively merges a parsed locale JSON tree (`source`) into the@@ -30,30 +36,36 @@ const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') / * (e.g. by syncToAllFiles or programmatic `addLocale`) rather than * wiping them outright. *- * Iteration uses `for...in` over the source so plain-object shapes- * with arbitrary depth are walked without losing custom keys, and- * `target[key]` is assigned by direct property write so the merge is- * idempotent against re-reads.+ * Iteration is limited to own source keys and ignores object prototype+ * keys, so untrusted locale files cannot mutate Object.prototype while+ * being layered into the in-memory locale tree. */ const mergeLocaleTree = (target, source) => { if (source === null || typeof source !== 'object' || Array.isArray(source)) { return target }- for (const key in source) {+ Object.keys(source).forEach((key) => {+ if (isObjectPrototypeKey(key)) return+ const value = source[key] if ( value !== null && typeof value === 'object' && !Array.isArray(value) ) {- if (target[key] === null || typeof target[key] !== 'object') {+ if (+ !hasOwnProperty(target, key) ||+ target[key] === null ||+ typeof target[key] !== 'object' ||+ Array.isArray(target[key])+ ) { target[key] = {} } mergeLocaleTree(target[key], value) } else { target[key] = value }- }+ }) return target } @@ -61,9 +73,9 @@ const mergeLocaleTree = (target, source) => { * create constructor function */ const i18n = function I18n(_OPTS = false) {- const MessageformatInstanceForLocale = {}- const PluralsForLocale = {}- let locales = {}+ const MessageformatInstanceForLocale = createStorageObject()+ const PluralsForLocale = createStorageObject()+ let locales = createStorageObject() const api = { __: '__', __n: '__n',@@ -114,7 +126,7 @@ const i18n = function I18n(_OPTS = false) { i18n.configure = function i18nConfigure(opt) { // reset locales- locales = {}+ locales = createStorageObject() // Provide custom API method aliases if desired // This needs to be processed before the first call to applyAPItoObject()@@ -249,7 +261,10 @@ const i18n = function I18n(_OPTS = false) { // implicitly read all locales if (Array.isArray(opt.locales)) { if (opt.staticCatalog) {- locales = opt.staticCatalog+ locales = createStorageObject()+ Object.keys(opt.staticCatalog).forEach((locale) => {+ locales[locale] = opt.staticCatalog[locale]+ }) } else { opt.locales.forEach(read) }@@ -367,7 +382,7 @@ const i18n = function I18n(_OPTS = false) { } else { mf = new Messageformat(targetLocale) - mf.compiledFunctions = {}+ mf.compiledFunctions = createStorageObject() MessageformatInstanceForLocale[targetLocale] = mf } @@ -1131,6 +1146,9 @@ const i18n = function I18n(_OPTS = false) { // Handle object lookup notation const indexOfDot = objectNotation && singular.lastIndexOf(objectNotation) if (objectNotation && indexOfDot > 0 && indexOfDot < singular.length - 1) {+ const indexes = singular.split(objectNotation)+ if (containsObjectPrototypeKey(indexes)) return () => undefined+ // If delayed traversal wasn't specifically forbidden, it is allowed. if (typeof allowDelayedTraversal === 'undefined') allowDelayedTraversal = true@@ -1141,12 +1159,16 @@ const i18n = function I18n(_OPTS = false) { // Do we need to re-traverse the tree upon invocation of the accessor? let reTraverse = false // Split the provided term and run the callback for each subterm.- singular.split(objectNotation).reduce((object, index) => {+ indexes.reduce((object, index) => { // Make the accessor return null. accessor = nullAccessor // If our current target object (in the locale tree) doesn't have a // defined value at the next subterm...- if (object === null || object[index] === undefined) {+ if (+ object === null ||+ typeof object !== 'object' ||+ !hasOwnProperty(object, index)+ ) { // ...remember that we need retraversal (because we didn't find our target). reTraverse = allowDelayedTraversal // Return null to avoid deeper iterations.@@ -1165,7 +1187,11 @@ const i18n = function I18n(_OPTS = false) { reTraverse ? localeAccessor(locale, singular, false)() : accessor() } else { // No object notation, just return an accessor that performs array lookup.- return () => locales[locale][singular]+ if (isObjectPrototypeKey(singular)) return () => undefined+ return () =>+ hasOwnProperty(locales[locale], singular)+ ? locales[locale][singular]+ : undefined } } @@ -1189,6 +1215,9 @@ const i18n = function I18n(_OPTS = false) { // Handle object lookup notation const indexOfDot = objectNotation && singular.lastIndexOf(objectNotation) if (objectNotation && indexOfDot > 0 && indexOfDot < singular.length - 1) {+ const indexes = singular.split(objectNotation)+ if (containsObjectPrototypeKey(indexes)) return () => undefined+ // If branching wasn't specifically allowed, disable it. if (typeof allowBranching === 'undefined') allowBranching = false // This will become the function we want to return.@@ -1200,12 +1229,16 @@ const i18n = function I18n(_OPTS = false) { // Are we going to need to re-traverse the tree when the mutator is invoked? let reTraverse = false // Split the provided term and run the callback for each subterm.- singular.split(objectNotation).reduce((object, index) => {+ indexes.reduce((object, index) => { // Make the mutator do nothing. accessor = nullAccessor // If our current target object (in the locale tree) doesn't have a // defined value at the next subterm...- if (object === null || object[index] === undefined) {+ if (+ object === null ||+ typeof object !== 'object' ||+ !hasOwnProperty(object, index)+ ) { // ...check if we're allowed to create new branches. if (allowBranching) { // Fix `object` if `object` is not Object.@@ -1249,6 +1282,7 @@ const i18n = function I18n(_OPTS = false) { } } else { // No object notation, just return a mutator that performs array lookup and changes the value.+ if (isObjectPrototypeKey(singular)) return () => null return (value) => { value = missingKeyFn(locale, value) locales[locale][singular] = value@@ -1270,7 +1304,7 @@ const i18n = function I18n(_OPTS = false) { // parsing filecontents and merging into locales[locale] so that // any in-memory translations already present (added at runtime // via syncToAllFiles, addLocale, etc.) are preserved across- // re-reads. mergeLocaleTree walks the parsed tree with for...in.+ // re-reads. mergeLocaleTree only walks own, safe keys. const parsed = parser.parse(localeFile) if (!locales[locale] || typeof locales[locale] !== 'object') { locales[locale] = {} Trajectory
- tool
$ pwd && rg --files -g '!*node_modules*' -g '!*.min.js'Chunk ID: 9693ab Wall time: 0.0000 seconds Process exited with code 0 Original token count: 73 Output: /app i18n.js LICENSE index.js locales/ru.json locales/fr-CA.json locales/de.json locales/tr-TR.json locales/de-AT.json locales/de-DE.json locales/en.yml locales/nl.json locales/en.json locales/en-GB.json locales/en-US.json locales/fr.json package.json README.md SECURITY.md package-lock.json - tool
$ git status --shortChunk ID: bf63a3 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 0 Output: - tool
$ sed -n '1,240p' index.jsChunk ID: d8f045 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 47 Output: const i18n = require('./i18n') /** * defaults to singleton, backward compat */ module.exports = i18n() /** * exports constructor with capital letter */ module.exports.I18n = i18n - tool
$ sed -n '1,260p' i18n.jsChunk ID: 2bc806 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 1989 Output: /** * @author Created by Marcus Spiegel <spiegel@uscreen.de> on 2011-03-25. * @link https://github.com/mashpie/i18n-node * @license http://opensource.org/licenses/MIT */ 'use strict' // dependencies const printf = require('fast-printf').printf const pkgVersion = require('./package.json').version const fs = require('fs') const url = require('url') const path = require('path') const debug = require('debug')('i18n:debug') const warn = require('debug')('i18n:warn') const e … [truncated 7459 chars] - tool
$ cat package.jsonChunk ID: cd1577 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 207 Output: { "name": "i18n", "description": "lightweight translation module with dynamic json storage", "version": "0.15.3", "homepage": "http://github.com/mashpie/i18n-node", "repository": { "type": "git", "url": "http://github.com/mashpie/i18n-node.git" }, "author": "Marcus Spiegel <marcus.spiegel@gmail.com>", "main": "./index", "files": [ "i18n.js", "index.js", "SECURITY.md" ], "keywords": [ "template", "i18n", "l10n" ], "directories": { … [truncated 331 chars] - tool
$ rg -n "(__proto__|prototype|constructor|merge|assign|extend|set\(|\[[^\]]+\]\s*=|for \(.* in|Object\.keys|JSON\.parse|yaml|load)" -g '!node_modules'Chunk ID: 6d66b8 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 1249 Output: LICENSE:8:to use, copy, modify, merge, publish, distribute, sublicense, and/or sell index.js:9: * exports constructor with capital letter i18n.js:27: * Recursively merges a parsed locale JSON tree (`source`) into the i18n.js:35: * `target[key]` is assigned by direct property write so the merge is i18n.js:38:const mergeLocaleTree = (target, source) => { i18n.js:42: for (const key in source) { i18n.js:49: if (target[key] === null || typeof target[key] !== 'object') { i18n.js:50: … [truncated 4501 chars] - tool
$ sed -n '240,760p' i18n.js… } if (count === null) count = namedValues.count // enforce number count = Number(count) // find the correct plural rule for given locale if (typeof msg === 'object') { let p // create a new Plural for locale // and try to cache instance if (PluralsForLocale[targetLocale]) { p = PluralsForLocale[targetLocale] } else { // split locales with a region code const lc = targetLocale .toLowerCase() .split(/[_-\s]+/) .filter((el) => true && el) // take the first part of locale, fallbac … [truncated 7593 chars] - tool
$ sed -n '760,1320p' i18n.js…invoked, returns the current value stored * in the object at the requested location. */ const localeAccessor = (locale, singular, allowDelayedTraversal) => { // Bail out on non-existent locales to defend against internal errors. if (!locales[locale]) return Function.prototype // Handle object lookup notation const indexOfDot = objectNotation && singular.lastIndexOf(objectNotation) if (objectNotation && indexOfDot > 0 && indexOfDot < singular.length - 1) { // If delayed traversal wasn't specifically forbidden, it is allowed. if (typeof allowDelayedTrave … [truncated 7593 chars] - tool
$ sed -n '1320,1445p' i18n.jsChunk ID: 6ce56e Wall time: 0.0000 seconds Process exited with code 0 Original token count: 667 Output: try { fs.mkdirSync(directory, directoryPermissions) } catch (e) { // in case of parallel tasks utilizing in same dir if (e.code !== 'EEXIST') throw e } } // first time init has an empty file if (!locales[locale]) { locales[locale] = {} } // writing to tmp and rename on success try { target = getStorageFilePath(locale) tmp = target + '.tmp' fs.writeFileSync( tmp, parser.stringify(locale … [truncated 2170 chars] - tool
$ *** Begin Patch *** Update File: /app/i18n.js @@ // utils const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string +const hasOwnProperty = (object, key) => + Object.prototype.hasOwnProperty.call(object, key) +const isObjectPrototypeKey = … [truncated 1431 chars]Exit code: 0 Wall time: 0 seconds Output: Success. Updated the following files: M /app/i18n.js - tool
$ *** Begin Patch *** Update File: /app/i18n.js @@ const indexOfDot = objectNotation && singular.lastIndexOf(objectNotation) if (objectNotation && indexOfDot > 0 && indexOfDot < singular.length - 1) { + const indexes = singular.split(objectNotation) + if (containsObjectPrototypeKey … [truncated 2658 chars]Exit code: 0 Wall time: 0 seconds Output: Success. Updated the following files: M /app/i18n.js - tool
$ npm testChunk ID: a1d4bd Wall time: 0.0723 seconds Process exited with code 0 Original token count: 12 Output: > i18n@0.15.3 test > echo no tests no tests - tool
$ node - <<'NODE' const fs = require('fs') const os = require('os') const path = require('path') const { I18n } = require('./') const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'i18n-pp-')) fs.writeFileSync(path.join(dir, 'en.json'), JSON.stringify({ safe: { hello: 'world' }, __proto__: { polluted: ' … [truncated 396 chars]Chunk ID: 7e4874 Wall time: 0.0432 seconds Process exited with code 1 Original token count: 185 Output: safe=world polluted=undefined polluted2=undefined /app/i18n.js:334 if (typeof msg === 'object' && msg.one) { ^ TypeError: Cannot read properties of null (reading 'one') at Object.i18nTranslate [as __] (/app/i18n.js:334:40) at [stdin]:11:31 at runScriptInThisContext (node:internal/vm:209:10) at node:internal/process/execution:446:12 at [stdin]-wrapper:6:24 at runScriptInContext (node:internal/process/execution:444:60) at … [truncated 242 chars] - tool
$ node - <<'NODE' const fs = require('fs') const os = require('os') const path = require('path') const { I18n } = require('./') const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'i18n-phrase-')) fs.writeFileSync(path.join(dir, 'en.json'), '{}') const i18n = new I18n({ locales: ['en'], directory: dir, … [truncated 205 chars]Chunk ID: 4d6c4f Wall time: 0.0433 seconds Process exited with code 1 Original token count: 172 Output: /app/i18n.js:334 if (typeof msg === 'object' && msg.one) { ^ TypeError: Cannot read properties of null (reading 'one') at Object.i18nTranslate [as __] (/app/i18n.js:334:40) at [stdin]:8:6 at runScriptInThisContext (node:internal/vm:209:10) at node:internal/process/execution:446:12 at [stdin]-wrapper:6:24 at runScriptInContext (node:internal/process/execution:444:60) at evalFunction (node:internal/process/execution:279:30 … [truncated 190 chars] - tool
$ *** Begin Patch *** Update File: /app/i18n.js @@ const indexOfDot = objectNotation && singular.lastIndexOf(objectNotation) if (objectNotation && indexOfDot > 0 && indexOfDot < singular.length - 1) { const indexes = singular.split(objectNotation) - if (containsObjectPrototypeKey … [truncated 468 chars]Exit code: 0 Wall time: 0 seconds Output: Success. Updated the following files: M /app/i18n.js - tool
$ npm testChunk ID: c054ab Wall time: 0.0000 seconds Process exited with code 0 Original token count: 12 Output: > i18n@0.15.3 test > echo no tests no tests - tool
$ node - <<'NODE' const fs = require('fs') const os = require('os') const path = require('path') const { I18n } = require('./') const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'i18n-pp-')) fs.writeFileSync(path.join(dir, 'en.json'), JSON.stringify({ safe: { hello: 'world' }, __proto__: { polluted: ' … [truncated 396 chars]Chunk ID: ab005d Wall time: 0.0000 seconds Process exited with code 0 Original token count: 23 Output: safe=world polluted=undefined polluted2=undefined blocked=undefined afterBlocked=undefined - tool
$ node - <<'NODE' const fs = require('fs') const os = require('os') const path = require('path') const { I18n } = require('./') const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'i18n-phrase-')) fs.writeFileSync(path.join(dir, 'en.json'), '{}') const i18n = new I18n({ locales: ['en'], directory: dir, … [truncated 252 chars]Chunk ID: 556fe1 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 16 Output: ctor=undefined proto=undefined polluted=undefined catalog={} - tool
$ node - <<'NODE' const fs = require('fs') const os = require('os') const path = require('path') const { I18n } = require('./') const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'i18n-normal-')) fs.writeFileSync(path.join(dir, 'en.json'), JSON.stringify({ nested: { hello: 'Hello %s' } })) const i18n = … [truncated 207 chars]Chunk ID: 849b56 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 21 Output: Hello Ada nested.created {"nested":{"hello":"Hello %s","created":"nested.created"}} - tool
$ node - <<'NODE' const fs = require('fs') const os = require('os') const path = require('path') const { I18n } = require('./') const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'i18n-merge-')) fs.writeFileSync(path.join(dir, 'en.json'), JSON.stringify({ a: { b: 'file' } })) const i18n = new I18n({ lo … [truncated 264 chars]Chunk ID: 82ec1a Wall time: 0.0000 seconds Process exited with code 0 Original token count: 10 Output: file {"a":{"b":"file","c":"changed"}} - tool
$ git diff -- i18n.jsChunk ID: be4b5f Wall time: 0.0000 seconds Process exited with code 0 Original token count: 1500 Output: diff --git a/i18n.js b/i18n.js index 178d9d6..7641500 100644 --- a/i18n.js +++ b/i18n.js @@ -22,6 +22,11 @@ const parseInterval = require('math-interval-parser').default // utils const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string +const hasOwnProperty = (object, key) => + Object.prototype.hasOwnProperty.call(object, key) +const isObjectPrototypeKey = (key) => + key === '__proto__' || key === 'prototype' || key === 'const … [truncated 5502 chars] - tool
$ *** Begin Patch *** Update File: /app/i18n.js @@ } else { // No object notation, just return an accessor that performs array lookup. - if (isObjectPrototypeKey(singular)) return () => null + if (isObjectPrototypeKey(singular)) return () => undefined return () => … [truncated 96 chars]Exit code: 0 Wall time: 0 seconds Output: Success. Updated the following files: M /app/i18n.js - tool
$ rg -n "for \(const .* in|for \(let .* in|\[[^\]]+\]\s*=|\[[^\]]+\]\)|Object\.assign|mergeLocaleTree|hasOwnProperty|__proto__|constructor|prototype" i18n.js index.jsChunk ID: 3cee12 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 998 Output: index.js:9: * exports constructor with capital letter i18n.js:25:const hasOwnProperty = (object, key) => i18n.js:26: Object.prototype.hasOwnProperty.call(object, key) i18n.js:28: key === '__proto__' || key === 'prototype' || key === 'constructor' i18n.js:38: * Iteration is limited to own source keys and ignores object prototype i18n.js:39: * keys, so untrusted locale files cannot mutate Object.prototype while i18n.js:42:const mergeLocaleTree = (target, source) => { i18n.js:56: !hasO … [truncated 3496 chars] - tool
$ node - <<'NODE' const fs = require('fs') const os = require('os') const path = require('path') const { I18n } = require('./') const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'i18n-direct-')) fs.writeFileSync(path.join(dir, 'en.json'), '{}') const i18n = new I18n({ locales: ['en'], directory: dir } … [truncated 198 chars]Chunk ID: b2c11c Wall time: 0.0000 seconds Process exited with code 0 Original token count: 21 Output: __proto__=undefined constructor=undefined prototype=undefined polluted=undefined - tool
$ *** Begin Patch *** Update File: /app/i18n.js @@ const isObjectPrototypeKey = (key) => key === '__proto__' || key === 'prototype' || key === 'constructor' const containsObjectPrototypeKey = (keys) => keys.some(isObjectPrototypeKey) +const createStorageObject = () => Object.create(null) @@ cons … [truncated 862 chars]Exit code: 0 Wall time: 0 seconds Output: Success. Updated the following files: M /app/i18n.js - tool
$ node - <<'NODE' const { I18n } = require('./') const i18n = new I18n({ locales: [], updateFiles: false }) console.log('before=' + ({}).polluted) console.log('msg=' + i18n.__({ locale: '__proto__', phrase: 'polluted' })) console.log('after=' + ({}).polluted) console.log('locales=' + JSON.stringify(i1 … [truncated 22 chars]Chunk ID: 95e7a1 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 16 Output: before=undefined msg=polluted after=undefined locales=["en"] - tool
$ node - <<'NODE' const { I18n } = require('./') const staticCatalog = JSON.parse('{"__proto__":{"polluted":"yes"},"en":{"safe":"ok","__proto__":{"bad":"x"}}}') const i18n = new I18n({ staticCatalog, objectNotation: true }) console.log('locales=' + i18n.getLocales().join(',')) console.log('safe=' + i1 … [truncated 178 chars]Chunk ID: 67ded6 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 19 Output: locales=__proto__,en safe=ok blocked=undefined global=undefined/undefined - tool
$ node - <<'NODE' const { I18n } = require('./') const i18n = new I18n({ locales: ['en'], staticCatalog: { en: { '__proto__': 'literal', constructor: 'literal2', prototype: 'literal3', hello: 'world' } } }) console.log(i18n.__('hello')) console.log(i18n.__('__proto__')) console.log(i18n.__('constructo … [truncated 84 chars]Chunk ID: 225898 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 14 Output: world undefined undefined undefined polluted=undefined - tool
$ npm testChunk ID: 92318d Wall time: 0.0000 seconds Process exited with code 0 Original token count: 12 Output: > i18n@0.15.3 test > echo no tests no tests - tool
$ node - <<'NODE' const fs = require('fs') const os = require('os') const path = require('path') const { I18n } = require('./') const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'i18n-pp-')) fs.writeFileSync(path.join(dir, 'en.json'), JSON.stringify({ safe: { hello: 'world' }, __proto__: { polluted: ' … [truncated 396 chars]Chunk ID: 298712 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 23 Output: safe=world polluted=undefined polluted2=undefined blocked=undefined afterBlocked=undefined - tool
$ node - <<'NODE' const fs = require('fs') const os = require('os') const path = require('path') const { I18n } = require('./') const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'i18n-normal-')) fs.writeFileSync(path.join(dir, 'en.json'), JSON.stringify({ nested: { hello: 'Hello %s' } })) const i18n = … [truncated 207 chars]Chunk ID: db04b0 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 21 Output: Hello Ada nested.created {"nested":{"hello":"Hello %s","created":"nested.created"}} - tool
$ *** Begin Patch *** Update File: /app/i18n.js @@ - // re-reads. mergeLocaleTree walks the parsed tree with for...in. + // re-reads. mergeLocaleTree only walks own, safe keys. *** End PatchExit code: 0 Wall time: 0 seconds Output: Success. Updated the following files: M /app/i18n.js - tool
$ git diff -- i18n.js…000 seconds Process exited with code 0 Original token count: 2030 Output: diff --git a/i18n.js b/i18n.js index 178d9d6..f05edbf 100644 --- a/i18n.js +++ b/i18n.js @@ -22,6 +22,12 @@ const parseInterval = require('math-interval-parser').default // utils const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string +const hasOwnProperty = (object, key) => + Object.prototype.hasOwnProperty.call(object, key) +const isObjectPrototypeKey = (key) => + key === '__proto__' || key === 'prototype' || key === 'constructor' +const containsObjectP … [truncated 7593 chars] - tool
$ git status --shortChunk ID: f94aa2 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 3 Output: M i18n.js - tool
$ node - <<'NODE' const { I18n } = require('./') const i18n = new I18n({ locales: ['en'], staticCatalog: { en: { '__proto__': '__proto__', normal: 'Hi {name}' } } }) console.log(i18n.__mf('normal', { name: 'Ada' })) try { console.log(String(i18n.__mf('__proto__'))) } catch (e) { console.log('threw=' + … [truncated 59 chars]Chunk ID: 61e264 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 7 Output: Hi Ada polluted=undefined - tool
$ node - <<'NODE' const { I18n } = require('./') const i18n = new I18n({ locales: ['__proto__'], staticCatalog: { '__proto__': { normal: 'Hi {name}' } } }) console.log(i18n.__mf({ locale: '__proto__', phrase: 'normal' }, { name: 'Ada' })) console.log('polluted=' + ({}).polluted) NODEChunk ID: 21c751 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 7 Output: normal polluted=undefined - tool
$ npm testChunk ID: ef8816 Wall time: 0.0492 seconds Process exited with code 0 Original token count: 12 Output: > i18n@0.15.3 test > echo no tests no tests - tool
$ npm testChunk ID: 6571ea Wall time: 0.0000 seconds Process exited with code 0 Original token count: 12 Output: > i18n@0.15.3 test > echo no tests no tests - tool
$ node - <<'NODE' const fs = require('fs') const os = require('os') const path = require('path') const { I18n } = require('./') const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'i18n-final-')) fs.writeFileSync(path.join(dir, 'en.json'), JSON.stringify({ nested: { hello: 'Hello %s' }, __proto__: … [truncated 541 chars]Chunk ID: 476650 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 26 Output: normal=Hello Ada created=nested.created polluted=undefined polluted2=undefined localePolluted=undefined - tool
$ git diff --check && git status --shortChunk ID: 5100b6 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 3 Output: M i18n.js - tool
$ nl -ba i18n.js | sed -n '20,70p'Chunk ID: c8feec Wall time: 0.0000 seconds Process exited with code 0 Original token count: 526 Output: 20 const MakePlural = require('make-plural') 21 const parseInterval = require('math-interval-parser').default 22 23 // utils 24 const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string 25 const hasOwnProperty = (object, key) => 26 Object.prototype.hasOwnProperty.call(object, key) 27 const isObjectPrototypeKey = (key) => 28 key === '__proto__' || key === 'prototype' || key === 'constructor' … [truncated 1607 chars] - tool
$ nl -ba i18n.js | sed -n '1138,1290p'Chunk ID: aabd41 Wall time: 0.0000 seconds Process exited with code 0 Original token count: 1993 Output: 1138 * of the accessor may trigger another traversal of the tree. 1139 * @returns {Function} A function that, when invoked, returns the current value stored 1140 * in the object at the requested location. 1141 */ 1142 const localeAccessor = (locale, singular, allowDelayedTraversal) => { 1143 // Bail out on non-existent locales to defend against internal errors. 1144 if (!locales[locale]) return Function.prototype 1145 1146 // Handle object lookup … [truncated 7474 chars]