VYPR
High severityNVD Advisory· Published Mar 20, 2026· Updated Mar 25, 2026

fast-xml-parser affected by numeric entity expansion bypassing all entity expansion limits (incomplete fix for CVE-2026-26278)

CVE-2026-33036

Description

fast-xml-parser allows users to process XML from JS object without C/C++ based libraries or callbacks. Versions 4.0.0-beta.3 through 5.5.5 contain a bypass vulnerability where numeric character references (&#NNN;, &#xHH;) and standard XML entities completely evade the entity expansion limits (e.g., maxTotalExpansions, maxExpandedLength) added to fix CVE-2026-26278, enabling XML entity expansion Denial of Service. The root cause is that replaceEntitiesValue() in OrderedObjParser.js only enforces expansion counting on DOCTYPE-defined entities while the lastEntities loop handling numeric/standard entities performs no counting at all. An attacker supplying 1M numeric entity references like A can force ~147MB of memory allocation and heavy CPU usage, potentially crashing the process—even when developers have configured strict limits. This issue has been fixed in version 5.5.6.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
fast-xml-parsernpm
>= 5.0.0, < 5.5.65.5.6
fast-xml-parsernpm
>= 4.0.0-beta.3, < 4.5.54.5.5

Affected products

1

Patches

1
bd26122c838e

check for entitiy expansion for lastEntities and html entities too

https://github.com/NaturalIntelligence/fast-xml-parseramit kumar guptaMar 16, 2026via ghsa
2 files changed · +44 6
  • spec/html_spec.js+19 0 modified
    @@ -79,4 +79,23 @@ describe("XMLParser", function () {
         output = output.replace('₹', '&inr;');
         expect(output.replace(/\s+/g, "")).toEqual(html.replace(/\s+/g, ""));
       });
    +
    +  it("should throw error for html entities", function () {
    +    const entity = '&#65;'.repeat(30);
    +    const xmlData = `<root>${entity}</root>`;
    +
    +    const options = {
    +      htmlEntities: true,
    +      processEntities: {
    +        enabled: true,
    +        maxTotalExpansions: 20,
    +      }
    +    };
    +    const parser = new XMLParser(options);
    +
    +    expect(function () {
    +      const result = parser.parse(xmlData);
    +      console.log(JSON.stringify(result, null, 4));
    +    }).toThrowError(/Entity expansion limit exceeded: 30 > 20/);
    +  });
     });
    \ No newline at end of file
    
  • src/xmlparser/OrderedObjParser.js+25 6 modified
    @@ -621,7 +621,7 @@ function replaceEntitiesValue(val, tagName, jPath) {
       }
     
       // Replace DOCTYPE entities
    -  for (let entityName in this.docTypeEntities) {
    +  for (const entityName of Object.keys(this.docTypeEntities)) {
         const entity = this.docTypeEntities[entityName];
         const matches = val.match(entity.regx);
     
    @@ -653,19 +653,38 @@ function replaceEntitiesValue(val, tagName, jPath) {
           }
         }
       }
    -  if (val.indexOf('&') === -1) return val;  // Early exit
    -
       // Replace standard entities
    -  for (let entityName in this.lastEntities) {
    +  for (const entityName of Object.keys(this.lastEntities)) {
         const entity = this.lastEntities[entityName];
    +    const matches = val.match(entity.regex);
    +    if (matches) {
    +      this.entityExpansionCount += matches.length;
    +      if (entityConfig.maxTotalExpansions &&
    +        this.entityExpansionCount > entityConfig.maxTotalExpansions) {
    +        throw new Error(
    +          `Entity expansion limit exceeded: ${this.entityExpansionCount} > ${entityConfig.maxTotalExpansions}`
    +        );
    +      }
    +    }
         val = val.replace(entity.regex, entity.val);
       }
    -  if (val.indexOf('&') === -1) return val;  // Early exit
    +  if (val.indexOf('&') === -1) return val;
     
       // Replace HTML entities if enabled
       if (this.options.htmlEntities) {
    -    for (let entityName in this.htmlEntities) {
    +    for (const entityName of Object.keys(this.htmlEntities)) {
           const entity = this.htmlEntities[entityName];
    +      const matches = val.match(entity.regex);
    +      if (matches) {
    +        //console.log(matches);
    +        this.entityExpansionCount += matches.length;
    +        if (entityConfig.maxTotalExpansions &&
    +          this.entityExpansionCount > entityConfig.maxTotalExpansions) {
    +          throw new Error(
    +            `Entity expansion limit exceeded: ${this.entityExpansionCount} > ${entityConfig.maxTotalExpansions}`
    +          );
    +        }
    +      }
           val = val.replace(entity.regex, entity.val);
         }
       }
    

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

6

News mentions

0

No linked articles in our index yet.