From 52f28025a5ac139332e214ce872b26727e489d7c Mon Sep 17 00:00:00 2001 From: FreddleSpl0it <75116288+FreddleSpl0it@users.noreply.github.com> Date: Wed, 4 Nov 2026 12:02:18 +0100 Subject: [PATCH] [Web][Dovecot] imapsync: Block skipmess in custom params --- data/Dockerfiles/dovecot/imapsync_runner.py | 2 +- .../mailcow/Imapsync/Model/CustomParams.php | 2 +- tests/php/Imapsync/Model/CustomParamsTest.php | 21 +++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/data/Dockerfiles/dovecot/imapsync_runner.py b/data/Dockerfiles/dovecot/imapsync_runner.py index 1d581ac58..ea75e2652 100755 --- a/data/Dockerfiles/dovecot/imapsync_runner.py +++ b/data/Dockerfiles/dovecot/imapsync_runner.py @@ -23,7 +23,7 @@ token_min_valid = 900 # Custom params never passed, also when stored before (same list as CustomParams::BLOCKED in the web UI) blocked_params = {'abort', 'delete2foldersbutnot', 'delete2foldersonly', 'logdir', 'logfile', 'maxlinelengthcmd', 'oauthrefreshcmd1', 'oauthrefreshcmd2', 'passfile1', 'passfile2', 'pidfile', 'pipemess', 'regexflag', 'regexmess', - 'regextrans2', 'showpasswords', 'tests', 'testsdebug', 'testslive', 'testslive6', 'testsunit', 'tmpdir'} + 'regextrans2', 'showpasswords', 'skipmess', 'tests', 'testsdebug', 'testslive', 'testslive6', 'testsunit', 'tmpdir'} # imapsync only gets these variables, not the secrets of the container environment job_env_keys = ('PATH', 'LANG', 'LC_ALL', 'TZ') # A source must not point to mailcow itself (internal Docker network), host1 is checked before each run diff --git a/data/web/inc/lib/mailcow/Imapsync/Model/CustomParams.php b/data/web/inc/lib/mailcow/Imapsync/Model/CustomParams.php index 7f31d67d7..2ea8c43d8 100644 --- a/data/web/inc/lib/mailcow/Imapsync/Model/CustomParams.php +++ b/data/web/inc/lib/mailcow/Imapsync/Model/CustomParams.php @@ -26,7 +26,7 @@ class CustomParams */ public const BLOCKED = ['abort', 'delete2foldersbutnot', 'delete2foldersonly', 'logdir', 'logfile', 'maxlinelengthcmd', 'oauthrefreshcmd1', 'oauthrefreshcmd2', 'passfile1', 'passfile2', 'pidfile', 'pipemess', 'regexflag', 'regexmess', - 'regextrans2', 'showpasswords', 'tests', 'testsdebug', 'testslive', 'testslive6', 'testsunit', 'tmpdir']; + 'regextrans2', 'showpasswords', 'skipmess', 'tests', 'testsdebug', 'testslive', 'testslive6', 'testsunit', 'tmpdir']; private static bool $warnedOldFormat = false; diff --git a/tests/php/Imapsync/Model/CustomParamsTest.php b/tests/php/Imapsync/Model/CustomParamsTest.php index 9ca43eace..674cc15dc 100644 --- a/tests/php/Imapsync/Model/CustomParamsTest.php +++ b/tests/php/Imapsync/Model/CustomParamsTest.php @@ -142,6 +142,27 @@ class CustomParamsTest extends TestCase CustomParams::toJson([['o' => '--tests', 'v' => '']], $allowlist); } + public function testCodeExecutingOptionsAreBlocked(): void + { + // imapsync evaluates these values as Perl code (eval) or runs them as commands + foreach (['delete2foldersbutnot', 'delete2foldersonly', 'maxlinelengthcmd', 'oauthrefreshcmd1', 'oauthrefreshcmd2', + 'pipemess', 'regexflag', 'regexmess', 'regextrans2', 'skipmess'] as $option) { + $this->assertContains($option, CustomParams::BLOCKED); + } + } + + public function testRunnerBlocksTheSameOptions(): void + { + $runner = file_get_contents(__DIR__ . '/../../../../data/Dockerfiles/dovecot/imapsync_runner.py'); + $this->assertSame(1, preg_match('/^blocked_params = \{(.*?)\}/ms', $runner, $m)); + preg_match_all("/'([a-z0-9]+)'/", $m[1], $options); + $runnerBlocked = $options[1]; + $blocked = CustomParams::BLOCKED; + sort($runnerBlocked); + sort($blocked); + $this->assertSame($blocked, $runnerBlocked); + } + public function testOldWhitelistFormatIsIgnored(): void { $errorLog = ini_set('error_log', '/dev/null');