Low severityNVD Advisory· Published Feb 26, 2026· Updated Feb 26, 2026
fast-xml-parser has stack overflow in XMLBuilder with preserveOrder
CVE-2026-27942
Description
fast-xml-parser allows users to validate XML, parse XML to JS object, or build XML from JS object without C/C++ based libraries and no callback. Prior to version 5.3.8, the application crashes with stack overflow when user use XML builder with preserveOrder:true. Version 5.3.8 fixes the issue. As a workaround, use XML builder with preserveOrder:false or check the input data before passing to builder.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
fast-xml-parsernpm | >= 5.0.0, < 5.3.8 | 5.3.8 |
fast-xml-parsernpm | >= 4.0.0-beta.0, < 4.5.4 | 4.5.4 |
Affected products
1- Range: < 5.3.8
Patches
1c13a961910f1handle non-array input for XML builder when preserveOrder is true
2 files changed · +51 −10
spec/j2x_ordered_spec.js+37 −7 modified@@ -1,4 +1,5 @@ -import {XMLParser, XMLBuilder} from "../src/fxp.js"; +import { format } from "path"; +import { XMLParser, XMLBuilder } from "../src/fxp.js"; describe("XMLBuilder", function () { @@ -31,11 +32,11 @@ describe("XMLBuilder", function () { } const parser = new XMLParser(options); let result = parser.parse(XMLdata); - // console.log(JSON.stringify(result, null,4)); + // console.log(JSON.stringify(result, null,4)); const builder = new XMLBuilder(options); result = builder.build(result); - // console.log(result); + // console.log(result); expect(result).toEqual(expected); }); @@ -65,16 +66,16 @@ describe("XMLBuilder", function () { preserveOrder: true, cdataPropName: "#CDATA", allowBooleanAttributes: true, - // format: true, + // format: true, } const parser = new XMLParser(options); let result = parser.parse(XMLdata); - // console.log(JSON.stringify(result, null,4)); + // console.log(JSON.stringify(result, null,4)); const builder = new XMLBuilder(options); result = builder.build(result); - // console.log(result); + // console.log(result); expect(result).toEqual(expected); }); @@ -300,7 +301,7 @@ describe("XMLBuilder", function () { const options = { ignoreAttributes: false, - isArray: (tagName, jpath, isLeafNode, isAttribute) => { + isArray: (tagName, jpath, isLeafNode, isAttribute) => { if (isLeafNode === true) return true; }, preserveOrder: true @@ -319,4 +320,33 @@ describe("XMLBuilder", function () { // console.log(result); expect(result).toEqual(expected); }); + + }); + +describe("XMLBuilder- array processing issue", function () { + it("should not throw stack overflow when child value is a non-array (issue #781)", function () { + const builder = new XMLBuilder({ + ignoreAttributes: false, + attributeNamePrefix: '@_', + preserveOrder: true, + }); + const input = [ + { + 'foo': [ + { 'bar': [{ '@_V': 'baz' }] }, + //{ 'fum': [{ 'qux': '' }] }, + { 'hello': [{ '#text': 'world' }] } + ] + } + ]; + expect(function () { + builder.build(input); + }).not.toThrow(); + + const result = builder.build(input); + expect(result).toContain('<hello>world</hello>'); + expect(result).toContain('<foo>'); + }); + +}); \ No newline at end of file
src/xmlbuilder/orderedJs2Xml.js+14 −3 modified@@ -18,10 +18,21 @@ function arrToStr(arr, options, jPath, indentation) { let xmlStr = ""; let isPreviousElementTag = false; + + if (!Array.isArray(arr)) { + // Non-array values (e.g. string tag values) should be treated as text content + if (arr !== undefined && arr !== null) { + let text = arr.toString(); + text = replaceEntitiesValue(text, options); + return text; + } + return ""; + } + for (let i = 0; i < arr.length; i++) { const tagObj = arr[i]; const tagName = propName(tagObj); - if(tagName === undefined) continue; + if (tagName === undefined) continue; let newJPath = ""; if (jPath.length === 0) newJPath = tagName @@ -92,7 +103,7 @@ function propName(obj) { const keys = Object.keys(obj); for (let i = 0; i < keys.length; i++) { const key = keys[i]; - if(!obj.hasOwnProperty(key)) continue; + if (!obj.hasOwnProperty(key)) continue; if (key !== ":@") return key; } } @@ -101,7 +112,7 @@ function attr_to_str(attrMap, options) { let attrStr = ""; if (attrMap && !options.ignoreAttributes) { for (let attr in attrMap) { - if(!attrMap.hasOwnProperty(attr)) continue; + if (!attrMap.hasOwnProperty(attr)) continue; let attrVal = options.attributeValueProcessor(attr, attrMap[attr]); attrVal = replaceEntitiesValue(attrVal, options); if (attrVal === true && options.suppressBooleanAttributes) {
Vulnerability mechanics
Generated by null/stub 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-fj3w-jwp8-x2g3ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-27942ghsaADVISORY
- github.com/NaturalIntelligence/fast-xml-parser/commit/c13a961910f14986295dd28484eee830fa1a0e8aghsax_refsource_MISCWEB
- github.com/NaturalIntelligence/fast-xml-parser/pull/791ghsax_refsource_MISCWEB
- github.com/NaturalIntelligence/fast-xml-parser/security/advisories/GHSA-fj3w-jwp8-x2g3ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.