Skip to content

Back to the catalog

Anatomy of an Automated Patch: Fixing a File Upload RCE CVE-2025-59304 | depthfirst
depthfirst.comwriteup

Anatomy of an Automated Patch: Fixing a File Upload RCE CVE-2025-59304 | depthfirst

CVE-2025-59304 is a critical path traversal (CWE-22) in Swetrix Web Analytics. CdnService.uploadFile built a temp file path from the unsanitized file.originalName, so ../ sequences let an attacker overwrite files such as the app entrypoint and get RCE on restart. The depthfirst platform generated the fix, which replaces the name with a UUID and keeps only the extension (Pull Request #397).

TL;DR Dissects a path traversal file upload RCE in Swetrix (CVE-2025-59304) and the UUID-filename patch generated automatically by depthfirst.
Document

What it is

CVE-2025-59304 is a path traversal (CWE-22) in Swetrix Web Analytics. The flaw is in the CdnService.uploadFile method in backend/apps/cloud/src/marketplace/cdn/cdn.service.ts. The depthfirst post describes it as a critical remote code execution bug, and says the depthfirst platform found it and generated the patch (Pull Request #397).

How it works

The vulnerable code builds a temp file path directly from the uploaded file's name and writes the buffer there:

const filePath = `${tmpdir()}/${file.originalName}`;
await writeFile(filePath, file.buffer);

Because file.originalName is not sanitized, ../ sequences let the write land anywhere the process can reach. The page gives this exploit chain:

  1. Craft a payload, such as a JavaScript reverse shell.
  2. Pick an executable file on the server, such as the application entry point (entrypoint.js).
  3. Upload the payload with a filename like ../../app/entrypoint.js, which overwrites that file.
  4. Code execution happens when the application restarts and loads the overwritten file.

Execution therefore depends on a restart. The upload alone does not run the payload.

What to do

Apply the fix from Pull Request #397. It discards the client-supplied name and keeps only the extension:

const fileExtension = extname(file.originalName || '');
const safeFilename = `${uuidv4()}${fileExtension}`;
const filePath = `${tmpdir()}/${safeFilename}`;

The same pattern applies to any code that builds a filesystem path from an uploaded file's original name.

Caveats

The page gives no affected version range, fixed release number, CVSS score or disclosure date. It does not say whether the upload endpoint needs authentication. It does not discuss validation of the retained extension, which still comes from the client-supplied name. The exploit steps are a description, not a tested proof of concept.

Organisations named here

  • depthfirst

CVEs named here

  • CVE-2025-59304

Technologies named here

  • Node.js
  • TypeScript
  • GitHub
  • CWE-22
  • depthfirst platform
  • GitHub Pull Request #397
  • Swetrix
  • Swetrix Web Analytics (CdnService.uploadFile method in backend/apps/cloud/src/marketplace/cdn/cdn.service.ts)

Techniques named here

  • Path traversal
  • Arbitrary file overwrite leading to remote code execution