The vulnerability is a prototype pollution issue within the counterpart library, specifically in how it caches processed translation keys. The root cause lies in the _normalizeKey function, which uses a JavaScript object as a cache (this._registry.normalizedKeys) with the translation key separator as one of the cache keys.
An attacker can trigger the vulnerability by calling the main translate function and passing __proto__ as the separator within the options object. Here is the exploitation flow:
- The
translate function is called with a malicious separator, for example: translate('someKey', { separator: '__proto__' }).
- The
translate function calls _normalizeKeys, which in turn calls _normalizeKey, passing along the malicious separator.
- Inside
_normalizeKey, the code attempts to access the cache using the separator as a key: this._registry.normalizedKeys[separator]. When separator is __proto__, this expression resolves to the Object.prototype of the cache object.
- The following line of code,
this._registry.normalizedKeys[separator][key] = ..., then proceeds to assign a value to a property on Object.prototype instead of the cache object itself. This action pollutes the global Object.prototype for the entire application.
The primary vulnerable function is _normalizeKey, where the unsafe caching logic resides. The translate function is the entry point that allows an attacker to supply the malicious input. Any runtime profile or stack trace generated during exploitation would show calls progressing from translate to _normalizeKeys and finally to _normalizeKey, where the prototype pollution occurs.