The original xml2js package is abandoned. Despite 29+ million weekly downloads, it remains unpatched for a critical prototype pollution vulnerability (CVE-2023-0842) that can compromise application security.
@brickhouse-tech/xml2js is a drop-in replacement with the security fix applied, comprehensive regression tests added, and ongoing maintenance.
- 29.1M weekly downloads (as of March 2025)
- Last meaningful commit: Years ago
- Maintainer status: Inactive/abandoned
- Critical CVE: CVE-2023-0842 — Prototype pollution via
__proto__andconstructorkeys in parsed XML - Risk exposure: Millions of production applications vulnerable to object injection attacks
Malicious XML containing __proto__ or constructor element names can pollute JavaScript's Object prototype chain, potentially leading to:
- Remote code execution (RCE) in certain contexts
- Authentication bypass
- Data exfiltration
- Denial of service (DoS)
- Arbitrary property injection across all objects
Example attack vector:
<root>
<__proto__>
<isAdmin>true</isAdmin>
</__proto__>
</root>When parsed by vulnerable versions, this XML can inject properties into Object.prototype, affecting all objects in the application.
@brickhouse-tech/xml2js is a community-maintained fork that:
- Fixes CVE-2023-0842 with hardened property assignment using
Object.defineProperty() - Adds comprehensive regression tests (3 new test cases covering attack vectors)
- Maintains 100% API compatibility (drop-in replacement)
- Provides ongoing security maintenance and dependency updates
- Stays current with Node.js LTS releases
// Direct property assignment - vulnerable to prototype pollution
obj[key] = value;function defineProperty(obj, key, value) {
// Create a clean descriptor to prevent prototype pollution
const descriptor = Object.create(null);
descriptor.value = value;
descriptor.writable = true;
descriptor.enumerable = true;
descriptor.configurable = true;
Object.defineProperty(obj, key, descriptor);
}This approach:
- Uses
Object.create(null)to prevent descriptor pollution - Employs
Object.defineProperty()for controlled property creation - Blocks
__proto__,constructor, andprototypeinjection vectors
We added three comprehensive regression tests to verify the fix:
-
__proto__element pollution testconst maliciousXML = '<root><__proto__><polluted>POLLUTED</polluted></__proto__></root>'; // Verifies Object.prototype.polluted remains undefined
-
constructorelement pollution testconst maliciousXML = '<root><constructor><polluted>POLLUTED</polluted></constructor></root>'; // Verifies constructor pollution is blocked
-
__proto__attribute pollution testconst maliciousXML = '<root><__proto__ polluted="POLLUTED"/></root>'; // Verifies attribute-based pollution vectors are blocked
All tests verify that Object.prototype.polluted and ({}).polluted remain undefined after parsing malicious XML.
npm uninstall xml2js
npm install @brickhouse-tech/xml2jsNone. This is a 100% drop-in replacement with identical API surface.
// Original
const xml2js = require('xml2js');
// Replacement (same code, secure implementation)
const xml2js = require('@brickhouse-tech/xml2js');// Original
import * as xml2js from 'xml2js';
// Replacement (identical import)
import * as xml2js from '@brickhouse-tech/xml2js';After installation, run your test suite. No code changes should be required. If you encounter any compatibility issues, please open an issue.
- Current Version: 1.1.4
- License: MIT (same as original)
- Node.js: >=18.0.0 (ESM support)
- Repository: github.com/brickhouse-tech/node-xml2js
- NPM: @brickhouse-tech/xml2js
For organizations requiring guaranteed SLA response times, dedicated security advisories, or priority patch delivery:
Enterprise Support Tiers Available
- 🥉 Bronze: 5-day response, email support
- 🥈 Silver: 48-hour response, security advisory access
- 🥇 Gold: 24-hour response, dedicated Slack channel, custom patches
📧 Contact: brickhouse-tech.lemonsqueezy.com
This fork is maintained by Brickhouse Tech as a community service. If your organization benefits from this security patch, consider sponsoring ongoing maintenance:
Sponsorship funds:
- Security research and proactive CVE monitoring
- Dependency updates and compatibility testing
- Long-term maintenance and Node.js LTS support
- Community issue triage and documentation
The API documentation remains unchanged from the original xml2js package. For complete usage examples, see:
const xml2js = require('@brickhouse-tech/xml2js');
const xml = "<root>Hello xml2js!</root>";
xml2js.parseString(xml, function (err, result) {
console.dir(result);
});const xml2js = require('@brickhouse-tech/xml2js');
const parser = new xml2js.Parser();
parser.parseString(xml, function (err, result) {
console.dir(result);
});const xml2js = require('@brickhouse-tech/xml2js');
const xml = '<foo>bar</foo>';
xml2js.parseStringPromise(xml)
.then(result => console.dir(result))
.catch(err => console.error(err));const xml2js = require('@brickhouse-tech/xml2js');
const builder = new xml2js.Builder();
const obj = {name: "Super", Surname: "Man", age: 23};
const xml = builder.buildObject(obj);Specify options via new Parser({optionName: value}):
attrkey(default:$) — Prefix for accessing attributescharkey(default:_) — Prefix for accessing character contentexplicitCharkey(default:false) — Use charkey even for elements with no attributestrim(default:false) — Trim whitespace at start/end of text nodesnormalizeTags(default:false) — Lowercase all tag namesnormalize(default:false) — Trim whitespace inside text nodesexplicitRoot(default:true) — Include root node in resultemptyTag(default:'') — Value for empty nodes (use factory function for objects)explicitArray(default:true) — Always use arrays for child nodesignoreAttrs(default:false) — Ignore all attributesmergeAttrs(default:false) — Merge attributes as properties of parentvalidator(default:null) — Custom validation functionxmlns(default:false) — Include namespace informationexplicitChildren(default:false) — Separate property for child elementschildkey(default:$$) — Prefix for child elementspreserveChildrenOrder(default:false) — Ordered children arraycharsAsChildren(default:false) — Treat text as childrenincludeWhiteChars(default:false) — Include whitespace-only text nodesasync(default:false) — Use async callbacksstrict(default:true) — Strict XML parsing (highly recommended)attrNameProcessors(default:null) — Attribute name processing functionsattrValueProcessors(default:null) — Attribute value processing functionstagNameProcessors(default:null) — Tag name processing functionsvalueProcessors(default:null) — Element value processing functions
Specify options via new Builder({optionName: value}):
attrkey(default:$) — Prefix for attributescharkey(default:_) — Prefix for character contentrootName(default:root) — Root element namerenderOpts— Rendering options for xmlbuilder-jspretty(default:true) — Prettify outputindent(default:' ') — Indentation stringnewline(default:'\n') — Newline character
xmldec— XML declaration attributesversion(default:'1.0')encoding(default:'UTF-8')standalone(default:true)
doctype(default:null) — Optional DTDheadless(default:false) — Omit XML headerallowSurrogateChars(default:false) — Allow Unicode surrogate blockscdata(default:false) — Wrap text in CDATA when necessary
You can provide custom processing functions to transform names and values during parsing:
function nameToUpperCase(name) {
return name.toUpperCase();
}
xml2js.parseString(xml, {
tagNameProcessors: [nameToUpperCase],
attrNameProcessors: [nameToUpperCase],
valueProcessors: [nameToUpperCase],
attrValueProcessors: [nameToUpperCase]
}, function (err, result) {
// All names and values transformed to uppercase
});Available in lib/processors.js:
normalize— Transform to lowercasefirstCharLowerCase— Lowercase first character onlystripPrefix— Remove XML namespace prefix (preservesxmlns)parseNumbers— Parse numeric strings to numbersparseBooleans— Parse boolean strings to booleans
npm test # Run test suite
npm run coverage # Run with coverage report
npm run lint # Run ESLintContributions welcome! Please:
- Write tests for new features or bug fixes
- Follow existing code style (ESLint enforced)
- Update documentation as needed
- Open an issue before major changes
This project uses:
- ESM (ECMAScript modules)
- Node.js >=18
- Mocha for testing
- ESLint for code quality
Reporting vulnerabilities: Please email security issues to the maintainers rather than opening public issues. We'll coordinate disclosure and patches.
Security policy: We monitor CVE databases and dependency advisories. Critical patches are released within 48 hours of disclosure.
MIT License — same as the original xml2js package.
Copyright (c) 2010-2024 Marek Kubica and contributors
Security patches and ongoing maintenance by Brickhouse Tech.
Original package by Marek Kubica and the xml2js contributors.
Security fork maintained by:
- Brickhouse Tech — github.com/brickhouse-tech
- Lead Maintainer: Nick McCready
Special thanks to the security research community for identifying and documenting CVE-2023-0842.
The original maintainer has not responded to issues or pull requests in years. With 29M+ weekly downloads at risk, the community needed an immediate, maintained solution.
We're committed to maintaining this fork as long as the original remains inactive. If upstream development resumes, we'll evaluate reunification.
Our primary focus is security and stability. We accept bug fixes and security patches readily. New features are evaluated case-by-case to maintain compatibility.
Run the test suite (npm test) and inspect the three CVE-2023-0842 regression tests in test/parser.test.js. The fix implementation is in lib/parser.js (the defineProperty function).
Email the maintainers immediately (see Security section). Do not open public issues for vulnerabilities.
Protect your supply chain. Migrate to @brickhouse-tech/xml2js today.