Skip to content

security: support array arguments in shell execution functions (1.2.x backport)#6912

Merged
TheWitness merged 1 commit intoCacti:1.2.xfrom
somethingwithproof:backport/1.2.x-rce-shell-hardening
Mar 29, 2026
Merged

security: support array arguments in shell execution functions (1.2.x backport)#6912
TheWitness merged 1 commit intoCacti:1.2.xfrom
somethingwithproof:backport/1.2.x-rce-shell-hardening

Conversation

@somethingwithproof
Copy link
Copy Markdown
Contributor

Summary

Surgical edits, +12/-0 lines. Pure additions, no existing code modified.

  • Accept array $args in exec_background(), auto-escape each element via cacti_escapeshellarg()
  • Accept array $command_line in __rrd_execute(), auto-escape each element
  • Backward compatible: existing string callers continue to work unchanged

Security

GHSA-8522-5p3m-754c (High) - Authenticated RCE via Host Variable Injection

Test plan

  • Verify poller background execution works
  • Verify RRDtool graph rendering works
  • Test with special characters in host variables

Copilot AI review requested due to automatic review settings March 28, 2026 23:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Backport to Cacti 1.2.x that extends internal execution helpers to accept array-form arguments, aiming to reduce command-injection risk by escaping individual tokens rather than relying on pre-concatenated strings.

Changes:

  • __rrd_execute() now accepts an array $command_line and escapes each element with cacti_escapeshellarg() before joining.
  • exec_background() now accepts an array $args and escapes each element with cacti_escapeshellarg() before joining.
  • exec_background() also accepts an array $redirect_args and joins elements with spaces.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
lib/rrd.php Adds array input support for RRDtool command execution by escaping and joining tokens.
lib/poller.php Adds array input support for background process arguments (escaped) and redirect arguments (joined).

…e (1.2.x backport)

- Accept array $args in exec_background(), auto-escape via cacti_escapeshellarg()
- Accept array $command_line in __rrd_execute(), auto-escape via cacti_escapeshellarg()
- Backward compatible: string arguments still work unchanged

Addresses GHSA-8522-5p3m-754c (High) - Authenticated RCE via Host Variable Injection

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
@somethingwithproof somethingwithproof force-pushed the backport/1.2.x-rce-shell-hardening branch from b3fdce8 to ebc9101 Compare March 29, 2026 07:46
@TheWitness TheWitness merged commit 0c64426 into Cacti:1.2.x Mar 29, 2026
4 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment on lines +259 to +260
$cmd = array_shift($command_line);
$command_line = $cmd . ' ' . implode(' ', array_map('cacti_escapeshellarg', $command_line));
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When $command_line is an array, array_shift() can return null (e.g., empty array), which would produce an invalid $command_line and later calls like substr()/logging/proc I/O will behave unpredictably. Consider validating that the array is non-empty and that the first element is a non-empty command token, and fail fast (return false and/or log an error) if not.

Suggested change
$cmd = array_shift($command_line);
$command_line = $cmd . ' ' . implode(' ', array_map('cacti_escapeshellarg', $command_line));
if (empty($command_line)) {
cacti_log('RRDTool command execution failed: empty command array provided to __rrd_execute()', false, 'SYSTEM', POLLER_VERBOSITY_MEDIUM);
return false;
}
$cmd = array_shift($command_line);
if (!is_string($cmd) || $cmd === '') {
cacti_log('RRDTool command execution failed: invalid command token provided to __rrd_execute()', false, 'SYSTEM', POLLER_VERBOSITY_MEDIUM);
return false;
}
$escaped_args = array_map('cacti_escapeshellarg', $command_line);
if (!empty($escaped_args)) {
$command_line = $cmd . ' ' . implode(' ', $escaped_args);
} else {
$command_line = $cmd;
}

Copilot uses AI. Check for mistakes.

if (is_array($command_line)) {
$cmd = array_shift($command_line);
$command_line = $cmd . ' ' . implode(' ', array_map('cacti_escapeshellarg', $command_line));
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the array form, only the arguments after the first element are escaped. If the first element ($cmd) can contain whitespace/newlines (even accidentally), it defeats the goal of treating each array entry as an atomic token. Consider either escaping/quoting the first element too (in a way RRDtool accepts) or validating it against an allowed token pattern (no spaces/control chars).

Suggested change
$command_line = $cmd . ' ' . implode(' ', array_map('cacti_escapeshellarg', $command_line));
$command_line = cacti_escapeshellarg($cmd) . ' ' . implode(' ', array_map('cacti_escapeshellarg', $command_line));

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants