Jan 26, 2026·6 min read·8 visits
BentoML versions before 1.4.34 fail to validate file paths in `bentofile.yaml`. An attacker can craft a project configuration that references absolute paths like `/etc/passwd` or `~/.ssh/id_rsa`. When a victim runs `bentoml build` on this project, the targeted files are read and baked into the final artifact, allowing the attacker to steal secrets from developer machines or CI/CD pipelines.
A critical path traversal vulnerability in BentoML allows attackers to create malicious configuration files that, when built by a victim, silently exfiltrate sensitive local files (SSH keys, AWS credentials) into the resulting model archive. This turns standard ML build pipelines into data exfiltration engines.
The AI ecosystem is the Wild West of software development right now. Developers are pulling models from Hugging Face, cloning random GitHub repositories, and running inference pipelines with root privileges, all in the name of "velocity." BentoML is a fantastic tool in this space—it takes the headache out of packaging machine learning models into deployable Docker containers (called "Bentos"). It’s the "docker build" for the AI crowd.
But here is the problem: convenience often murders security. When you run bentoml build, the tool reads a configuration file (bentofile.yaml) to understand what files to include in the package. It expects things like python scripts, model weights, and readmes.
CVE-2026-24123 is what happens when that tool trusts you a little too much. It turns the bentoml build command into a file exfiltration utility. Imagine downloading a "state-of-the-art LLM wrapper," running the build command to containerize it, and unknowingly uploading your private SSH keys or AWS credentials inside the resulting Docker image. It is a classic supply chain poison pill, and it works because the code simply assumed that nobody would ever ask it to read /etc/shadow.
At its core, this is a textbook Path Traversal (CWE-22) vulnerability, but with a twist. Usually, we see path traversal in web servers where an attacker requests ../../../../etc/passwd. Here, the traversal happens during the build process.
BentoML allows users to specify descriptions and template files in the bentofile.yaml. For example:
description: "file:README.md"The intention is innocent: read the local README.md and use it as the description for the Bento. However, the logic handling this directive lacked what we call "containment checks." It blindly resolved whatever path was provided.
If you gave it a relative path, it joined it to the current directory. If you gave it an absolute path (on Linux/macOS) or a drive letter path (on Windows), the underlying Python os.path functions happily obliged. There was no jail, no chroot, and no validation ensuring the resolved path was actually inside the project directory.
This is the digital equivalent of a hotel concierge who, when asked to fetch a towel from "room 101", complies. But when asked to fetch a towel from "the bank vault across the street", also complies, breaks into the vault, and brings you the gold bars wrapped in a towel.
Let's look at the vulnerable code in src/bentoml/_internal/utils/filesystem.py. The function resolve_user_filepath was responsible for figuring out where files lived. Here is a simplified view of the logic prior to the fix:
def resolve_user_filepath(filepath: str, ctx: t.Optional[str]) -> str:
# Expand ~ to home directory and $VAR environment variables
_path = os.path.expanduser(os.path.expandvars(filepath))
# If it's relative, join it with the context (project root)
if not os.path.isabs(_path) and ctx:
_path = os.path.expanduser(os.path.join(ctx, filepath))
if os.path.exists(_path):
# 🚩 VULNERABILITY: Just resolves the path.
# No check to see if we escaped 'ctx'.
return os.path.realpath(_path)
raise FileNotFoundError(f"file {filepath} not found")The patch (Commit 84d08cfeb40c5f2ce71b3d3444bbaa0fb16b5ca4) introduces a secure flag and rigorous validation:
# THE FIX
if secure:
# 1. Block absolute paths
if os.path.isabs(_path):
raise ValueError("Absolute paths are not allowed...")
# 2. Block hidden files/dirs (like .ssh or .aws)
if any(p.startswith(".") for p in pathlib.Path(_path).parts):
raise ValueError("Hidden files are not allowed...")
# 3. Ensure containment within CWD
# Uses pathlib.Path.is_relative_to()The developers essentially had to reimplement a filesystem jail. They specifically added blocklists for sensitive system paths like /etc and /proc, acknowledging that standard path resolution is a minefield.
How does an attacker weaponize this? The most dangerous vector is via CI/CD pipelines. Automated build environments often hold high-privilege secrets in environment variables (AWS_ACCESS_KEY_ID, GITHUB_TOKEN).
bentofile.yaml, they inject the following directive:
service: "service.py:MyModel"
# The Payload
description: "file:/proc/self/environ"bentoml build.
description field./proc/self/environ (on Linux, this file contains the process's environment variables).README.md inside the generated Bento archive.README.md, and now has the victim's API keys.This isn't limited to environment variables. An attacker could target ~/.ssh/id_rsa by using the docker.dockerfile_template field or ~/.aws/credentials.
This vulnerability turns the build tool into a confused deputy. The impact is High Confidentiality Loss.
Consider the scenarios:
~/.aws/.Because BentoML is designed to package everything up nicely for distribution, it effectively cleans up the crime scene by wrapping the stolen loot in a legitimate-looking package. The user thinks they are deploying a model; they are actually deploying their own secrets.
If you are using BentoML, stop what you are doing and check your version.
The Fix:
Update to BentoML version 1.4.34 or later immediately. The maintainers have implemented strict checks that prevent the build process from reading outside the build context directory. They also explicitly block access to hidden directories (like .ssh) and system paths.
Defense in Depth:
Even with the patch, treat bentofile.yaml files like you treat package.json or requirements.txt scripts—with extreme suspicion. Never run build commands on untrusted repositories without auditing the configuration files first. If you are building inside CI/CD, ensure your runners have the minimum necessary privileges (Least Privilege Principle), so that even if a file read occurs, the blast radius is contained.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
BentoML BentoML | < 1.4.34 | 1.4.34 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 (Path Traversal) |
| CVSS v3.1 | 7.4 (High) |
| Attack Vector | Network / Supply Chain |
| Impact | Confidentiality (High) |
| Affected Component | bentoml build (filesystem.py) |
| Exploit Status | PoC Available |
The software 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 software 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.