[Pkg-roundcube-maintainers] Bug#1122899: roundcube: XSS and information disclosure vulnerabilities
Guilhem Moulin
guilhem at debian.org
Thu Dec 18 12:53:34 GMT 2025
Thanks Salvatore! Here are tested debdiffs for trixie-security and
bookworm-security.
--
Guilhem.
-------------- next part --------------
diffstat for roundcube-1.6.11+dfsg roundcube-1.6.12+dfsg
.htaccess | 4
CHANGELOG.md | 13 ++
debian/changelog | 16 ++
debian/gbp.conf | 2
debian/patches/Fix-FTBFS-with-phpunit-11.patch | 136 +++++++++--------------
debian/patches/map-sqlite3-to-sqlite.patch | 2
debian/salsa-ci.yml | 3
plugins/enigma/lib/enigma_engine.php | 2
plugins/zipdownload/zipdownload.php | 11 +
program/actions/mail/import.php | 2
program/js/app.js | 7 +
program/lib/Roundcube/bootstrap.php | 29 ++--
program/lib/Roundcube/rcube_contacts.php | 11 +
program/lib/Roundcube/rcube_db.php | 11 +
program/lib/Roundcube/rcube_imap.php | 17 ++
program/lib/Roundcube/rcube_imap_generic.php | 4
program/lib/Roundcube/rcube_utils.php | 7 +
program/lib/Roundcube/rcube_washtml.php | 13 +-
program/localization/lv_LV/labels.inc | 2
public_html/.htaccess | 4
public_html/plugins/enigma/lib/enigma_engine.php | 2
public_html/plugins/zipdownload/zipdownload.php | 11 +
public_html/program/js/app.js | 7 +
tests/Framework/DB.php | 35 ++++-
tests/Framework/Utils.php | 10 +
tests/Framework/Washtml.php | 17 ++
26 files changed, 247 insertions(+), 131 deletions(-)
diff -Nru roundcube-1.6.11+dfsg/CHANGELOG.md roundcube-1.6.12+dfsg/CHANGELOG.md
--- roundcube-1.6.11+dfsg/CHANGELOG.md 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/CHANGELOG.md 2025-12-14 09:10:51.000000000 +0100
@@ -2,6 +2,19 @@
## Unreleased
+- Support IPv6 in database DSN (#9937)
+- Don't force specific error_reporting setting
+- Fix compatibility with PHP 8.5 regarding array_first()
+- Remove X-XSS-Protection example from .htaccess file (#9875)
+- Fix "Assign to group" action state after creation of a first group (#9889)
+- Fix bug where contacts search would fail if `contactlist_fields` contained vcard fields (#9850)
+- Fix bug where an mbox export file could include inconsistent message delimiters (#9879)
+- Fix parsing of inline styles that aren't well-formatted (#9948)
+- Fix Cross-Site-Scripting vulnerability via SVG's animate tag
+- Fix Information Disclosure vulnerability in the HTML style sanitizer
+
+## Release 1.6.11
+
- Managesieve: Fix match-type selector (remove unsupported options) in delete header action (#9610)
- Improve installer to fix confusion about disabling SMTP authentication (#9801)
- Fix PHP warning in index.php (#9813)
diff -Nru roundcube-1.6.11+dfsg/debian/changelog roundcube-1.6.12+dfsg/debian/changelog
--- roundcube-1.6.11+dfsg/debian/changelog 2025-06-01 11:12:44.000000000 +0200
+++ roundcube-1.6.12+dfsg/debian/changelog 2025-12-14 11:51:43.000000000 +0100
@@ -1,7 +1,21 @@
+roundcube (1.6.12+dfsg-0+deb13u1) trixie-security; urgency=high
+
+ * New upstream security and bugfix release (closes: #1122899).
+ + Fix CVE-2025-68461: Cross-Site-Scripting vulnerability via SVG's animate
+ tag.
+ + Fix CVE-2025-68460: Information Disclosure vulnerability in the HTML
+ style sanitizer.
+ * Refresh d/patches.
+ * d/gbp.conf: Set debian-branch=debian/trixie.
+ * Salsa CI: Set RELEASE=trixie, disable reprotest and lintian jobs.
+
+ -- Guilhem Moulin <guilhem at debian.org> Sun, 14 Dec 2025 11:51:43 +0100
+
roundcube (1.6.11+dfsg-1) unstable; urgency=high
* New upstream security and bugfix release.
- + Fix Post-Auth RCE via PHP Object Deserialization (closes: #1107073).
+ + Fix CVE-2025-49113: Post-Auth RCE via PHP Object Deserialization.
+ (Closes: #1107073)
* Refresh d/patches.
-- Guilhem Moulin <guilhem at debian.org> Sun, 01 Jun 2025 11:12:44 +0200
diff -Nru roundcube-1.6.11+dfsg/debian/gbp.conf roundcube-1.6.12+dfsg/debian/gbp.conf
--- roundcube-1.6.11+dfsg/debian/gbp.conf 2025-06-01 11:12:44.000000000 +0200
+++ roundcube-1.6.12+dfsg/debian/gbp.conf 2025-12-14 11:51:43.000000000 +0100
@@ -1,5 +1,5 @@
[DEFAULT]
-debian-branch = debian/latest
+debian-branch = debian/trixie
upstream-branch = upstream/release-1.6
pristine-tar = True
components = ["tinymce", "tinymce-langs"]
diff -Nru roundcube-1.6.11+dfsg/debian/patches/Fix-FTBFS-with-phpunit-11.patch roundcube-1.6.12+dfsg/debian/patches/Fix-FTBFS-with-phpunit-11.patch
--- roundcube-1.6.11+dfsg/debian/patches/Fix-FTBFS-with-phpunit-11.patch 2025-06-01 11:12:44.000000000 +0200
+++ roundcube-1.6.12+dfsg/debian/patches/Fix-FTBFS-with-phpunit-11.patch 2025-12-14 11:51:43.000000000 +0100
@@ -159,7 +159,7 @@
tests/Framework/Contacts.php | 14 +-
tests/Framework/ContentFilter.php | 12 +-
tests/Framework/Csv2vcard.php | 18 +-
- tests/Framework/DB.php | 31 +--
+ tests/Framework/DB.php | 27 +--
tests/Framework/DBMssql.php | 14 +-
tests/Framework/DBMysql.php | 14 +-
tests/Framework/DBOracle.php | 14 +-
@@ -222,7 +222,7 @@
tests/StderrMock.php | 15 +-
tests/StorageMock.php | 4 +-
tests/bootstrap.php | 21 +-
- 213 files changed, 2505 insertions(+), 1799 deletions(-)
+ 213 files changed, 2503 insertions(+), 1797 deletions(-)
diff --git a/plugins/acl/tests/Acl.php b/plugins/acl/tests/Acl.php
index 94e0bd4..0ad987f 100644
@@ -7405,7 +7405,7 @@
$result = $csv->export();
diff --git a/tests/Framework/DB.php b/tests/Framework/DB.php
-index 09d40ea..b8991df 100644
+index 3ac4f13..853489d 100644
--- a/tests/Framework/DB.php
+++ b/tests/Framework/DB.php
@@ -1,12 +1,17 @@
@@ -7428,25 +7428,7 @@
{
/**
* Test script execution and table_prefix replacements
-@@ -178,7 +183,7 @@ class Framework_DB extends PHPUnit\Framework\TestCase
- {
- $dsn = "mysql://USERNAME:PASSWORD@HOST:3306/DATABASE";
-
-- $result = rcube_db::parse_dsn($dsn);
-+ $result = \rcube_db::parse_dsn($dsn);
-
- $this->assertSame('mysql', $result['phptype']);
- $this->assertSame('USERNAME', $result['username']);
-@@ -189,7 +194,7 @@ class Framework_DB extends PHPUnit\Framework\TestCase
-
- $dsn = "pgsql:///DATABASE";
-
-- $result = rcube_db::parse_dsn($dsn);
-+ $result = \rcube_db::parse_dsn($dsn);
-
- $this->assertSame('pgsql', $result['phptype']);
- $this->assertTrue(!array_key_exists('username', $result));
-@@ -204,7 +209,7 @@ class Framework_DB extends PHPUnit\Framework\TestCase
+@@ -227,7 +232,7 @@ class Framework_DB extends PHPUnit\Framework\TestCase
*/
function test_list_tables()
{
@@ -7455,7 +7437,7 @@
$tables = $db->list_tables();
-@@ -216,7 +221,7 @@ class Framework_DB extends PHPUnit\Framework\TestCase
+@@ -239,7 +244,7 @@ class Framework_DB extends PHPUnit\Framework\TestCase
*/
function test_list_cols()
{
@@ -7464,7 +7446,7 @@
$columns = $db->list_cols('cache');
-@@ -228,7 +233,7 @@ class Framework_DB extends PHPUnit\Framework\TestCase
+@@ -251,7 +256,7 @@ class Framework_DB extends PHPUnit\Framework\TestCase
*/
function test_array2list()
{
@@ -7473,7 +7455,7 @@
$this->assertSame('', $db->array2list([]));
$this->assertSame('\'test\'', $db->array2list(['test']));
-@@ -241,7 +246,7 @@ class Framework_DB extends PHPUnit\Framework\TestCase
+@@ -264,7 +269,7 @@ class Framework_DB extends PHPUnit\Framework\TestCase
*/
function test_concat()
{
@@ -7482,7 +7464,7 @@
$this->assertSame('(test)', $db->concat('test'));
$this->assertSame('(test1 || test2)', $db->concat('test1', 'test2'));
-@@ -259,20 +264,20 @@ class Framework_DB extends PHPUnit\Framework\TestCase
+@@ -282,20 +287,20 @@ class Framework_DB extends PHPUnit\Framework\TestCase
$str .= chr($x);
}
@@ -10024,7 +10006,7 @@
$idents = $user->list_identities();
diff --git a/tests/Framework/Utils.php b/tests/Framework/Utils.php
-index 4e52809..962f3a3 100644
+index 29df81d..cf76834 100644
--- a/tests/Framework/Utils.php
+++ b/tests/Framework/Utils.php
@@ -1,11 +1,15 @@
@@ -10239,10 +10221,10 @@
+ $mod = \rcube_utils::mod_css_styles($style, 'rcmbody', true);
$this->assertSame("#rcmbody { content: ''; color: red; }", $mod);
- $style = "body { content: '< page: ;/style>< page: ;img src onerror=\"alert(\'hello\');\">'; color: red; }";
+ $style = "body { content: '< page: ;/style>< page: ;img src onerror=\"alert(\\'hello\\');\">'; color: red; }";
- $mod = rcube_utils::mod_css_styles($style, 'rcmbody', true);
+ $mod = \rcube_utils::mod_css_styles($style, 'rcmbody', true);
- $this->assertSame("#rcmbody { content: '< page: ;/style>< page: ;img src onerror=\"alert('hello');\">'; color: red; }", $mod);
+ $this->assertSame("#rcmbody { color: red; }", $mod);
// Removing page: property
$style = "body { page: test; color: red }";
@@ -10295,19 +10277,19 @@
{
return [
[
-@@ -431,9 +440,10 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -435,9 +444,10 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
*
* @dataProvider data_parse_css_block
*/
+ #[DataProvider('data_parse_css_block')]
- function test_explode_style($input, $output)
+ function test_parse_css_block($input, $output)
{
- $this->assertSame($output, rcube_utils::parse_css_block($input));
+ $this->assertSame($output, \rcube_utils::parse_css_block($input));
}
/**
-@@ -448,7 +458,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -452,7 +462,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($data as $text => $res) {
@@ -10316,7 +10298,7 @@
$this->assertSame($res, $result);
}
}
-@@ -461,7 +471,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -465,7 +475,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
$data = ['', 'a,b,c', 'a', ',', ',a'];
foreach ($data as $text) {
@@ -10325,7 +10307,7 @@
$this->assertSame(explode(',', $text), $result);
}
}
-@@ -476,7 +486,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -480,7 +490,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($input as $idx => $value) {
@@ -10334,7 +10316,7 @@
}
$input = [
-@@ -484,7 +494,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -488,7 +498,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($input as $idx => $value) {
@@ -10343,7 +10325,7 @@
}
}
-@@ -494,13 +504,13 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -498,13 +508,13 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
function test_get_input_string()
{
$_GET = [];
@@ -10360,7 +10342,7 @@
}
/**
-@@ -508,18 +518,18 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -512,18 +522,18 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
*/
function test_is_simple_string()
{
@@ -10391,7 +10373,7 @@
}
/**
-@@ -534,7 +544,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -538,7 +548,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($test as $v) {
@@ -10400,7 +10382,7 @@
$this->assertSame($v[2], $result);
}
}
-@@ -564,7 +574,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -568,7 +578,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($test as $datetime => $ts) {
@@ -10409,7 +10391,7 @@
$this->assertSame($ts, $result, "Error parsing date: $datetime");
}
}
-@@ -591,7 +601,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -595,7 +605,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($test as $datetime => $ts) {
@@ -10418,7 +10400,7 @@
$this->assertSame($ts, $result ? $result->format('Y-m-d') : false, "Error parsing date: $datetime");
}
-@@ -601,7 +611,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -605,7 +615,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($test as $datetime => $ts) {
@@ -10427,7 +10409,7 @@
$this->assertSame($ts, $result ? $result->format('Y-m-d H:i:s') : false, "Error parsing date: $datetime");
}
-@@ -610,7 +620,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -614,7 +624,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($test as $datetime => $ts) {
@@ -10436,7 +10418,7 @@
$this->assertSame($ts, $result ? $result->format('Y-m-d H:i:s O') : false, "Error parsing date: $datetime");
}
}
-@@ -620,17 +630,17 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -624,17 +634,17 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
*/
function test_anytodatetime_timezone()
{
@@ -10457,7 +10439,7 @@
if ($result) $result->setTimezone($tz); // move to target timezone for comparison
$this->assertSame($ts, $result ? $result->format('Y-m-d H:i') : false, "Error parsing date: $datetime");
}
-@@ -649,7 +659,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -653,7 +663,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($test as $data) {
@@ -10466,7 +10448,7 @@
$this->assertSame($data[2], $result, "Error formatting date: " . $data[0]);
}
}
-@@ -668,7 +678,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -672,7 +682,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($test as $input => $output) {
@@ -10475,7 +10457,7 @@
$this->assertSame($output, $result);
}
}
-@@ -693,7 +703,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -697,7 +707,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($test as $input => $output) {
@@ -10484,7 +10466,7 @@
$this->assertSame($output, $result, "Error normalizing '$input'");
}
}
-@@ -716,7 +726,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -720,7 +730,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
];
foreach ($test as $idx => $params) {
@@ -10493,7 +10475,7 @@
$this->assertSame($params[2], $result, "words_match() at index $idx");
}
}
-@@ -742,7 +752,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -746,7 +756,7 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
}
foreach ($test as $input => $output) {
@@ -10502,7 +10484,7 @@
$this->assertSame($output, $result);
}
}
-@@ -752,17 +762,17 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -756,17 +766,17 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
*/
function test_random_bytes()
{
@@ -10526,7 +10508,7 @@
{
/*
-@@ -799,9 +809,10 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -803,9 +813,10 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
* @param string $encoded Encoded email address
* @dataProvider data_idn_convert
*/
@@ -10538,7 +10520,7 @@
}
/**
-@@ -811,9 +822,10 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -815,9 +826,10 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
* @param string $encoded Encoded email address
* @dataProvider data_idn_convert
*/
@@ -10550,7 +10532,7 @@
}
/**
-@@ -821,14 +833,14 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -825,14 +837,14 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
*/
function test_idn_to_ascii_special()
{
@@ -10568,7 +10550,7 @@
{
return [
['%z', 'hostname', 'hostname'],
-@@ -843,15 +855,16 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -847,15 +859,16 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
*
* @dataProvider data_parse_host
*/
@@ -10587,7 +10569,7 @@
{
return [
[['hostname', null, null], ['hostname', null, null]],
-@@ -874,15 +887,16 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -878,15 +891,16 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
*
* @dataProvider data_parse_host_uri
*/
@@ -10606,7 +10588,7 @@
return [
['both', 'Fwd: Re: Test subject both', 'Test subject both'],
['both', 'Re: Fwd: Test subject both', 'Test subject both'],
-@@ -900,8 +914,9 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -904,8 +918,9 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
*
* @dataProvider data_remove_subject_prefix
*/
@@ -10617,7 +10599,7 @@
}
/**
-@@ -909,13 +924,13 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -913,13 +928,13 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
*/
function test_server_name()
{
@@ -10634,7 +10616,7 @@
}
/**
-@@ -925,31 +940,31 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+@@ -929,31 +944,31 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
{
$_SERVER['test'] = 'test.com';
@@ -10833,7 +10815,7 @@
$this->assertSame($result, "BEGIN:VCARD\r\nVERSION:3.0\r\nFN:\r\nN:;;;;\r\nEND:VCARD");
diff --git a/tests/Framework/Washtml.php b/tests/Framework/Washtml.php
-index 4fdae1a..7e5de5f 100644
+index 0b9e1e9..a3a6d5b 100644
--- a/tests/Framework/Washtml.php
+++ b/tests/Framework/Washtml.php
@@ -1,11 +1,14 @@
@@ -11007,7 +10989,7 @@
$washed = $washer->wash($html);
$this->assertTrue(strpos($washed, $exp) !== false, "Style quotes XSS issue (#1490227)");
-@@ -319,7 +322,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -326,7 +329,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
*/
function test_title()
{
@@ -11016,8 +10998,8 @@
$html = "<html><head><title>title1</title></head><body><p>test</p></body>";
$washed = $washer->wash($html);
-@@ -365,7 +368,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
- <animate attributeName="xlink:href" begin="0" x-washed="from" />
+@@ -372,7 +375,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+ <!-- animate blocked -->
</svg>';
- $washer = new rcube_washtml;
@@ -11025,7 +11007,7 @@
$washed = $washer->wash($svg);
$this->assertSame($washed, $exp, "SVG content");
-@@ -374,7 +377,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -381,7 +384,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
/**
* Test cases for SVG tests
*/
@@ -11034,7 +11016,7 @@
{
$svg1 = "<svg id='x' width='100' height='100'><a xlink:href='javascript:alert(1)'><rect x='0' y='0' width='100' height='100' /></a></svg>";
-@@ -485,9 +488,10 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -500,9 +503,10 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
*
* @dataProvider data_wash_svg_tests
*/
@@ -11046,7 +11028,7 @@
$washed = $washer->wash($input);
$this->assertSame($expected, $this->cleanupResult($washed), "SVG content");
-@@ -496,7 +500,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -511,7 +515,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
/**
* Test cases for various XSS issues
*/
@@ -11055,7 +11037,7 @@
{
return [
[
-@@ -551,9 +555,10 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -566,9 +570,10 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
*
* @dataProvider data_wash_xss_tests
*/
@@ -11067,7 +11049,7 @@
$washed = $washer->wash($input);
$this->assertSame($expected, $this->cleanupResult($washed), "XSS issues");
-@@ -567,7 +572,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -582,7 +587,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
$html = "<img style='position:fixed' /><img style=\"position:/**/ fixed; top:10px\" />";
$exp = "<img style=\"position: absolute\" /><img style=\"position: absolute; top: 10px\" />";
@@ -11076,7 +11058,7 @@
$washed = $washer->wash($html);
$this->assertTrue(strpos($washed, $exp) !== false, "Position:fixed (#5264)");
-@@ -611,7 +616,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -626,7 +631,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
<annotation encoding="TeX">I_D = \frac{1}{2} k_n \frac{W}{L} (V_{GS}-V_t)^2</annotation>
</semantics></math>';
@@ -11085,7 +11067,7 @@
$washed = $washer->wash($mathml);
// remove whitespace between tags
-@@ -628,7 +633,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -643,7 +648,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
{
$html = "<input type=\"image\" src=\"http://TRACKING_URL/\">";
@@ -11094,7 +11076,7 @@
$washed = $washer->wash($html);
$this->assertTrue($washer->extlinks);
-@@ -636,7 +641,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -651,7 +656,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
$html = "<video src=\"http://TRACKING_URL/\">";
@@ -11103,7 +11085,7 @@
$washed = $washer->wash($html);
$this->assertTrue($washer->extlinks);
-@@ -657,14 +662,14 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -672,14 +677,14 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
];
foreach ($html as $item) {
@@ -11120,7 +11102,7 @@
$washed = $washer->wash($item[0]);
$this->assertFalse($washer->extlinks);
-@@ -675,7 +680,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -690,7 +695,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
{
$html = '<textarea><p style="x:</textarea><img src=x onerror=alert(1)>">';
@@ -11129,7 +11111,7 @@
$washed = $washer->wash($html);
$this->assertStringNotContainsString('onerror=alert(1)>', $washed);
-@@ -687,7 +692,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -702,7 +707,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
*/
function test_css_prefix()
{
@@ -11138,7 +11120,7 @@
$html = '<p id="my-id">'
. '<label for="my-other-id" class="my-class1 my-class2">test</label>'
-@@ -715,14 +720,14 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -730,14 +735,14 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
{
$html = '<p><?xml:namespace prefix = "xsl" /></p>';
@@ -11155,7 +11137,7 @@
$washed = $this->cleanupResult($washer->wash($html));
$this->assertSame($washed, 'HTML');
-@@ -733,7 +738,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -748,7 +753,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
*/
function test_missing_tags()
{
@@ -11164,7 +11146,7 @@
$html = '<head></head>First line<br />Second line';
$washed = $washer->wash($html);
-@@ -775,7 +780,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -790,7 +795,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
{
$html = '<p><![CDATA[<script>alert(document.cookie)</script>]]></p>';
@@ -11173,7 +11155,7 @@
$washed = $washer->wash($html);
$this->assertTrue(strpos($washed, '<script>') === false, "CDATA content");
-@@ -787,7 +792,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -802,7 +807,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
function test_resolve_base()
{
$html = file_get_contents(TESTS_DIR . 'src/htmlbase.txt');
@@ -11182,7 +11164,7 @@
$this->assertMatchesRegularExpression('|src="http://alec\.pl/dir/img1\.gif"|', $html, "URI base resolving [1]");
$this->assertMatchesRegularExpression('|src="http://alec\.pl/dir/img2\.gif"|', $html, "URI base resolving [2]");
-@@ -833,7 +838,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+@@ -848,7 +853,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
<tr><td></td></tr>
</table>';
diff -Nru roundcube-1.6.11+dfsg/debian/patches/map-sqlite3-to-sqlite.patch roundcube-1.6.12+dfsg/debian/patches/map-sqlite3-to-sqlite.patch
--- roundcube-1.6.11+dfsg/debian/patches/map-sqlite3-to-sqlite.patch 2025-06-01 11:12:44.000000000 +0200
+++ roundcube-1.6.12+dfsg/debian/patches/map-sqlite3-to-sqlite.patch 2025-12-14 11:51:43.000000000 +0100
@@ -9,7 +9,7 @@
1 file changed, 1 insertion(+)
diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php
-index 96090cb..6387b47 100644
+index 7384c98..e2fbe1a 100644
--- a/program/lib/Roundcube/rcube_db.php
+++ b/program/lib/Roundcube/rcube_db.php
@@ -81,6 +81,7 @@ class rcube_db
diff -Nru roundcube-1.6.11+dfsg/debian/salsa-ci.yml roundcube-1.6.12+dfsg/debian/salsa-ci.yml
--- roundcube-1.6.11+dfsg/debian/salsa-ci.yml 2025-06-01 11:12:44.000000000 +0200
+++ roundcube-1.6.12+dfsg/debian/salsa-ci.yml 2025-12-14 11:51:43.000000000 +0100
@@ -3,5 +3,8 @@
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml
variables:
+ RELEASE: 'trixie'
+ SALSA_CI_DISABLE_REPROTEST: 1
+ SALSA_CI_DISABLE_LINTIAN: 1
# install suitable RDBMS before running piuparts (workaround for #1015732)
SALSA_CI_PIUPARTS_PRE_INSTALL_SCRIPT: 'debian/salsa-ci/pre_install_database-server'
diff -Nru roundcube-1.6.11+dfsg/.htaccess roundcube-1.6.12+dfsg/.htaccess
--- roundcube-1.6.11+dfsg/.htaccess 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/.htaccess 2025-12-14 09:10:51.000000000 +0100
@@ -55,10 +55,6 @@
# Only template - fill with your values
#Header always set Public-Key-Pins "max-age=3600; report-uri=\"\"; pin-sha256=\"\"; pin-sha256=\"\"" env=HTTPS
-# X-Xss-Protection
-# This header is used to configure the built in reflective XSS protection found in Internet Explorer, Chrome and Safari (Webkit).
-#Header set X-XSS-Protection "1; mode=block"
-
# X-Frame-Options
# The X-Frame-Options header (RFC), or XFO header, protects your visitors against clickjacking attacks
# Already set by php code! Do not activate both options
diff -Nru roundcube-1.6.11+dfsg/plugins/enigma/lib/enigma_engine.php roundcube-1.6.12+dfsg/plugins/enigma/lib/enigma_engine.php
--- roundcube-1.6.11+dfsg/plugins/enigma/lib/enigma_engine.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/plugins/enigma/lib/enigma_engine.php 2025-12-14 09:10:51.000000000 +0100
@@ -882,7 +882,7 @@
// @TODO: Handle big bodies using (temp) files
// Get rid of possible non-ascii characters (#5962)
- $sig_body = preg_replace('/[^\x00-\x7F]/', '', $sig_body);
+ $sig_body = preg_replace('/[^\x00-\x7F]/', '', (string) $sig_body);
$sig = $this->pgp_driver->verify($msg_body, $sig_body);
diff -Nru roundcube-1.6.11+dfsg/plugins/zipdownload/zipdownload.php roundcube-1.6.12+dfsg/plugins/zipdownload/zipdownload.php
--- roundcube-1.6.11+dfsg/plugins/zipdownload/zipdownload.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/plugins/zipdownload/zipdownload.php 2025-12-14 09:10:51.000000000 +0100
@@ -315,6 +315,7 @@
$zip = new ZipArchive();
$zip->open($tmpfname, ZIPARCHIVE::OVERWRITE);
+ $last_key = array_key_last($messages);
foreach ($messages as $key => $value) {
list($uid, $mbox) = explode(':', $key, 2);
$imap->set_folder($mbox);
@@ -327,7 +328,15 @@
$filter = stream_filter_append($tmpfp, 'mbox_filter');
$imap->get_raw_body($uid, $tmpfp);
stream_filter_remove($filter);
- fwrite($tmpfp, "\r\n");
+
+ // Make sure the delimiter is a double \r\n
+ $fstat = fstat($tmpfp);
+ if (stream_get_contents($tmpfp, 2, $fstat['size'] - 2) != "\r\n") {
+ fwrite($tmpfp, "\r\n");
+ }
+ if ($key != $last_key) {
+ fwrite($tmpfp, "\r\n");
+ }
}
else { // maildir
$tmpfn = rcube_utils::temp_filename('zipmessage');
diff -Nru roundcube-1.6.11+dfsg/program/actions/mail/import.php roundcube-1.6.12+dfsg/program/actions/mail/import.php
--- roundcube-1.6.11+dfsg/program/actions/mail/import.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/program/actions/mail/import.php 2025-12-14 09:10:51.000000000 +0100
@@ -54,7 +54,7 @@
continue;
}
}
- else if (!in_array($mtype_primary, ['text', 'message'])) {
+ else if (!in_array($mtype_primary, ['text', 'message']) && $ctype != 'application/mbox') {
continue;
}
diff -Nru roundcube-1.6.11+dfsg/program/js/app.js roundcube-1.6.12+dfsg/program/js/app.js
--- roundcube-1.6.11+dfsg/program/js/app.js 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/program/js/app.js 2025-12-14 09:10:51.000000000 +0100
@@ -6781,9 +6781,16 @@
.click(function() { return ref.command('listgroup', prop, this); })
.text(prop.name);
+ if (!this.env.contactgroups.length)
+ this.env.contactgroups = {}
+
this.env.contactfolders[key] = this.env.contactgroups[key] = prop;
this.treelist.insert({ id:key, html:link, classes:['contactgroup'] }, prop.source, 'contactgroup');
+ // If there was a contact selected we have to clear the list because we have outdated
+ // some commands state (e.g. group-assign-selected) as well as groups list in the contact frame
+ this.contact_list.clear_selection();
+
// make sure there is no cached address book or contact group selectors
this.destroy_entity_selector('addressbook-selector');
this.destroy_entity_selector('contactgroup-selector');
diff -Nru roundcube-1.6.11+dfsg/program/lib/Roundcube/bootstrap.php roundcube-1.6.12+dfsg/program/lib/Roundcube/bootstrap.php
--- roundcube-1.6.11+dfsg/program/lib/Roundcube/bootstrap.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/program/lib/Roundcube/bootstrap.php 2025-12-14 09:10:51.000000000 +0100
@@ -26,7 +26,6 @@
*/
$config = [
- 'error_reporting' => E_ALL & ~E_NOTICE & ~E_STRICT,
'display_errors' => false,
'log_errors' => true,
// Some users are not using Installer, so we'll check some
@@ -298,19 +297,21 @@
return $keys;
}
-/**
- * Get first element from an array
- *
- * @param array $array Input array
- *
- * @return mixed First element if found, Null otherwise
- */
-function array_first($array)
-{
- if (is_array($array)) {
- reset($array);
- foreach ($array as $element) {
- return $element;
+if (!function_exists('array_first')) {
+ /**
+ * Get first element from an array
+ *
+ * @param array $array Input array
+ *
+ * @return mixed First element if found, Null otherwise
+ */
+ function array_first($array)
+ {
+ if (is_array($array)) {
+ reset($array);
+ foreach ($array as $element) {
+ return $element;
+ }
}
}
}
diff -Nru roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_contacts.php roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_contacts.php
--- roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_contacts.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_contacts.php 2025-12-14 09:10:51.000000000 +0100
@@ -351,7 +351,16 @@
foreach ($words as $word) {
$groups = [];
foreach ((array) $fields as $idx => $col) {
- $groups[] = $this->fulltext_sql_where($word, $mode, $col);
+ // table column
+ if (in_array($col, $this->table_cols)) {
+ $groups[] = $this->fulltext_sql_where($word, $mode, $col);
+ }
+ // vCard field
+ else {
+ if (in_array($col, $this->fulltext_cols)) {
+ $groups[] = $this->fulltext_sql_where($word, $mode, 'words');
+ }
+ }
}
$where[] = '(' . implode(' OR ', $groups) . ')';
}
diff -Nru roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_db.php roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_db.php
--- roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_db.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_db.php 2025-12-14 09:10:51.000000000 +0100
@@ -1310,9 +1310,18 @@
// process the different protocol options
$parsed['protocol'] = !empty($proto) ? $proto : 'tcp';
$proto_opts = rawurldecode($proto_opts);
- if (strpos($proto_opts, ':') !== false) {
+
+ // Support IPv6 in the host spec.
+ if (preg_match('/(\[[a-f0-9:]+\])/i', $proto_opts, $matches)) {
+ $proto_opts = str_replace($matches[1], '', $proto_opts);
+ if (($pos = strpos($proto_opts, ':')) !== false) {
+ $parsed['port'] = substr($proto_opts, $pos + 1);
+ }
+ $proto_opts = $matches[1];
+ } elseif (strpos($proto_opts, ':') !== false) {
list($proto_opts, $parsed['port']) = explode(':', $proto_opts);
}
+
if ($parsed['protocol'] == 'tcp' && strlen($proto_opts)) {
$parsed['hostspec'] = $proto_opts;
}
diff -Nru roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_imap_generic.php roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_imap_generic.php
--- roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_imap_generic.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_imap_generic.php 2025-12-14 09:10:51.000000000 +0100
@@ -2574,7 +2574,9 @@
$result[$id]->envelope = $value;
}
else if ($name == 'BODYSTRUCTURE' || ($name == 'BODY' && count($value) > 2)) {
- if (!is_array($value[0]) && (strtolower($value[0]) == 'message' && strtolower($value[1]) == 'rfc822')) {
+ if (is_string($value[0]) && is_string($value[1])
+ && strtolower($value[0]) == 'message' && strtolower($value[1]) == 'rfc822'
+ ) {
$value = [$value];
}
$result[$id]->bodystructure = $value;
diff -Nru roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_imap.php roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_imap.php
--- roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_imap.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_imap.php 2025-12-14 09:10:51.000000000 +0100
@@ -2136,14 +2136,21 @@
x. location (optional)
*/
+ // regular part
+ // Note: If the BODYSTRUCTURE is invalid index 0 and 1 can be NULL (#9896)
+ if (is_array($part[1])) {
+ $struct->ctype_primary = 'multipart';
+ $struct->ctype_secondary = isset($part[0]) ? strtolower($part[0]) : 'mixed';
+ } else {
+ $struct->ctype_primary = isset($part[0]) ? strtolower($part[0]) : 'text';
+ $struct->ctype_secondary = isset($part[1]) ? strtolower($part[1]) : 'plain';
+ }
+
+ $struct->mimetype = $struct->ctype_primary . '/' . $struct->ctype_secondary;
+
// Sometimes it might be: 0. subtype, 1. parameters, ...
$params_idx = is_array($part[1]) ? 1 : 2;
- // regular part
- $struct->ctype_primary = is_array($part[1]) ? 'multipart' : strtolower($part[0]);
- $struct->ctype_secondary = is_array($part[1]) ? strtolower($part[0]) : strtolower($part[1]);
- $struct->mimetype = $struct->ctype_primary.'/'.$struct->ctype_secondary;
-
// read content type parameters
if (is_array($part[$params_idx])) {
$struct->ctype_parameters = [];
diff -Nru roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_utils.php roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_utils.php
--- roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_utils.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_utils.php 2025-12-14 09:10:51.000000000 +0100
@@ -559,6 +559,9 @@
$value .= ' url(' . $url . ')';
}
}
+ } elseif (preg_match('/;.*/', $val)) {
+ // Invalid or evil content, ignore
+ continue;
} else {
// whitelist ?
$value .= ' ' . $val;
@@ -642,7 +645,9 @@
}
$value_length = $i - $colon_pos - ($s ? 1 : 0);
- $value = trim(substr($style, $colon_pos + 1, $value_length));
+ $value = trim(substr($style, $colon_pos + 1, $value_length));
+ // Remove "orfaned" semicolons (#9948)
+ $name = ltrim($name, "; \t\r\n");
if (strlen($name) && !preg_match('/[^a-z-]/', $name) && strlen($value) && $value !== ';') {
$result[] = [$name, $value];
diff -Nru roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_washtml.php roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_washtml.php
--- roundcube-1.6.11+dfsg/program/lib/Roundcube/rcube_washtml.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/program/lib/Roundcube/rcube_washtml.php 2025-12-14 09:10:51.000000000 +0100
@@ -303,7 +303,8 @@
// in SVG to/from attribs may contain anything, including URIs
if ($key == 'to' || $key == 'from') {
- $key = strtolower($node->getAttribute('attributeName'));
+ $key = strtolower((string) $node->getAttribute('attributeName'));
+ $key = trim(preg_replace('/^.*:/', '', $key));
if ($key && !isset($this->_html_attribs[$key])) {
$key = null;
}
@@ -512,10 +513,14 @@
private static function attribute_value($node, $attr_name, $attr_value)
{
$attr_name = strtolower($attr_name);
+ $attr_value = strtolower($attr_value);
foreach ($node->attributes as $name => $attr) {
if (strtolower($name) === $attr_name) {
- if (strtolower($attr_value) === strtolower(trim($attr->nodeValue))) {
+ // Read the attribute name, remove the namespace (e.g. xlink:href => href)
+ $val = strtolower(trim($attr->nodeValue));
+ $val = trim(preg_replace('/^.*:/', '', $val));
+ if ($attr_value === $val) {
return true;
}
}
@@ -734,6 +739,7 @@
// space(s) between <NOBR>
'/(<\/nobr>)(\s+)(<nobr>)/i',
// PHP bug #32547 workaround: remove title tag
+ // TODO: This is an old libxml2 bug, maybe we could drop this at some point
'/<title[^>]*>.*<\/title>/iU',
// remove <!doctype> before BOM (#1490291)
'/<\!doctype[^>]+>[^<]*/im',
@@ -741,8 +747,7 @@
'/^(\0\0\xFE\xFF|\xFF\xFE\0\0|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/',
// washtml/DOMDocument cannot handle xml namespaces
'/<html\s[^>]+>/i',
- // washtml/DOMDocument cannot handle xml namespaces
- // HTML5 parser cannot handler <?xml
+ // HTML5 parser cannot handle <?xml
'/<\?xml[^>]*>/i',
];
diff -Nru roundcube-1.6.11+dfsg/program/localization/lv_LV/labels.inc roundcube-1.6.12+dfsg/program/localization/lv_LV/labels.inc
--- roundcube-1.6.11+dfsg/program/localization/lv_LV/labels.inc 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/program/localization/lv_LV/labels.inc 2025-12-14 09:10:51.000000000 +0100
@@ -132,7 +132,7 @@
$labels['markmessages'] = 'Atzīmēt vēstules:';
$labels['markread'] = 'kā lasītas';
$labels['markunread'] = 'kā nelasītas';
-$labels['markflagged'] = 'kā atīmētas';
+$labels['markflagged'] = 'kā atzīmētas';
$labels['markunflagged'] = 'kā neatzīmētas';
$labels['moreactions'] = 'Papildus darbības...';
$labels['markallread'] = 'Atzīmēt visus kā izlasītus';
diff -Nru roundcube-1.6.11+dfsg/public_html/.htaccess roundcube-1.6.12+dfsg/public_html/.htaccess
--- roundcube-1.6.11+dfsg/public_html/.htaccess 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/public_html/.htaccess 2025-12-14 09:10:51.000000000 +0100
@@ -55,10 +55,6 @@
# Only template - fill with your values
#Header always set Public-Key-Pins "max-age=3600; report-uri=\"\"; pin-sha256=\"\"; pin-sha256=\"\"" env=HTTPS
-# X-Xss-Protection
-# This header is used to configure the built in reflective XSS protection found in Internet Explorer, Chrome and Safari (Webkit).
-#Header set X-XSS-Protection "1; mode=block"
-
# X-Frame-Options
# The X-Frame-Options header (RFC), or XFO header, protects your visitors against clickjacking attacks
# Already set by php code! Do not activate both options
diff -Nru roundcube-1.6.11+dfsg/public_html/plugins/enigma/lib/enigma_engine.php roundcube-1.6.12+dfsg/public_html/plugins/enigma/lib/enigma_engine.php
--- roundcube-1.6.11+dfsg/public_html/plugins/enigma/lib/enigma_engine.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/public_html/plugins/enigma/lib/enigma_engine.php 2025-12-14 09:10:51.000000000 +0100
@@ -882,7 +882,7 @@
// @TODO: Handle big bodies using (temp) files
// Get rid of possible non-ascii characters (#5962)
- $sig_body = preg_replace('/[^\x00-\x7F]/', '', $sig_body);
+ $sig_body = preg_replace('/[^\x00-\x7F]/', '', (string) $sig_body);
$sig = $this->pgp_driver->verify($msg_body, $sig_body);
diff -Nru roundcube-1.6.11+dfsg/public_html/plugins/zipdownload/zipdownload.php roundcube-1.6.12+dfsg/public_html/plugins/zipdownload/zipdownload.php
--- roundcube-1.6.11+dfsg/public_html/plugins/zipdownload/zipdownload.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/public_html/plugins/zipdownload/zipdownload.php 2025-12-14 09:10:51.000000000 +0100
@@ -315,6 +315,7 @@
$zip = new ZipArchive();
$zip->open($tmpfname, ZIPARCHIVE::OVERWRITE);
+ $last_key = array_key_last($messages);
foreach ($messages as $key => $value) {
list($uid, $mbox) = explode(':', $key, 2);
$imap->set_folder($mbox);
@@ -327,7 +328,15 @@
$filter = stream_filter_append($tmpfp, 'mbox_filter');
$imap->get_raw_body($uid, $tmpfp);
stream_filter_remove($filter);
- fwrite($tmpfp, "\r\n");
+
+ // Make sure the delimiter is a double \r\n
+ $fstat = fstat($tmpfp);
+ if (stream_get_contents($tmpfp, 2, $fstat['size'] - 2) != "\r\n") {
+ fwrite($tmpfp, "\r\n");
+ }
+ if ($key != $last_key) {
+ fwrite($tmpfp, "\r\n");
+ }
}
else { // maildir
$tmpfn = rcube_utils::temp_filename('zipmessage');
diff -Nru roundcube-1.6.11+dfsg/public_html/program/js/app.js roundcube-1.6.12+dfsg/public_html/program/js/app.js
--- roundcube-1.6.11+dfsg/public_html/program/js/app.js 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/public_html/program/js/app.js 2025-12-14 09:10:51.000000000 +0100
@@ -6781,9 +6781,16 @@
.click(function() { return ref.command('listgroup', prop, this); })
.text(prop.name);
+ if (!this.env.contactgroups.length)
+ this.env.contactgroups = {}
+
this.env.contactfolders[key] = this.env.contactgroups[key] = prop;
this.treelist.insert({ id:key, html:link, classes:['contactgroup'] }, prop.source, 'contactgroup');
+ // If there was a contact selected we have to clear the list because we have outdated
+ // some commands state (e.g. group-assign-selected) as well as groups list in the contact frame
+ this.contact_list.clear_selection();
+
// make sure there is no cached address book or contact group selectors
this.destroy_entity_selector('addressbook-selector');
this.destroy_entity_selector('contactgroup-selector');
diff -Nru roundcube-1.6.11+dfsg/tests/Framework/DB.php roundcube-1.6.12+dfsg/tests/Framework/DB.php
--- roundcube-1.6.11+dfsg/tests/Framework/DB.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/tests/Framework/DB.php 2025-12-14 09:10:51.000000000 +0100
@@ -176,9 +176,7 @@
function test_parse_dsn()
{
- $dsn = "mysql://USERNAME:PASSWORD@HOST:3306/DATABASE";
-
- $result = rcube_db::parse_dsn($dsn);
+ $result = \rcube_db::parse_dsn('mysql://USERNAME:PASSWORD@HOST:3306/DATABASE');
$this->assertSame('mysql', $result['phptype']);
$this->assertSame('USERNAME', $result['username']);
@@ -187,9 +185,7 @@
$this->assertSame('HOST', $result['hostspec']);
$this->assertSame('DATABASE', $result['database']);
- $dsn = "pgsql:///DATABASE";
-
- $result = rcube_db::parse_dsn($dsn);
+ $result = \rcube_db::parse_dsn('pgsql:///DATABASE');
$this->assertSame('pgsql', $result['phptype']);
$this->assertTrue(!array_key_exists('username', $result));
@@ -197,6 +193,33 @@
$this->assertTrue(!array_key_exists('port', $result));
$this->assertTrue(!array_key_exists('hostspec', $result));
$this->assertSame('DATABASE', $result['database']);
+
+ $result = \rcube_db::parse_dsn('mysql://user:pass@[fd00:3::11]:3306/roundcubemail');
+
+ $this->assertSame('mysql', $result['phptype']);
+ $this->assertSame('user', $result['username']);
+ $this->assertSame('pass', $result['password']);
+ $this->assertSame('[fd00:3::11]', $result['hostspec']);
+ $this->assertSame('3306', $result['port']);
+ $this->assertSame('roundcubemail', $result['database']);
+
+ $result = \rcube_db::parse_dsn('mysql://user:pass@[::1]/roundcubemail');
+
+ $this->assertSame('mysql', $result['phptype']);
+ $this->assertSame('user', $result['username']);
+ $this->assertSame('pass', $result['password']);
+ $this->assertSame('[::1]', $result['hostspec']);
+ $this->assertTrue(!array_key_exists('port', $result));
+ $this->assertSame('roundcubemail', $result['database']);
+
+ $result = \rcube_db::parse_dsn('mysql://192.168.0.1:1234/roundcubemail');
+
+ $this->assertSame('mysql', $result['phptype']);
+ $this->assertSame('192.168.0.1', $result['hostspec']);
+ $this->assertSame('1234', $result['port']);
+ $this->assertTrue(!array_key_exists('username', $result));
+ $this->assertTrue(!array_key_exists('password', $result));
+ $this->assertSame('roundcubemail', $result['database']);
}
/**
diff -Nru roundcube-1.6.11+dfsg/tests/Framework/Utils.php roundcube-1.6.12+dfsg/tests/Framework/Utils.php
--- roundcube-1.6.11+dfsg/tests/Framework/Utils.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/tests/Framework/Utils.php 2025-12-14 09:10:51.000000000 +0100
@@ -291,9 +291,9 @@
$mod = rcube_utils::mod_css_styles($style, 'rcmbody', true);
$this->assertSame("#rcmbody { content: ''; color: red; }", $mod);
- $style = "body { content: '< page: ;/style>< page: ;img src onerror=\"alert(\'hello\');\">'; color: red; }";
+ $style = "body { content: '< page: ;/style>< page: ;img src onerror=\"alert(\\'hello\\');\">'; color: red; }";
$mod = rcube_utils::mod_css_styles($style, 'rcmbody', true);
- $this->assertSame("#rcmbody { content: '< page: ;/style>< page: ;img src onerror=\"alert('hello');\">'; color: red; }", $mod);
+ $this->assertSame("#rcmbody { color: red; }", $mod);
// Removing page: property
$style = "body { page: test; color: red }";
@@ -423,6 +423,10 @@
'font-family:"新細明體","serif";color:red',
[['font-family', '"新細明體","serif"'], ['color', 'red']]
],
+ [
+ 'text-align: center; ; background-color: #C83232; color: #ffffff; ; display: inline-block;',
+ [['text-align', 'center'], ['background-color', '#C83232'], ['color', '#ffffff'], ['display', 'inline-block']],
+ ],
];
}
@@ -431,7 +435,7 @@
*
* @dataProvider data_parse_css_block
*/
- function test_explode_style($input, $output)
+ function test_parse_css_block($input, $output)
{
$this->assertSame($output, rcube_utils::parse_css_block($input));
}
diff -Nru roundcube-1.6.11+dfsg/tests/Framework/Washtml.php roundcube-1.6.12+dfsg/tests/Framework/Washtml.php
--- roundcube-1.6.11+dfsg/tests/Framework/Washtml.php 2025-06-01 09:44:15.000000000 +0200
+++ roundcube-1.6.12+dfsg/tests/Framework/Washtml.php 2025-12-14 09:10:51.000000000 +0100
@@ -312,6 +312,13 @@
$washed = $washer->wash($html);
$this->assertTrue(strpos($washed, $exp) !== false, "Style quotes XSS issue (#1490227)");
+
+ $html = '<div style=\'content: "\0026quot;; background: url(//http.cat/418); content:""; width: 100%; height: 100%;\'>test</div>';
+
+ $washer = new \rcube_washtml();
+ $washed = $washer->wash($html);
+
+ $this->assertTrue(strpos($washed, '<div x-washed="style">test</div>') !== false);
}
/**
@@ -362,7 +369,7 @@
<!-- foreignObject ignored -->
<set attributeName="onmouseover" x-washed="to" />
<animate attributeName="onunload" x-washed="to" />
- <animate attributeName="xlink:href" begin="0" x-washed="from" />
+ <!-- animate blocked -->
</svg>';
$washer = new rcube_washtml;
@@ -432,6 +439,14 @@
'<svg><!-- set blocked --><a id="xss"><text x="20" y="20">XSS</text></a></svg>',
],
[
+ '<svg><a class="a"><animate attributeName="xlink:href" values="javascript:alert(1)" /></a></svg>',
+ '<svg><a class="a"><!-- animate blocked --></a></svg>',
+ ],
+ [
+ '<title><html><head><meta><body></title><svg><a class="a"><animate attributeName="xlink:href" values="javascript:alert(1)" /></a></svg>',
+ '<svg><a class="a"><!-- animate blocked --></a></svg>',
+ ],
+ [
'<svg><animate xlink:href="#xss" attributename="href" dur="5s" repeatCount="indefinite" keytimes="0;0;1" values="https://portswigger.net?;javascript:alert(1);0" />'
. '<a id="xss"><text x="20" y="20">XSS</text></a></svg>',
'<svg><!-- animate blocked --><a id="xss"><text x="20" y="20">XSS</text></a></svg>',
-------------- next part --------------
diffstat for roundcube-1.6.5+dfsg roundcube-1.6.5+dfsg
changelog | 12 +++++
patches/CVE-2025-68460.patch | 64 ++++++++++++++++++++++++++++++
patches/CVE-2025-68461.patch | 91 +++++++++++++++++++++++++++++++++++++++++++
patches/series | 2
4 files changed, 168 insertions(+), 1 deletion(-)
diff -Nru roundcube-1.6.5+dfsg/debian/changelog roundcube-1.6.5+dfsg/debian/changelog
--- roundcube-1.6.5+dfsg/debian/changelog 2025-06-02 10:01:44.000000000 +0200
+++ roundcube-1.6.5+dfsg/debian/changelog 2025-12-16 09:10:17.000000000 +0100
@@ -1,8 +1,18 @@
+roundcube (1.6.5+dfsg-1+deb12u6) bookworm-security; urgency=high
+
+ * Cherry pick upstream security fixes from v1.6.12 (closes: #1122899):
+ + Fix CVE-2025-68461: Cross-Site-Scripting vulnerability via SVG's animate
+ tag.
+ + Fix CVE-2025-68460: Information Disclosure vulnerability in the HTML
+ style sanitizer.
+
+ -- Guilhem Moulin <guilhem at debian.org> Tue, 16 Dec 2025 09:10:17 +0100
+
roundcube (1.6.5+dfsg-1+deb12u5) bookworm-security; urgency=high
* Fix CVE-2025-49113: Post-Auth RCE via PHP Object Deserialization.
(Closes: #1107073)
- * Regression fix: CVE-2024-42009.patch from 1.6.5+dfsg-1+deb12u3 and
+ * Regression fix: CVE-2024-42010.patch from 1.6.5+dfsg-1+deb12u3 and
1.6.5+dfsg-1+deb12u4 caused some HTML messages to be displayed unstyled.
-- Guilhem Moulin <guilhem at debian.org> Mon, 02 Jun 2025 10:01:44 +0200
diff -Nru roundcube-1.6.5+dfsg/debian/patches/CVE-2025-68460.patch roundcube-1.6.5+dfsg/debian/patches/CVE-2025-68460.patch
--- roundcube-1.6.5+dfsg/debian/patches/CVE-2025-68460.patch 1970-01-01 01:00:00.000000000 +0100
+++ roundcube-1.6.5+dfsg/debian/patches/CVE-2025-68460.patch 2025-12-16 09:10:17.000000000 +0100
@@ -0,0 +1,64 @@
+From: Aleksander Machniak <alec at alec.pl>
+Date: Sun, 14 Dec 2025 09:02:25 +0100
+Subject: Fix Information Disclosure vulnerability in the HTML style sanitizer
+
+reported by somerandomdev
+
+Origin: https://github.com/roundcube/roundcubemail/commit/08de250fba731b634bed188bbe18d2f6ef3c7571
+Bug: https://roundcube.net/news/2025/12/13/security-updates-1.6.12-and-1.5.12
+Bug-Debian: https://bugs.debian.org/1122899
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-68460
+---
+ program/lib/Roundcube/rcube_utils.php | 3 +++
+ tests/Framework/Utils.php | 4 ++--
+ tests/Framework/Washtml.php | 7 +++++++
+ 3 files changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php
+index b5f8606..1110905 100644
+--- a/program/lib/Roundcube/rcube_utils.php
++++ b/program/lib/Roundcube/rcube_utils.php
+@@ -559,6 +559,9 @@ class rcube_utils
+ $value .= ' url(' . $url . ')';
+ }
+ }
++ } elseif (preg_match('/;.*/', $val)) {
++ // Invalid or evil content, ignore
++ continue;
+ } else {
+ // whitelist ?
+ $value .= ' ' . $val;
+diff --git a/tests/Framework/Utils.php b/tests/Framework/Utils.php
+index 019895b..4b43758 100644
+--- a/tests/Framework/Utils.php
++++ b/tests/Framework/Utils.php
+@@ -291,9 +291,9 @@ class Framework_Utils extends PHPUnit\Framework\TestCase
+ $mod = rcube_utils::mod_css_styles($style, 'rcmbody', true);
+ $this->assertSame("#rcmbody { content: ''; color: red; }", $mod);
+
+- $style = "body { content: '< page: ;/style>< page: ;img src onerror=\"alert(\'hello\');\">'; color: red; }";
++ $style = "body { content: '< page: ;/style>< page: ;img src onerror=\"alert(\\'hello\\');\">'; color: red; }";
+ $mod = rcube_utils::mod_css_styles($style, 'rcmbody', true);
+- $this->assertSame("#rcmbody { content: '< page: ;/style>< page: ;img src onerror=\"alert('hello');\">'; color: red; }", $mod);
++ $this->assertSame("#rcmbody { color: red; }", $mod);
+
+ // Removing page: property
+ $style = "body { page: test; color: red }";
+diff --git a/tests/Framework/Washtml.php b/tests/Framework/Washtml.php
+index ace4716..0b9e1e9 100644
+--- a/tests/Framework/Washtml.php
++++ b/tests/Framework/Washtml.php
+@@ -312,6 +312,13 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+ $washed = $washer->wash($html);
+
+ $this->assertTrue(strpos($washed, $exp) !== false, "Style quotes XSS issue (#1490227)");
++
++ $html = '<div style=\'content: "\0026quot;; background: url(//http.cat/418); content:""; width: 100%; height: 100%;\'>test</div>';
++
++ $washer = new \rcube_washtml();
++ $washed = $washer->wash($html);
++
++ $this->assertTrue(strpos($washed, '<div x-washed="style">test</div>') !== false);
+ }
+
+ /**
diff -Nru roundcube-1.6.5+dfsg/debian/patches/CVE-2025-68461.patch roundcube-1.6.5+dfsg/debian/patches/CVE-2025-68461.patch
--- roundcube-1.6.5+dfsg/debian/patches/CVE-2025-68461.patch 1970-01-01 01:00:00.000000000 +0100
+++ roundcube-1.6.5+dfsg/debian/patches/CVE-2025-68461.patch 2025-12-16 09:10:17.000000000 +0100
@@ -0,0 +1,91 @@
+From: Aleksander Machniak <alec at alec.pl>
+Date: Sun, 14 Dec 2025 09:01:26 +0100
+Subject: Fix Cross-Site-Scripting vulnerability via SVG's animate tag
+
+reported by Valentin T., CrowdStrike
+
+Origin: https://github.com/roundcube/roundcubemail/commit/bfa032631c36b900e7444dfa278340b33cbf7cdb
+Bug: https://roundcube.net/news/2025/12/13/security-updates-1.6.12-and-1.5.12
+Bug-Debian: https://bugs.debian.org/1122899
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-68461
+---
+ program/lib/Roundcube/rcube_washtml.php | 13 +++++++++----
+ tests/Framework/Washtml.php | 10 +++++++++-
+ 2 files changed, 18 insertions(+), 5 deletions(-)
+
+diff --git a/program/lib/Roundcube/rcube_washtml.php b/program/lib/Roundcube/rcube_washtml.php
+index 281d369..85972f0 100644
+--- a/program/lib/Roundcube/rcube_washtml.php
++++ b/program/lib/Roundcube/rcube_washtml.php
+@@ -303,7 +303,8 @@ class rcube_washtml
+
+ // in SVG to/from attribs may contain anything, including URIs
+ if ($key == 'to' || $key == 'from') {
+- $key = strtolower($node->getAttribute('attributeName'));
++ $key = strtolower((string) $node->getAttribute('attributeName'));
++ $key = trim(preg_replace('/^.*:/', '', $key));
+ if ($key && !isset($this->_html_attribs[$key])) {
+ $key = null;
+ }
+@@ -512,10 +513,14 @@ class rcube_washtml
+ private static function attribute_value($node, $attr_name, $attr_value)
+ {
+ $attr_name = strtolower($attr_name);
++ $attr_value = strtolower($attr_value);
+
+ foreach ($node->attributes as $name => $attr) {
+ if (strtolower($name) === $attr_name) {
+- if (strtolower($attr_value) === strtolower(trim($attr->nodeValue))) {
++ // Read the attribute name, remove the namespace (e.g. xlink:href => href)
++ $val = strtolower(trim($attr->nodeValue));
++ $val = trim(preg_replace('/^.*:/', '', $val));
++ if ($attr_value === $val) {
+ return true;
+ }
+ }
+@@ -734,6 +739,7 @@ class rcube_washtml
+ // space(s) between <NOBR>
+ '/(<\/nobr>)(\s+)(<nobr>)/i',
+ // PHP bug #32547 workaround: remove title tag
++ // TODO: This is an old libxml2 bug, maybe we could drop this at some point
+ '/<title[^>]*>.*<\/title>/iU',
+ // remove <!doctype> before BOM (#1490291)
+ '/<\!doctype[^>]+>[^<]*/im',
+@@ -741,8 +747,7 @@ class rcube_washtml
+ '/^(\0\0\xFE\xFF|\xFF\xFE\0\0|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/',
+ // washtml/DOMDocument cannot handle xml namespaces
+ '/<html\s[^>]+>/i',
+- // washtml/DOMDocument cannot handle xml namespaces
+- // HTML5 parser cannot handler <?xml
++ // HTML5 parser cannot handle <?xml
+ '/<\?xml[^>]*>/i',
+ ];
+
+diff --git a/tests/Framework/Washtml.php b/tests/Framework/Washtml.php
+index 4fdae1a..ace4716 100644
+--- a/tests/Framework/Washtml.php
++++ b/tests/Framework/Washtml.php
+@@ -362,7 +362,7 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+ <!-- foreignObject ignored -->
+ <set attributeName="onmouseover" x-washed="to" />
+ <animate attributeName="onunload" x-washed="to" />
+- <animate attributeName="xlink:href" begin="0" x-washed="from" />
++ <!-- animate blocked -->
+ </svg>';
+
+ $washer = new rcube_washtml;
+@@ -431,6 +431,14 @@ class Framework_Washtml extends PHPUnit\Framework\TestCase
+ . '<a id="xss"><text x="20" y="20">XSS</text></a></svg>',
+ '<svg><!-- set blocked --><a id="xss"><text x="20" y="20">XSS</text></a></svg>',
+ ],
++ [
++ '<svg><a class="a"><animate attributeName="xlink:href" values="javascript:alert(1)" /></a></svg>',
++ '<svg><a class="a"><!-- animate blocked --></a></svg>',
++ ],
++ [
++ '<title><html><head><meta><body></title><svg><a class="a"><animate attributeName="xlink:href" values="javascript:alert(1)" /></a></svg>',
++ '<svg><a class="a"><!-- animate blocked --></a></svg>',
++ ],
+ [
+ '<svg><animate xlink:href="#xss" attributename="href" dur="5s" repeatCount="indefinite" keytimes="0;0;1" values="https://portswigger.net?;javascript:alert(1);0" />'
+ . '<a id="xss"><text x="20" y="20">XSS</text></a></svg>',
diff -Nru roundcube-1.6.5+dfsg/debian/patches/series roundcube-1.6.5+dfsg/debian/patches/series
--- roundcube-1.6.5+dfsg/debian/patches/series 2025-06-02 10:01:44.000000000 +0200
+++ roundcube-1.6.5+dfsg/debian/patches/series 2025-12-16 09:10:17.000000000 +0100
@@ -28,3 +28,5 @@
CVE-2024-42010.patch
Fix-regression-where-HTML-messages-were-displayed-unstyle.patch
CVE-2025-49113.patch
+CVE-2025-68461.patch
+CVE-2025-68460.patch
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://alioth-lists.debian.net/pipermail/pkg-roundcube-maintainers/attachments/20251218/e8f25ff3/attachment-0001.sig>
More information about the Pkg-roundcube-maintainers
mailing list