flatted: Prototype Pollution via parse()
Description
flatted is a circular JSON parser. Prior to version 3.4.2, the parse() function in flatted can use attacker-controlled string values from the parsed JSON as direct array index keys, without validating that they are numeric. Since the internal input buffer is a JavaScript Array, accessing it with the key "__proto__" returns Array.prototype via the inherited getter. This object is then treated as a legitimate parsed value and assigned as a property of the output object, effectively leaking a live reference to Array.prototype to the consumer. Any code that subsequently writes to that property will pollute the global prototype. This issue has been patched in version 3.4.2.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Flatted parse() prior to 3.4.2 allows prototype pollution via '__proto__' key, leaking Array.prototype.
Root
Cause
The parse() function in flatted prior to version 3.4.2 uses attacker-controlled string values from the parsed JSON as direct array index keys without validating that they are numeric [1]. Since the internal input buffer is a JavaScript Array, accessing it with the key "__proto__" returns Array.prototype via the inherited getter. This object is then treated as a legitimate parsed value and assigned as a property of the output object, effectively leaking a live reference to Array.prototype to the consumer [3].
Exploitation
An attacker can supply a crafted flatted string to parse() such that the returned object holds a live reference to Array.prototype. No authentication or special network position is required; the attacker only needs to deliver the malicious payload to an application that calls parse() on untrusted data [3].
Impact
Any code that subsequently writes to that property will pollute the global prototype chain. This can lead to denial of service, property injection, or other unpredictable behavior depending on the affected application [1][3]. The vulnerability is classified under CWE-1321 (Prototype Pollution).
Mitigation
This issue has been patched in flatted version 3.4.2 [4]. Users should upgrade immediately. No known workarounds are available. The vulnerability is not currently listed in CISA KEV.
AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
flattednpm | < 3.4.2 | 3.4.2 |
Affected products
1- WebReflection/flattedv5Range: < 3.4.2
Patches
16 files changed · +6 −6
cjs/index.js+1 −1 modified@@ -27,7 +27,7 @@ const resolver = (input, lazy, parsed, $) => output => { const k = ke[y]; const value = output[k]; if (value instanceof Primitive) { - const tmp = input[value]; + const tmp = input[+value]; if (typeof tmp === object && !parsed.has(tmp)) { parsed.add(tmp); output[k] = ignore;
es.js+1 −1 modified@@ -1 +1 @@ -self.Flatted=function(t){"use strict";const{parse:e,stringify:n}=JSON,{keys:r}=Object,o=String,s="string",c={},l="object",f=(t,e)=>e,i=t=>t instanceof o?o(t):t,a=(t,e)=>typeof e===s?new o(e):e,u=(t,e,n)=>{const r=o(e.push(n)-1);return t.set(n,r),r},p=(t,n)=>{const s=e(t,a).map(i),u=n||f;let p=s[0];if(typeof p===l&&p){const t=[],e=((t,e,n,s)=>f=>{for(let i=r(f),{length:a}=i,u=0;u<a;u++){const r=i[u],a=f[r];if(a instanceof o){const o=t[a];typeof o!==l||n.has(o)?f[r]=s.call(f,r,o):(n.add(o),f[r]=c,e.push({o:f,k:r,r:o}))}else f[r]!==c&&(f[r]=s.call(f,r,a))}return f})(s,t,new Set,u);p=e(p);let n=0;for(;n<t.length;){const{o:r,k:o,r:s}=t[n++];r[o]=u.call(r,o,e(s))}}return u.call({"":p},"",p)},g=(t,e,r)=>{const o=e&&typeof e===l?(t,n)=>""===t||-1<e.indexOf(t)?n:void 0:e||f,c=new Map,i=[],a=[];let p=+u(c,i,o.call({"":t},"",t)),g=!p;for(;p<i.length;)g=!0,a[p]=n(i[p++],h,r);return"["+a.join(",")+"]";function h(t,e){if(g)return g=!g,e;const n=o.call(this,t,e);switch(typeof n){case l:if(null===n)return n;case s:return c.get(n)||u(c,i,n)}return n}};return t.fromJSON=t=>p(n(t)),t.parse=p,t.stringify=g,t.toJSON=t=>e(g(t)),t}({}); +self.Flatted=function(t){"use strict";const{parse:e,stringify:n}=JSON,{keys:r}=Object,o=String,s="string",c={},l="object",f=(t,e)=>e,i=t=>t instanceof o?o(t):t,a=(t,e)=>typeof e===s?new o(e):e,u=(t,e,n)=>{const r=o(e.push(n)-1);return t.set(n,r),r},p=(t,n)=>{const s=e(t,a).map(i),u=n||f;let p=s[0];if(typeof p===l&&p){const t=[],e=((t,e,n,s)=>f=>{for(let i=r(f),{length:a}=i,u=0;u<a;u++){const r=i[u],a=f[r];if(a instanceof o){const o=t[+a];typeof o!==l||n.has(o)?f[r]=s.call(f,r,o):(n.add(o),f[r]=c,e.push({o:f,k:r,r:o}))}else f[r]!==c&&(f[r]=s.call(f,r,a))}return f})(s,t,new Set,u);p=e(p);let n=0;for(;n<t.length;){const{o:r,k:o,r:s}=t[n++];r[o]=u.call(r,o,e(s))}}return u.call({"":p},"",p)},g=(t,e,r)=>{const o=e&&typeof e===l?(t,n)=>""===t||-1<e.indexOf(t)?n:void 0:e||f,c=new Map,i=[],a=[];let p=+u(c,i,o.call({"":t},"",t)),g=!p;for(;p<i.length;)g=!0,a[p]=n(i[p++],h,r);return"["+a.join(",")+"]";function h(t,e){if(g)return g=!g,e;const n=o.call(this,t,e);switch(typeof n){case l:if(null===n)return n;case s:return c.get(n)||u(c,i,n)}return n}};return t.fromJSON=t=>p(n(t)),t.parse=p,t.stringify=g,t.toJSON=t=>e(g(t)),t}({});
esm/index.js+1 −1 modified@@ -26,7 +26,7 @@ const resolver = (input, lazy, parsed, $) => output => { const k = ke[y]; const value = output[k]; if (value instanceof Primitive) { - const tmp = input[value]; + const tmp = input[+value]; if (typeof tmp === object && !parsed.has(tmp)) { parsed.add(tmp); output[k] = ignore;
esm.js+1 −1 modified@@ -1 +1 @@ -const{parse:t,stringify:e}=JSON,{keys:n}=Object,o=String,r="string",s={},c="object",l=(t,e)=>e,f=t=>t instanceof o?o(t):t,i=(t,e)=>typeof e===r?new o(e):e,a=(t,e,n)=>{const r=o(e.push(n)-1);return t.set(n,r),r},u=(e,r)=>{const a=t(e,i).map(f),u=r||l;let p=a[0];if(typeof p===c&&p){const t=[],e=((t,e,r,l)=>f=>{for(let i=n(f),{length:a}=i,u=0;u<a;u++){const n=i[u],a=f[n];if(a instanceof o){const o=t[a];typeof o!==c||r.has(o)?f[n]=l.call(f,n,o):(r.add(o),f[n]=s,e.push({o:f,k:n,r:o}))}else f[n]!==s&&(f[n]=l.call(f,n,a))}return f})(a,t,new Set,u);p=e(p);let r=0;for(;r<t.length;){const{o:n,k:o,r:s}=t[r++];n[o]=u.call(n,o,e(s))}}return u.call({"":p},"",p)},p=(t,n,o)=>{const s=n&&typeof n===c?(t,e)=>""===t||-1<n.indexOf(t)?e:void 0:n||l,f=new Map,i=[],u=[];let p=+a(f,i,s.call({"":t},"",t)),h=!p;for(;p<i.length;)h=!0,u[p]=e(i[p++],g,o);return"["+u.join(",")+"]";function g(t,e){if(h)return h=!h,e;const n=s.call(this,t,e);switch(typeof n){case c:if(null===n)return n;case r:return f.get(n)||a(f,i,n)}return n}},h=e=>t(p(e)),g=t=>u(e(t));export{g as fromJSON,u as parse,p as stringify,h as toJSON}; +const{parse:t,stringify:e}=JSON,{keys:n}=Object,o=String,r="string",s={},c="object",l=(t,e)=>e,f=t=>t instanceof o?o(t):t,i=(t,e)=>typeof e===r?new o(e):e,a=(t,e,n)=>{const r=o(e.push(n)-1);return t.set(n,r),r},u=(e,r)=>{const a=t(e,i).map(f),u=r||l;let p=a[0];if(typeof p===c&&p){const t=[],e=((t,e,r,l)=>f=>{for(let i=n(f),{length:a}=i,u=0;u<a;u++){const n=i[u],a=f[n];if(a instanceof o){const o=t[+a];typeof o!==c||r.has(o)?f[n]=l.call(f,n,o):(r.add(o),f[n]=s,e.push({o:f,k:n,r:o}))}else f[n]!==s&&(f[n]=l.call(f,n,a))}return f})(a,t,new Set,u);p=e(p);let r=0;for(;r<t.length;){const{o:n,k:o,r:s}=t[r++];n[o]=u.call(n,o,e(s))}}return u.call({"":p},"",p)},p=(t,n,o)=>{const s=n&&typeof n===c?(t,e)=>""===t||-1<n.indexOf(t)?e:void 0:n||l,f=new Map,i=[],u=[];let p=+a(f,i,s.call({"":t},"",t)),h=!p;for(;p<i.length;)h=!0,u[p]=e(i[p++],g,o);return"["+u.join(",")+"]";function g(t,e){if(h)return h=!h,e;const n=s.call(this,t,e);switch(typeof n){case c:if(null===n)return n;case r:return f.get(n)||a(f,i,n)}return n}},h=e=>t(p(e)),g=t=>u(e(t));export{g as fromJSON,u as parse,p as stringify,h as toJSON};
index.js+1 −1 modified@@ -38,7 +38,7 @@ self.Flatted = (function (exports) { var k = ke[y]; var value = output[k]; if (value instanceof Primitive) { - var tmp = input[value]; + var tmp = input[+value]; if (_typeof(tmp) === object && !parsed.has(tmp)) { parsed.add(tmp); output[k] = ignore;
min.js+1 −1 modified@@ -1 +1 @@ -self.Flatted=function(n){"use strict";function t(n){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n},t(n)}var r=JSON.parse,e=JSON.stringify,o=Object.keys,u=String,f="string",i={},c="object",a=function(n,t){return t},l=function(n){return n instanceof u?u(n):n},s=function(n,r){return t(r)===f?new u(r):r},y=function(n,t,r){var e=u(t.push(r)-1);return n.set(r,e),e},p=function(n,e){var f=r(n,s).map(l),y=e||a,p=f[0];if(t(p)===c&&p){var v=[],S=function(n,r,e,f){return function(a){for(var l=o(a),s=l.length,y=0;y<s;y++){var p=l[y],v=a[p];if(v instanceof u){var S=n[v];t(S)!==c||e.has(S)?a[p]=f.call(a,p,S):(e.add(S),a[p]=i,r.push({o:a,k:p,r:S}))}else a[p]!==i&&(a[p]=f.call(a,p,v))}return a}}(f,v,new Set,y);p=S(p);for(var b=0;b<v.length;){var m=v[b++],g=m.o,h=m.k,O=m.r;g[h]=y.call(g,h,S(O))}}return y.call({"":p},"",p)},v=function(n,r,o){for(var u=r&&t(r)===c?function(n,t){return""===n||-1<r.indexOf(n)?t:void 0}:r||a,i=new Map,l=[],s=[],p=+y(i,l,u.call({"":n},"",n)),v=!p;p<l.length;)v=!0,s[p]=e(l[p++],S,o);return"["+s.join(",")+"]";function S(n,r){if(v)return v=!v,r;var e=u.call(this,n,r);switch(t(e)){case c:if(null===e)return e;case f:return i.get(e)||y(i,l,e)}return e}};return n.fromJSON=function(n){return p(e(n))},n.parse=p,n.stringify=v,n.toJSON=function(n){return r(v(n))},n}({}); \ No newline at end of file +self.Flatted=function(n){"use strict";function t(n){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n},t(n)}var r=JSON.parse,e=JSON.stringify,o=Object.keys,u=String,f="string",i={},c="object",a=function(n,t){return t},l=function(n){return n instanceof u?u(n):n},s=function(n,r){return t(r)===f?new u(r):r},y=function(n,t,r){var e=u(t.push(r)-1);return n.set(r,e),e},p=function(n,e){var f=r(n,s).map(l),y=e||a,p=f[0];if(t(p)===c&&p){var v=[],S=function(n,r,e,f){return function(a){for(var l=o(a),s=l.length,y=0;y<s;y++){var p=l[y],v=a[p];if(v instanceof u){var S=n[+v];t(S)!==c||e.has(S)?a[p]=f.call(a,p,S):(e.add(S),a[p]=i,r.push({o:a,k:p,r:S}))}else a[p]!==i&&(a[p]=f.call(a,p,v))}return a}}(f,v,new Set,y);p=S(p);for(var b=0;b<v.length;){var m=v[b++],g=m.o,h=m.k,O=m.r;g[h]=y.call(g,h,S(O))}}return y.call({"":p},"",p)},v=function(n,r,o){for(var u=r&&t(r)===c?function(n,t){return""===n||-1<r.indexOf(n)?t:void 0}:r||a,i=new Map,l=[],s=[],p=+y(i,l,u.call({"":n},"",n)),v=!p;p<l.length;)v=!0,s[p]=e(l[p++],S,o);return"["+s.join(",")+"]";function S(n,r){if(v)return v=!v,r;var e=u.call(this,n,r);switch(t(e)){case c:if(null===e)return e;case f:return i.get(e)||y(i,l,e)}return e}};return n.fromJSON=function(n){return p(e(n))},n.parse=p,n.stringify=v,n.toJSON=function(n){return r(v(n))},n}({}); \ No newline at end of file
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-rf6f-7fwh-wjghghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-33228ghsaADVISORY
- github.com/WebReflection/flatted/commit/885ddcc33cf9657caf38c57c7be45ae1c5272802ghsax_refsource_MISCWEB
- github.com/WebReflection/flatted/releases/tag/v3.4.2ghsax_refsource_MISCWEB
- github.com/WebReflection/flatted/security/advisories/GHSA-rf6f-7fwh-wjghghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.