toContain("\$safe_log = cacti_escapeshellarg(read_config_option('path_rrdcheck_log'));") ->and($source)->toContain("poller_rrdcheck.php >> ' . \$safe_log . ' 2>&1'"); }); test('rrdcheck never concatenates the raw log path into the redirect', function () use ($source) { expect($source)->not->toContain("poller_rrdcheck.php >> ' . read_config_option('path_rrdcheck_log')"); }); test('escaping the malicious rrdcheck log path keeps the injection in one argument', function () { $evil = '/tmp/rrdcheck.log 2>&1; touch /tmp/pwned ; echo'; $args = 'poller_rrdcheck.php >> ' . cacti_escapeshellarg($evil) . ' 2>&1'; expect($args)->toContain("'/tmp/rrdcheck.log 2>&1; touch /tmp/pwned ; echo'") ->and(substr_count($args, "'"))->toBe(2); });