Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-38361 — Advisory: CVE-2026-38361 multiple DoS vulnerabilities (CWE-400/CWE-670) in dash-uploader (Python/PyPI) | Kitploit
Tools/GitHubGitHub/a1ohadance/cve-2026-38361
Vulnerability AnalysisExploitationWeb SecurityPenetration TestingLearning & Education
GitHuba1ohadance/cve-2026-38361

CVE-2026-38361

Advisory: CVE-2026-38361 multiple DoS vulnerabilities (CWE-400/CWE-670) in dash-uploader (Python/PyPI)

View Repository
3 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-38361: Multiple Unauthenticated DoS Vulnerabilities in dash-uploader

CVE NVD CWE-400 CWE-670 Severity Patch Auth Version PyPI Downloads Total Downloads License

Multiple unauthenticated Denial of Service (DoS) issues in fohrloop/dash-uploader (Python, PyPI), including (but not limited to) Out-of-Memory (OOM) process crash, file truncation to zero bytes, permanent disk exhaustion, and complete bypass of the documented max_file_size limit. Additional resource-abuse paths exist through the same unsanitized parameter set.

⚠️ No patch is available, and none will ever be released

The repository was archived on 2025-07-19 with no active maintainer. Every published version (0.1.0 through 0.7.0a2) is affected and will remain so. The package still pulls roughly 28,000 monthly downloads.

Anyone running dash-uploader in production must apply a mitigation themselves. The recommended fix is to migrate to Plotly Dash's built-in dcc.Upload component. See Mitigation for full options.

Description

The dash-uploader HTTP handler accepts unauthenticated POST requests with attacker-controlled parameters that flow into memory allocation, file operations, and directory creation with no bounds checks, no rate limits, and no cleanup mechanism. Four independent issues in the same code path:

1. OOM crash (verified)

Verified on a 7.7 GB system: 5 concurrent POST requests with resumableTotalChunks=30000000 triggered the Linux OOM killer within 2 seconds. Kernel log confirms:

root@kitploit:~
Out of memory: Killed process 24203 (python3) total-vm:8302276kB, anon-rss:7068012kB

Each request allocates approximately 2.9 GB via a list comprehension over range(1, resumableTotalChunks + 1). The server process is terminated and the application becomes completely unavailable until manual restart.

2. File truncation (verified)

A file containing 42 bytes of data was reduced to 0 bytes via a single POST request with resumableTotalChunks=0. The root cause is Python's all() returning True for empty iterables, which tricks the upload handler into treating zero chunks as a completed upload. The existing file is deleted via os.unlink() and replaced with an empty file.

3. Abandoned upload accumulation (verified)

10 orphaned temp directories with chunk files were created and persisted indefinitely on disk. A codebase-wide search across all source files for cleanup, ttl, expire, garbage, purge, cron, schedule, and periodic returned zero results. The only cleanup call (shutil.rmtree) executes exclusively on completed uploads. There is no mechanism to reclaim disk space from incomplete sessions.

4. max_file_size bypass (verified)

The server accepted a 5 MB chunk for a file claiming resumableTotalSize=999999999999 (~999 GB) with HTTP 200. The max_file_size parameter is passed only to the React JavaScript component. The server never checks file size, chunk size, Content-Length, or Flask MAX_CONTENT_LENGTH. A developer setting max_file_size=10 has no server-side protection.

Vulnerable code

root@kitploit:~
# dash_uploader/httprequesthandler.py
def _post(self):
    resumableTotalChunks = request.form.get("resumableTotalChunks", type=int)   # attacker-controlled, no bounds
    ...
    chunk_paths = [
        os.path.join(temp_dir, get_chunk_name(resumableFilename, x))
        for x in range(1, resumableTotalChunks + 1)                              # unbounded; e.g. 30M -> ~2.9 GB -> OOM
    ]
    upload_complete = all([os.path.exists(p) for p in chunk_paths])              # all([]) is True -> truncation when chunks=0
    if upload_complete:
        target_file_name = os.path.join(temp_root, resumableFilename)
        if os.path.exists(target_file_name):
            os.unlink(target_file_name)                                          # existing file deleted
        with open(target_file_name, "ab") as target_file:
            for p in chunk_paths:                                                # empty list -> empty file written
                ...

Same code path produces both the OOM (large resumableTotalChunks) and the file-truncation primitive (resumableTotalChunks=0).

Attack vectors

An attacker sends unauthenticated POST requests to the /API/resumable endpoint.

  • OOM crash: 5 concurrent requests with resumableTotalChunks=30000000 allocate ~2.9 GB each, triggering the OOM killer.
  • Disk exhaustion: start uploads but never complete them; orphaned temp files accumulate forever.
  • File truncation: send resumableTotalChunks=0; Python all([])=True tricks the server into overwriting the target file with empty content.
  • Size bypass: any size limit set by the developer is enforced only in client JavaScript, so a direct HTTP request bypasses it entirely.

No authentication or privileges required.

Impact

  • Server process crash via Linux OOM killer triggered by unbounded memory allocation from a single user-controlled POST parameter (resumableTotalChunks)
  • Permanent disk exhaustion through abandoned upload sessions that are never cleaned up (no TTL, no garbage collection, no expiry mechanism exists in the codebase)
  • Filesystem inode exhaustion via arbitrary depth directory creation through os.makedirs() with unsanitized resumableIdentifier
  • Data destruction via file truncation to zero bytes caused by Python all() returning True for empty iterables when resumableTotalChunks=0
  • Bypass of all file size restrictions because max_file_size is enforced only in client-side JavaScript while the server-side handler performs zero size validation and never sets Flask MAX_CONTENT_LENGTH

Affected components

  • dash_uploader/httprequesthandler.py (BaseHttpRequestHandler._post method)
  • dash_uploader/upload.py (Upload function, max_file_size parameter)
  • dash_uploader/configure_upload.py (missing MAX_CONTENT_LENGTH)

Mitigation

⚠️ No patch is available, and the project is archived

Options for currently-deployed users, in order of preference:

  1. Migrate to dcc.Upload, the official upload component shipped with Plotly Dash. It has no chunk-count parameter, no on-disk temporary state, and respects Flask MAX_CONTENT_LENGTH. None of the four issues here apply. Best suited to small and medium files. For very large uploads, see item 2.
  2. Roll a small Flask upload handler with explicit per-request size enforcement (MAX_CONTENT_LENGTH), bounds on any client-supplied chunk count, and an allowlist for accepted filenames.
  3. If continuing to use dash-uploader, set Flask MAX_CONTENT_LENGTH at the application level (the library does not), and reject inputs at the application or reverse-proxy layer where any of the following are true:
    • resumableTotalChunks <= 0
    • resumableTotalChunks exceeds a reasonable bound (e.g., 10,000)
    • resumableTotalSize exceeds the developer-configured max_file_size
  4. Add a rate limit on the upload endpoint at the reverse-proxy or WAF layer to mitigate the concurrent-request OOM vector.
  5. Periodically clean up orphaned temp directories with an external cron job, since the library has no internal cleanup.

Disclosure timeline

Package context

  • Approximately 28,000 monthly downloads on PyPI (27,756 in the 30 days preceding 2026-05-07, with sustained daily volume despite repository archival). Source: pypistats.org.
  • Latest published version: 0.6.1 (stable line). Pre-releases extend to 0.7.0a2.
  • Required dependency: dash. Optional dependency: pyyaml. License: MIT.
  • 11 dependent packages, 6 dependent repositories.
  • 153 GitHub stars.
  • Repository archived 2025-07-19 (Issue #153).
  • No prior CVEs (verified against NVD, GitHub Advisory Database, Snyk, OSV on 2026-03-19).

References

  • https://www.cve.org/CVERecord?id=CVE-2026-38361
  • https://nvd.nist.gov/vuln/detail/CVE-2026-38361
  • https://github.com/fohrloop/dash-uploader
  • https://github.com/fohrloop/dash-uploader/blob/stable/dash_uploader/httprequesthandler.py
  • https://github.com/fohrloop/dash-uploader/issues/153
  • https://pypi.org/project/dash-uploader/
  • https://pypistats.org/packages/dash-uploader
  • https://libraries.io/pypi/dash-uploader
  • https://pepy.tech/project/dash-uploader
  • https://cwe.mitre.org/data/definitions/400.html
  • https://cwe.mitre.org/data/definitions/670.html
  • https://docs.python.org/3/library/functions.html#all

Discoverer

Muhammad Fitri Bin Mohd Sultan

Download Tool
CVE IDCVE-2026-38361 (NVD)
VulnerabilityUncontrolled Resource Consumption (CWE-400), Always-Incorrect Control Flow Implementation (CWE-670)
CVSS 3.17.5 / High (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)
Productdash-uploader
Affected versions0.1.0 through 0.7.0a2 (all 18 releases)
Fixed versionnone (project archived 2025-07-19)
Attack vectorRemote, unauthenticated
DiscovererMuhammad Fitri Bin Mohd Sultan
Assigned byMITRE, 2026-05-07
RelatedCVE-2026-38360 (path traversal in same library)
DateEvent
2026-03-19Vulnerabilities discovered during security research on a production deployment.
2026-03-22CVE request submitted to MITRE.
2026-05-07CVE-2026-38361 assigned by MITRE.
2026-05-07Public advisory published.
2026-05-09CVE record published on the MITRE CVE database and the NVD.