CVE-2022-25848 is a serious Directory Traversal vulnerability found in the popular Node.js package static-dev-server. This security hole can allow attackers to access sensitive files outside the specified static directory simply by manipulating URL paths – making it a risk for any project using this package in any version.

In this deep dive, we’ll explain how CVE-2022-25848 works, why it happens, provide code samples and exploitation details, and suggest fixes. If you use static-dev-server for local development or in production, you’ll want to read this!

What is static-dev-server?

static-dev-server is a lightweight Node.js package that makes it easy to serve static files during development. It’s widely used for quickly spinning up servers for front-end projects.

How it should work

When the server receives a request, it joins the requested path with a pre-defined root directory and serves the corresponding file. For example:

// Example (not vulnerable) path joining:
const filePath = path.join(rootDir, requestedUrlPath);

Ideally, this makes sure users can access files *only* within the rootDir folder.

What’s the Vulnerability?

CVE-2022-25848 is a Directory Traversal vulnerability. The problem is that the static-dev-server did not properly sanitize user input in URL paths. So, if an attacker sends a path like /../../etc/passwd, the code may resolve it to a file outside of the intended root directory – e.g., your system password file (!).

Why is this possible?

The vulnerable code simply joins the user-supplied path to the root directory without checking for directory traversal patterns (../). Node.js’s path.join() will resolve these, possibly pointing *outside* the root directory.

Here’s a simplified version illustrating the unsafe logic

const http = require('http');
const path = require('path');
const fs = require('fs');

const rootDir = '/var/www/public';

http.createServer((req, res) => {
  let filePath = path.join(rootDir, req.url);
  fs.readFile(filePath, (err, data) => {
    if (err) {
      res.writeHead(404);
      return res.end('Not found');
    }
    res.writeHead(200);
    res.end(data);
  });
}).listen(808);

Problem:
If an attacker requests http://localhost:808/../../etc/passwd, filePath would resolve to /etc/passwd on Unix-like systems.

An attacker can craft a URL such as

GET /../../../../etc/passwd HTTP/1.1
Host: victim.com

If the server is running as root or a user with enough permission

- /etc/passwd is read and sent to the attacker’s browser

Proof of Concept with curl

curl http://localhost:808/../../../../etc/passwd

References

- NPM Advisory – static-dev-server
- Snyk CVE entry
- Official CVE reference

How to Fix?

The best way is to make sure resolved file paths are always within your root directory. Here’s how you can make your code safe:

http.createServer((req, res) => {
  const requestedPath = decodeURIComponent(req.url);
  const safePath = path.normalize(path.join(rootDir, requestedPath));

  // Check if the final path is inside rootDir
  if (!safePath.startsWith(rootDir)) {
    res.writeHead(403);
    return res.end('Forbidden');
  }

  fs.readFile(safePath, (err, data) => {
    if (err) {
      res.writeHead(404);
      return res.end('Not found');
    }
    res.writeHead(200);
    res.end(data);
  });
}).listen(808);


This fix ensures an attacker cannot escape the root directory.

Conclusion

CVE-2022-25848 is a classic example of why it’s vital to sanitize user input, especially in file-serving code. Directory traversal bugs remain a favorite tool for attackers, and fixing them is usually simple but crucial.

Stay safe and keep your dependencies up to date!

*For more details, always check the official advisories and monitor feeds like NVD.*


*Exclusive for you by GPT – keep learning, keep coding securely!*

Timeline

Published on: 11/29/2022 17:15:00 UTC
Last modified on: 12/01/2022 20:56:00 UTC