google / google/python-fire

python-fire: (1) PAGER+shell=True RCE in console_io.More (2) bash $(...) runs when sourcing --completion from maliciously named .py file. PoC verified.

Abierto
#665 2 comentarios 0 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
Python
Estrellas
28.2k
Forks
1.5k
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

## Summary

Two related issues in **python-fire** (library + `python -m fire` entrypoint): (1) OS command injection when an external pager is spawned; (2) arbitrary shell command execution when a user **sources** a generated Bash completion script, if the CLI `name` (often derived from a `.py` filename) contains Bash command substitution or other shell metacharacters.

Repository: https://github.com/google/python-fire

---

## Issue A: `PAGER` + `subprocess.Popen(..., shell=True)`

**File:** `fire/console/console_io.py`, function `More()`, approximately lines 81–100.

**Behavior:** When `check_pager` is true (default), stdin/stdout are TTYs, and `PAGER` is set, the value from `os.environ['PAGER']` is passed to:

`subprocess.Popen(pager, stdin=subprocess.PIPE, shell=True)`

Because `shell=True`, the string is interpreted by `/bin/sh`. Metacharacters (`;`, `|`, `` ` ``, `$()`, etc.) allow **arbitrary commands** to run in the same security context as the Fire-based process.

**Trigger:** Any code path that calls `console_io.More()` with the default pager behavior—e.g. `fire.core.Display()` used for help text, traces, and other paged output—when the process has a malicious or attacker-controlled `PAGER` and an interactive terminal.

**Verification (PoC):** With `PAGER='touch /tmp/fire_verify_pager'`, run under a pseudo-TTY (e.g. `script -qefc 'python -c "from fire.console import console_io; import sys; console_io.More(\"x\", sys.stdout)"' /dev/null`). The side-effect file appears, confirming shell interpretation of `PAGER`.

---

## Issue B: Bash completion script — unsanitized `name` / `identifier`

**File:** `fire/completion.py`, function `_BashScript()`, template `bash_completion_template` and `.format(...)` around lines 179–187.

**Behavior:** The Bash script embeds `name` and `identifier` with only a weak transform:

`identifier = name.replace('/', '').replace('.', '').replace(',', '')`

Characters such as `$`, `(`, `)`, `` ` ``, `;`, newlines, etc. are **not** removed. The template includes lines such as:

- `_complete-{identifier}()`
- `complete -F _complete-{identifier} {command}`

with `command=name`. When the generated script is **sourced** by Bash, **command substitution** in `identifier` or `name` (e.g. `$(touch marker)`) is evaluated.

**Trigger:** `python -m fire` sets `name` from `os.path.basename(path)` (`fire/__main__.py`, `import_from_file_path`). A file named like `$(touch _marker).py` therefore yields a completion script that runs `touch` (or worse) when the victim runs `source` on the output of `-- --completion`.

**Verification (PoC):** Create a minimal module file literally named `$(touch _fire_verify_completion_marker).py`, run `python -m fire '' -- --completion > comp.sh`, then `bash -c 'source comp.sh'`. The marker file is created (Bash may also error on an invalid function name, but substitution still runs).

**Note:** A subshell payload **must not contain `/` in the basename** (invalid filename on Unix); use e.g. `$(touch _marker)` with a relative target.

---

## CWE mapping

- Issue A: CWE-78 (OS command injection)
- Issue B: CWE-78 / insufficient neutralization of shell metacharacters in generated shell code

**Who can exploit**

- **Issue A:** Anyone who can control the **environment** of a process that runs Fire and reaches `More()` on a TTY with `PAGER` set (e.g. misconfigured services, wrappers, CI jobs, compromised `.env`, multi-tenant job runners). The user running the CLI can also set `PAGER` themselves; the higher risk is **untrusted or inherited environment** for automated or privileged contexts.
- **Issue B:** An attacker who can place or name a `.py` file on disk (or otherwise influence the `name` passed to `fire.Fire(..., name=...)`) and convince a victim to **generate and source** Bash completion from that module (e.g. cloned repo, malicious path, social engineering). Supply-chain / “run this install script” scenarios are plausible.

**What the attacker gains**

- **Issue A:** **Arbitrary code execution** as the Fire process user: read/write secrets the process can access, lateral movement on the host, data destruction (CIA triad: High).
- **Issue B:** **Arbitrary code execution** as the user who **sources** the completion script in Bash—typically the developer’s or operator’s interactive account.

**Prerequisites / limits**

- Issue A requires an **interactive TTY** for the default pager path (`IsInteractive(output=True)`); non-TTY falls back to writing without `PAGER`.
- Issue B requires the victim to **execute** the generated script in Bash (e.g. `source`); reading the file alone is not enough.

**Suggested severity (informal)**

- Issue A: often assessed **High** locally (e.g. CVSS ~8.x) when env is attacker-influenced; lower if only self-controlled env.
- Issue B: **High** when sourcing untrusted completion is realistic; depends on social/engineering and workflow.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.