Version in base suite: 5.12.1-3+deb13u1 Base version: sogo_5.12.1-3+deb13u1 Target version: sogo_5.12.1-3+deb13u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/s/sogo/sogo_5.12.1-3+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/s/sogo/sogo_5.12.1-3+deb13u2.dsc changelog | 40 +++ patches/CVE-2025-71276.patch | 64 +++++ patches/CVE-2026-3054.patch | 51 ++++ patches/CVE-2026-33550.patch | 251 ++++++++++++++++++++++ patches/CVE-2026-46445_CVE-2026-46446.patch | 176 +++++++++++++++ patches/CVE-2026-8496.patch | 87 +++++++ patches/CVE-2026-8496_regression_fix.patch | 64 +++++ patches/CVE-2026-8851_1.patch | 207 ++++++++++++++++++ patches/CVE-2026-8851_2.patch | 37 +++ patches/fix_message_rendering_1.patch | 82 +++++++ patches/fix_message_rendering_2.patch | 29 ++ patches/fix_message_rendering_3.patch | 22 + patches/fix_openid_validation.patch | 118 ++++++++++ patches/fix_xss_message_subject_rendering_1.patch | 22 + patches/fix_xss_message_subject_rendering_2.patch | 72 ++++++ patches/git_clean_import_event.patch | 26 ++ patches/series | 15 + 17 files changed, 1363 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpzq4viqv7/sogo_5.12.1-3+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpzq4viqv7/sogo_5.12.1-3+deb13u2.dsc: no acceptable signature found diff -Nru sogo-5.12.1/debian/changelog sogo-5.12.1/debian/changelog --- sogo-5.12.1/debian/changelog 2025-12-31 10:33:39.000000000 +0000 +++ sogo-5.12.1/debian/changelog 2026-06-15 19:26:37.000000000 +0000 @@ -1,3 +1,43 @@ +sogo (5.12.1-3+deb13u2) trixie-security; urgency=medium + + * Non-maintainer upload. + + [ Peter Wienemann ] + * Add patch to fix CVE-2026-46445 and CVE-2026-46446: + - CVE-2026-46445: SQL injection vulnerability when at least one user + source is a PostgreSQL database + - CVE-2026-46446: SQL injection vulnerability when at least one user + source is an SQL database (MariaDB or PostgreSQL) and passwords are + stored in plain text + * Add patch to fix CVE-2025-71276: (Closes: #1131605) + XSS with events, tasks and contacts categories + * Add patch to fix CVE-2026-3054: (Closes: #1130878) + XSS via manipulation of the argument hint + * Add patch to fix CVE-2026-33550: (Closes: #1131606) + TOTP vulnerabilities: + - If a user disables/enables it, it is not renewed. + - Length is too short (12 rather than recommended 20). + * Add patch to fix CVE-2026-8496: + A maliciously crafted ICS calendar invitation file allows arbitrary + JavaScript execution within the authenticated SOGo webmail session. + * Add patch to fix a regression introduced by fix for CVE-2026-8496 + * Add patch to fix CVE-2026-8851: + SQL injection vulnerability in the access control list + management functionality that allows authenticated users to extract + arbitrary data from the database by injecting SQL subqueries through + the uid parameter of the addUserInAcls endpoint. + * Add patch to fix folder path in fix for CVE-2026-8851 + * Add patch to fix openid validation: + Verify that the returned email domain is authorized and that the + user exists in the local source. + * Add two patches to fix XSS in message subject rendering + * Add three patches to fix message rendering + + [ Jordi Mallach ] + * Add upstream patch to fix impersonation issues when importing events. + + -- Peter Wienemann Mon, 15 Jun 2026 21:26:37 +0200 + sogo (5.12.1-3+deb13u1) trixie; urgency=high * Non-maintainer upload by the Security Team. diff -Nru sogo-5.12.1/debian/patches/CVE-2025-71276.patch sogo-5.12.1/debian/patches/CVE-2025-71276.patch --- sogo-5.12.1/debian/patches/CVE-2025-71276.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/CVE-2025-71276.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,64 @@ +From: Hivert Quentin +Date: Tue, 16 Dec 2025 10:25:49 +0100 +Subject: fix(vulnerability): prevent xss with events, tasks and contacts categories + +Origin: upstream, https://github.com/Alinto/sogo/commit/e9b3f2a43d7557e8416f6749df4ab4f9128af2d1.diff +--- + UI/Contacts/UIxContactEditor.m | 2 +- + UI/Contacts/UIxListEditor.m | 2 +- + UI/Scheduler/UIxAppointmentEditor.m | 2 +- + UI/Scheduler/UIxTaskEditor.m | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/UI/Contacts/UIxContactEditor.m b/UI/Contacts/UIxContactEditor.m +index e01475d..a4d5f62 100644 +--- a/UI/Contacts/UIxContactEditor.m ++++ b/UI/Contacts/UIxContactEditor.m +@@ -485,7 +485,7 @@ static Class SOGoContactGCSEntryK = Nil; + co = [self clientObject]; + card = [co vCard]; + request = [context request]; +- params = [[request contentAsString] objectFromJSONString]; ++ params = [[[request contentAsString] stringWithoutHTMLInjection: YES] objectFromJSONString]; + forceSave = [[params objectForKey: @"ignoreDuplicate"] boolValue]; + + [self setAttributes: params]; +diff --git a/UI/Contacts/UIxListEditor.m b/UI/Contacts/UIxListEditor.m +index 9e9c673..477714c 100644 +--- a/UI/Contacts/UIxListEditor.m ++++ b/UI/Contacts/UIxListEditor.m +@@ -339,7 +339,7 @@ + [list retain]; + + request = [context request]; +- params = [[request contentAsString] objectFromJSONString]; ++ params = [[[request contentAsString] stringWithoutHTMLInjection: YES] objectFromJSONString]; + + o = [params objectForKey: @"refs"]; + if (![o isKindOfClass: [NSArray class]]) +diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m +index 5ef8e8e..27b94ef 100644 +--- a/UI/Scheduler/UIxAppointmentEditor.m ++++ b/UI/Scheduler/UIxAppointmentEditor.m +@@ -556,7 +556,7 @@ + + ex = nil; + request = [context request]; +- params = [[request contentAsString] objectFromJSONString]; ++ params = [[[request contentAsString] stringWithoutHTMLInjection: NO] objectFromJSONString]; + if (params == nil) + { + ex = [NSException exceptionWithName: @"JSONParsingException" +diff --git a/UI/Scheduler/UIxTaskEditor.m b/UI/Scheduler/UIxTaskEditor.m +index ad86e5c..8f2e136 100644 +--- a/UI/Scheduler/UIxTaskEditor.m ++++ b/UI/Scheduler/UIxTaskEditor.m +@@ -335,7 +335,7 @@ + + ex = nil; + request = [context request]; +- params = [[request contentAsString] objectFromJSONString]; ++ params = [[[request contentAsString] stringWithoutHTMLInjection: NO] objectFromJSONString]; + if (params == nil) + { + ex = [NSException exceptionWithName: @"JSONParsingException" diff -Nru sogo-5.12.1/debian/patches/CVE-2026-3054.patch sogo-5.12.1/debian/patches/CVE-2026-3054.patch --- sogo-5.12.1/debian/patches/CVE-2026-3054.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/CVE-2026-3054.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,51 @@ +From: Hivert Quentin +Date: Tue, 24 Feb 2026 17:06:04 +0100 +Subject: fix(vulnerability): prevent javascript njection with hint query + +Origin: upstream, https://github.com/Alinto/sogo/commit/e821b20f87d1a9757f1d0aff7d1e31703f97054b.diff +--- + UI/MainUI/SOGoRootPage.m | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/UI/MainUI/SOGoRootPage.m b/UI/MainUI/SOGoRootPage.m +index 79533e4..ff24f44 100644 +--- a/UI/MainUI/SOGoRootPage.m ++++ b/UI/MainUI/SOGoRootPage.m +@@ -1016,12 +1016,14 @@ static const NSString *kJwtKey = @"jwt"; + { + id value; + WORequest *rq; +- NSString* login; ++ NSString* login, *loginClean; + NSDictionary *formValues; + + login = @""; + + rq = [context request]; ++ ++ + if((formValues=[rq formValues]) && (value=[formValues objectForKey: @"hint"])) + { + if ([value isKindOfClass: [NSArray class]]) +@@ -1029,7 +1031,20 @@ static const NSString *kJwtKey = @"jwt"; + else + login = value; + } +- return login; ++ ++ //Check common injection ++ loginClean = [login stringWithoutHTMLInjection: YES]; ++ if(![loginClean isEqualToString: login]) ++ { ++ loginClean = @""; ++ } ++ //Check single quote to inject javascript ++ if ([loginClean rangeOfString:@"'"].location !=NSNotFound) ++ { ++ loginClean = @""; ++ } ++ ++ return loginClean; + } + + - (BOOL) hasPasswordRecovery diff -Nru sogo-5.12.1/debian/patches/CVE-2026-33550.patch sogo-5.12.1/debian/patches/CVE-2026-33550.patch --- sogo-5.12.1/debian/patches/CVE-2026-33550.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/CVE-2026-33550.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,251 @@ +From: Hivert Quentin +Date: Wed, 25 Feb 2026 15:23:57 +0100 +Subject: fix(vulnerability): properly change the totp code after disabling it + +Origin: upstream, https://github.com/Alinto/sogo/commit/83d4c522f87cfde0ba543837d9b24c3479083ec2.diff +--- + SoObjects/SOGo/SOGoUser.h | 3 ++- + SoObjects/SOGo/SOGoUser.m | 47 +++++++++++++++++++++++++++++++- + SoObjects/SOGo/SOGoUserSettings.h | 2 ++ + SoObjects/SOGo/SOGoUserSettings.m | 36 +++++++++++++++++++++++++ + UI/MainUI/SOGoRootPage.m | 57 ++++++++++++++++++++++++++++++++++----- + UI/PreferencesUI/UIxPreferences.m | 4 +-- + 6 files changed, 138 insertions(+), 11 deletions(-) + +diff --git a/SoObjects/SOGo/SOGoUser.h b/SoObjects/SOGo/SOGoUser.h +index 7cb85ef..927a482 100644 +--- a/SoObjects/SOGo/SOGoUser.h ++++ b/SoObjects/SOGo/SOGoUser.h +@@ -124,7 +124,8 @@ + + - (BOOL) isSuperUser; + - (BOOL) canAuthenticate; +-- (NSString *) totpKey; ++- (NSString *) totpKey: (bool) isCheck; ++- (NSString *) oldtotpKey; + + /* resource */ + - (BOOL) isResource; +diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m +index 80255d6..62a5418 100644 +--- a/SoObjects/SOGo/SOGoUser.m ++++ b/SoObjects/SOGo/SOGoUser.m +@@ -1292,7 +1292,7 @@ static const NSString *kEncryptedUserNamePrefix = @"uenc"; + return [authValue boolValue]; + } + +-- (NSString *) totpKey ++- (NSString *) totpKey: (bool) isCheck + { + #if defined(MFA_CONFIG) + NSString *key, *result; +@@ -1301,6 +1301,51 @@ static const NSString *kEncryptedUserNamePrefix = @"uenc"; + + size_t s_len, secret_len; + ++ //Until 5.12.4, SOGo had two problems with totp: ++ // * It was not renew after a user disable it/renable it. ++ // * The length was too small: 12 instead of the recommanded 20 ++ ++ if(![_defaults totpEnabled]) ++ { ++ //Totp was not enabled ++ //Only renew if this is not a check (happen when the user enable it for the first time and save its preferences ++ //the saveAction will check the totp code but [_defaults totpEnabled] is still False ) ++ key = [[self userSettings] userCurrentTotpKey: !isCheck]; ++ } ++ else ++ { ++ //Totp currently enabled ++ key = [[self userSettings] userCurrentTotpKey: NO]; ++ } ++ ++ s = [key UTF8String]; ++ s_len = strlen(s); ++ ++ oath_init(); ++ oath_base32_encode(s,s_len, &secret, &secret_len); ++ oath_done(); ++ ++ result = [[NSString alloc] initWithBytesNoCopy: secret ++ length: secret_len ++ encoding: NSASCIIStringEncoding ++ freeWhenDone: YES]; ++ ++ return [result autorelease]; ++#else ++ return nil; ++#endif ++} ++ ++- (NSString *) oldtotpKey ++{ ++#if defined(MFA_CONFIG) ++ //Was used before 5.12.5, is to not make obsolete totp profile set before ++ NSString *key, *result; ++ const char *s; ++ char *secret; ++ ++ size_t s_len, secret_len; ++ + key = [[[self userSettings] userPrivateSalt] substringToIndex: 12]; + s = [key UTF8String]; + s_len = strlen(s); +diff --git a/SoObjects/SOGo/SOGoUserSettings.h b/SoObjects/SOGo/SOGoUserSettings.h +index 2809439..749b2f7 100644 +--- a/SoObjects/SOGo/SOGoUserSettings.h ++++ b/SoObjects/SOGo/SOGoUserSettings.h +@@ -35,6 +35,8 @@ + - (NSArray *) subscribedCalendars; + - (NSArray *) subscribedAddressBooks; + - (NSString *) userPrivateSalt; ++- (NSString *) userCurrentTotpKey: (bool) renew; ++- (void) setTotpKey: (NSString* ) newKey; + - (NSString *) userPublicSalt; + - (void)enableForceResetPassword; + - (void)disableForceResetPassword; +diff --git a/SoObjects/SOGo/SOGoUserSettings.m b/SoObjects/SOGo/SOGoUserSettings.m +index f4f6d58..c735067 100644 +--- a/SoObjects/SOGo/SOGoUserSettings.m ++++ b/SoObjects/SOGo/SOGoUserSettings.m +@@ -116,6 +116,42 @@ static Class SOGoUserProfileKlass = Nil; + return salt; + } + ++- (NSString *) userCurrentTotpKey: (bool) renew ++{ ++ NSMutableDictionary *values; ++ NSString *key; ++ ++ key = [[self dictionaryForKey: @"General"] objectForKey: @"totpKey"]; ++ ++ if (!key || renew) ++ { ++ key = [[[[NSProcessInfo processInfo] globallyUniqueString] asSHA1String] substringToIndex: 20]; ++ values = [self objectForKey: @"General"]; ++ ++ if (!values) ++ values = [NSMutableDictionary dictionary]; ++ ++ [values setObject: key forKey: @"totpKey"]; ++ [self setObject: values forKey: @"General"]; ++ [self synchronize]; ++ } ++ ++ return key; ++} ++ ++- (void) setTotpKey: (NSString* ) newKey ++{ ++ NSMutableDictionary *values; ++ values = [self objectForKey: @"General"]; ++ ++ if (!values) ++ values = [NSMutableDictionary dictionary]; ++ ++ [values setObject: newKey forKey: @"totpKey"]; ++ [self setObject: values forKey: @"General"]; ++ [self synchronize]; ++} ++ + - (void) enableForceResetPassword + { + [self setObject: [NSNumber numberWithInt:1] forKey: @"ForceResetPassword"]; +diff --git a/UI/MainUI/SOGoRootPage.m b/UI/MainUI/SOGoRootPage.m +index ff24f44..c5cde4a 100644 +--- a/UI/MainUI/SOGoRootPage.m ++++ b/UI/MainUI/SOGoRootPage.m +@@ -338,7 +338,7 @@ static const NSString *kJwtKey = @"jwt"; + const auto time_step = OATH_TOTP_DEFAULT_TIME_STEP_SIZE; + const auto digits = 6; + +- real_secret = [[loggedInUser totpKey] UTF8String]; ++ real_secret = [[loggedInUser totpKey: YES] UTF8String]; + + auto result = oath_init(); + auto t = time(NULL); +@@ -366,13 +366,56 @@ static const NSString *kJwtKey = @"jwt"; + + if (code != [verificationCode unsignedIntValue]) + { +- [self logWithFormat: @"Invalid TOTP key for '%@'", username]; +- [json setObject: [NSNumber numberWithInt: 1] +- forKey: @"totpInvalidKey"]; +- return [self responseWithStatus: 403 +- andJSONRepresentation: json]; ++ //With 5.12.5, the totpKey has changed (non longer from salt but from a propoer totpkey parameter) ++ //To avoid making all old totp configuration obsolete, we're trying the verification code with ++ //the old method first ++ unsigned int old_code; ++ const char *old_real_secret; ++ char *old_secret; ++ ++ size_t old_secret_len; ++ ++ const auto old_time_step = OATH_TOTP_DEFAULT_TIME_STEP_SIZE; ++ const auto old_digits = 6; ++ ++ old_real_secret = [[loggedInUser oldtotpKey] UTF8String]; ++ ++ auto old_result = oath_init(); ++ auto old_time = time(NULL); ++ auto old_left = old_time_step - (old_time % old_time_step); ++ ++ char old_otp[old_digits + 1]; ++ ++ oath_base32_decode (old_real_secret, ++ strlen(old_real_secret), ++ &old_secret, &old_secret_len); ++ ++ old_result = oath_totp_generate2(old_secret, ++ old_secret_len, ++ old_time, ++ old_time_step, ++ OATH_TOTP_DEFAULT_START_TIME, ++ old_digits, ++ 0, ++ old_otp); ++ ++ sscanf(old_otp, "%u", &old_code); ++ ++ oath_done(); ++ free(old_secret); ++ ++ if (old_code != [verificationCode unsignedIntValue]) ++ { ++ [self logWithFormat: @"Invalid TOTP key for '%@'", username]; ++ [json setObject: [NSNumber numberWithInt: 1] forKey: @"totpInvalidKey"]; ++ return [self responseWithStatus: 403 andJSONRepresentation: json]; ++ } ++ else { ++ //Move the old secret to the new parameter ++ [us setTotpKey: [[us userPrivateSalt] substringToIndex: 12]]; ++ } + } +- } // if ([verificationCode length] == 6 && [verificationCode unsignedIntValue] > 0) ++ } + else + { + if ([us dictionaryForKey: @"General"] && ![[us dictionaryForKey: @"General"] objectForKey: @"PrivateSalt"]) +diff --git a/UI/PreferencesUI/UIxPreferences.m b/UI/PreferencesUI/UIxPreferences.m +index 9e2e66b..c8fae80 100644 +--- a/UI/PreferencesUI/UIxPreferences.m ++++ b/UI/PreferencesUI/UIxPreferences.m +@@ -1123,7 +1123,7 @@ static NSArray *reminderValues = nil; + + - (NSString *) totpKey + { +- return [[context activeUser] totpKey]; ++ return [[context activeUser] totpKey: NO]; + } + + // +@@ -1910,7 +1910,7 @@ static NSArray *reminderValues = nil; + const auto time_step = OATH_TOTP_DEFAULT_TIME_STEP_SIZE; + const auto digits = 6; + +- real_secret = [[user totpKey] UTF8String]; ++ real_secret = [[user totpKey: YES] UTF8String]; + + auto result = oath_init(); + auto t = time(NULL); diff -Nru sogo-5.12.1/debian/patches/CVE-2026-46445_CVE-2026-46446.patch sogo-5.12.1/debian/patches/CVE-2026-46445_CVE-2026-46446.patch --- sogo-5.12.1/debian/patches/CVE-2026-46445_CVE-2026-46446.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/CVE-2026-46445_CVE-2026-46446.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,176 @@ +From: Hivert Quentin +Date: Tue, 24 Mar 2026 15:26:37 +0100 +Subject: fix(sql): use proper sql adaptor for usr source + +Origin: upstream, https://github.com/Alinto/sogo/commit/1f7e5d2b2c2047c44a6a9e05f73c36491cb96d21.diff +--- + SoObjects/SOGo/SQLSource.m | 70 ++++++++++++++++++++++++++++++++-------------- + 1 file changed, 49 insertions(+), 21 deletions(-) + +diff --git a/SoObjects/SOGo/SQLSource.m b/SoObjects/SOGo/SQLSource.m +index 93e8a81..2a4a950 100644 +--- a/SoObjects/SOGo/SQLSource.m ++++ b/SoObjects/SOGo/SQLSource.m +@@ -225,9 +225,16 @@ + */ + - (NSString *) _encryptPassword: (NSString *) plainPassword + { +- NSString *pass; ++ NSString *pass, *passwordScheme; + NSString* result; + ++ // if ([_userPasswordAlgorithm caseInsensitiveCompare: @"none"] == NSOrderedSame || ++ // [_userPasswordAlgorithm caseInsensitiveCompare: @"plain"] == NSOrderedSame || ++ // [_userPasswordAlgorithm caseInsensitiveCompare: @"cleartext"] == NSOrderedSame) ++ // { ++ // pass = [pass stringByReplacingString: @"'" withString: @"''"]; ++ // } ++ + pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm + keyPath: _keyPath]; + +@@ -272,6 +279,7 @@ + grace: (int *) _grace + disablepasswordPolicyCheck: (BOOL) _disablepasswordPolicyCheck + { ++ EOAdaptor *adaptor; + EOAdaptorChannel *channel; + EOQualifier *qualifier; + GCSChannelManager *cm; +@@ -281,11 +289,13 @@ + + rc = NO; + +- _login = [_login stringByReplacingString: @"'" withString: @"''"]; + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: _viewURL]; + if (channel) + { ++ EOAdaptorContext *adaptorCtx; ++ adaptorCtx = [channel adaptorContext]; ++ adaptor = [adaptorCtx adaptor]; + if (_loginFields) + { + NSMutableArray *qualifiers; +@@ -324,7 +334,8 @@ + nil]; + [qualifier autorelease]; + } +- [qualifier appendSQLToString: sql]; ++ [qualifier appendSQLToString: sql ++ withAdaptor: adaptor]; + + ex = [channel evaluateExpressionX: sql]; + if (!ex) +@@ -430,9 +441,11 @@ + { + BOOL didChange, isOldPwdOk, isPolicyOk; + EOAdaptorChannel *channel; ++ EOAdaptor *adaptor; ++ EOQualifier *qualifier_login, *qualifier_pwd; + GCSChannelManager *cm; + NSException *ex; +- NSString *sqlstr; ++ NSMutableString *sqlstr; + + *perr = -1; + isOldPwdOk = NO; +@@ -455,16 +468,28 @@ + return NO; + + // Save new password +- login = [login stringByReplacingString: @"'" withString: @"''"]; ++ // login = [login stringByReplacingString: @"'" withString: @"''"]; + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: _viewURL]; + if (channel) + { +- sqlstr = [NSString stringWithFormat: (@"UPDATE %@" +- @" SET c_password = '%@'" +- @" WHERE c_uid = '%@'"), +- [_viewURL gcsTableName], encryptedPassword, login]; +- ++ EOAdaptorContext *adaptorCtx; ++ adaptorCtx = [channel adaptorContext]; ++ adaptor = [adaptorCtx adaptor]; ++ sqlstr = [NSMutableString stringWithFormat: @"UPDATE %@ SET ", ++ [_viewURL gcsTableName]]; ++ ++ qualifier_pwd = [[EOKeyValueQualifier alloc] initWithKey: @"c_password" ++ operatorSelector: EOQualifierOperatorEqual ++ value: encryptedPassword]; ++ [qualifier_pwd appendSQLToString: sqlstr ++ withAdaptor: adaptor]; ++ [sqlstr appendString: @" WHERE "]; ++ qualifier_login = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid" ++ operatorSelector: EOQualifierOperatorEqual ++ value: login]; ++ [qualifier_login appendSQLToString: sqlstr ++ withAdaptor: adaptor]; + ex = [channel evaluateExpressionX: sqlstr]; + if (!ex) + { +@@ -998,7 +1023,9 @@ + inDomain: (NSString *)domain + limit: (int)limit + { ++ EOAdaptor *adaptor; + EOAdaptorChannel *channel; ++ EOQualifier *qualifier; + NSEnumerator *criteriaList; + NSMutableArray *fields, *results; + GCSChannelManager *cm; +@@ -1014,12 +1041,14 @@ + channel = [cm acquireOpenChannelForURL: _viewURL]; + if (channel) + { ++ EOAdaptorContext *adaptorCtx; ++ adaptorCtx = [channel adaptorContext]; ++ adaptor = [adaptorCtx adaptor]; + fields = [NSMutableArray array]; + if ([filter length]) + { +- lowerFilter = [filter lowercaseString]; +- lowerFilter = [lowerFilter asSafeSQLLikeString]; +- filterFormat = [NSString stringWithFormat: @"LOWER(%%@) LIKE '%%%%%@%%%%'", lowerFilter]; ++ filter = [[filter asSafeSQLString] stringByReplacingString: @"\%" withString: @"%%"]; ++ filterFormat = [NSString stringWithFormat: @"(%%@ isCaseInsensitiveLike: '*%@*')", filter]; + if (criteria) + criteriaList = [criteria objectEnumerator]; + else +@@ -1044,7 +1073,9 @@ + if ([fields count]) + { + qs = [[[fields uniqueObjects] stringsWithFormat: filterFormat] componentsJoinedByString: @" OR "]; +- [sql appendString: qs]; ++ qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; ++ [qualifier appendSQLToString: sql ++ withAdaptor: adaptor]; + } + else + [sql appendString: @"1 = 1"]; +@@ -1108,7 +1139,7 @@ + andSortOrdering: (EOSortOrdering *) ordering + inDomain: (NSString *) domain + { +- static EOAdaptor *adaptor = nil; ++ EOAdaptor *adaptor; + NSException *ex; + NSMutableArray *results; + NSMutableString *sql; +@@ -1123,12 +1154,9 @@ + channel = [cm acquireOpenChannelForURL: _viewURL]; + if (channel) + { +- if (!adaptor) +- { +- EOAdaptorContext *adaptorCtx; +- adaptorCtx = [channel adaptorContext]; +- adaptor = [adaptorCtx adaptor]; +- } ++ EOAdaptorContext *adaptorCtx; ++ adaptorCtx = [channel adaptorContext]; ++ adaptor = [adaptorCtx adaptor]; + sql = [NSMutableString stringWithFormat: @"SELECT c_name FROM %@ WHERE (", [_viewURL gcsTableName]]; + + if (qualifier) diff -Nru sogo-5.12.1/debian/patches/CVE-2026-8496.patch sogo-5.12.1/debian/patches/CVE-2026-8496.patch --- sogo-5.12.1/debian/patches/CVE-2026-8496.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/CVE-2026-8496.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,87 @@ +From: Hivert Quentin +Date: Sun, 3 May 2026 15:08:15 +0200 +Subject: fix(mail): sanitise mail with ics (invitation to event) + +Origin: upstream, https://github.com/Alinto/sogo/commit/67ce01ec2a1a7854d8e9f615dd65afb949043e8.diff +--- + SoObjects/SOGo/NSString+Utilities.m | 30 ++++++++++++++++++++---------- + UI/MailPartViewers/UIxMailPartICalViewer.m | 11 ++++++++--- + 2 files changed, 28 insertions(+), 13 deletions(-) + +diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m +index ac1d36a..b710fac 100644 +--- a/SoObjects/SOGo/NSString+Utilities.m ++++ b/SoObjects/SOGo/NSString+Utilities.m +@@ -1028,16 +1028,26 @@ static int cssEscapingCount; + newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"]+)" ++ options: NSRegularExpressionCaseInsensitive error: &error]; ++ newResult = [regex stringByReplacingMatchesInString: result options: 0 range: NSMakeRange(0, [result length]) withTemplate: @"on***=\"\""]; + result = [NSString stringWithString: newResult]; + + // Remove @import css (in style tags) +diff --git a/UI/MailPartViewers/UIxMailPartICalViewer.m b/UI/MailPartViewers/UIxMailPartICalViewer.m +index 7831900..d8f7527 100644 +--- a/UI/MailPartViewers/UIxMailPartICalViewer.m ++++ b/UI/MailPartViewers/UIxMailPartICalViewer.m +@@ -44,6 +44,7 @@ + #import + #import + #import ++#import + #import + #import + #import +@@ -81,8 +82,7 @@ + { + if (!inCalendar) + { +- inCalendar +- = [iCalCalendar parseSingleFromSource: [self flatContentAsString]]; ++ inCalendar = [iCalCalendar parseSingleFromSource: [self flatContentAsString]]; + [inCalendar retain]; + } + +@@ -583,7 +583,12 @@ + [[person partStatWithDefault] lowercaseString], @"partstat", nil]]; + } + +- [d setObject: a forKey: @"participants"]; ++ [d setObject: a forKey: @"participants"]; ++ ++ //Sanitise the html content ++ if([d objectForKey:@"content"]){ ++ [d setObject: [[d objectForKey:@"content"] stringWithoutHTMLInjection: NO] forKey: @"content"]; ++ } + + return d; + } diff -Nru sogo-5.12.1/debian/patches/CVE-2026-8496_regression_fix.patch sogo-5.12.1/debian/patches/CVE-2026-8496_regression_fix.patch --- sogo-5.12.1/debian/patches/CVE-2026-8496_regression_fix.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/CVE-2026-8496_regression_fix.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,64 @@ +From: Hivert Quentin +Date: Tue, 19 May 2026 09:30:58 +0200 +Subject: fix(pref): prevent onevent cleaning to remove legitimate words + +Origin: backport, https://github.com/Alinto/sogo/commit/c45233c11e250a22fa1e1f3e47fee2d6e232045b.diff +--- + SoObjects/SOGo/NSString+Utilities.m | 42 +++++++++++++++++++------------------ + 1 file changed, 22 insertions(+), 20 deletions(-) + +diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m +index b710fac..de0e328 100644 +--- a/SoObjects/SOGo/NSString+Utilities.m ++++ b/SoObjects/SOGo/NSString+Utilities.m +@@ -1028,28 +1028,30 @@ static int cssEscapingCount; + newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"]+)" +- options: NSRegularExpressionCaseInsensitive error: &error]; +- newResult = [regex stringByReplacingMatchesInString: result options: 0 range: NSMakeRange(0, [result length]) withTemplate: @"on***=\"\""]; ++ // Remove onload ++ regex = [NSRegularExpression regularExpressionWithPattern:@"onload=" ++ options: NSRegularExpressionCaseInsensitive error:&error]; ++ newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onl***="]; + result = [NSString stringWithString: newResult]; + ++ // Remove onmouseover ++ regex = [NSRegularExpression regularExpressionWithPattern:@"onmouseover=" ++ options: NSRegularExpressionCaseInsensitive error:&error]; ++ newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onmouseo***="]; ++ result = [NSString stringWithString: newResult]; ++ ++ // Remove onrepeat ++ regex = [NSRegularExpression regularExpressionWithPattern:@"onrepeat=" ++ options: NSRegularExpressionCaseInsensitive error:&error]; ++ newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onrep***="]; ++ result = [NSString stringWithString: newResult]; ++ ++ // Remove onerror ++ regex = [NSRegularExpression regularExpressionWithPattern:@"onerror=" ++ options: NSRegularExpressionCaseInsensitive error:&error]; ++ newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onerr***="]; ++ result = [NSString stringWithString: newResult]; ++ + // Remove @import css (in style tags) + regex = [NSRegularExpression regularExpressionWithPattern:@"(<[\\s\\u200B \\\\0]*s[\\s\\u200B \\\\0]*t[\\s\\u200B \\\\0]*y[\\s\\u200B \\\\0]*l[\\s\\u200B \\\\0]*e.*)([\\s\\u200B \\\\0]*@[\\s\\u200B \\\\0]*i[\\s\\u200B \\\\0]*m[\\s\\u200B \\\\0]*p[\\s\\u200B \\\\0]*o[\\s\\u200B \\\\0]*r[\\s\\u200B \\\\0]*t)(.*<[\\s\\u200B \\\\0]*\\/[\\s\\u200B \\\\0]*s[\\s\\u200B \\\\0]*t[\\s\\u200B \\\\0]*y[\\s\\u200B \\\\0]*l[\\s\\u200B \\\\0]*e[\\s\\u200B \\\\0]*>)" + options: NSRegularExpressionCaseInsensitive error:&error]; diff -Nru sogo-5.12.1/debian/patches/CVE-2026-8851_1.patch sogo-5.12.1/debian/patches/CVE-2026-8851_1.patch --- sogo-5.12.1/debian/patches/CVE-2026-8851_1.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/CVE-2026-8851_1.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,207 @@ +From: Hivert Quentin +Date: Wed, 15 Apr 2026 14:28:56 +0200 +Subject: fix(acl): only add existing uid + +Origin: upstream, https://github.com/Alinto/sogo/commit/f9b71059f4f382d7b337d16ce1257443ade43d02.diff +--- + SoObjects/SOGo/SOGoGCSFolder.m | 76 ++++++++++++++++++++++++++++++++++-------- + SoObjects/SOGo/SQLSource.m | 8 ----- + UI/Common/UIxObjectActions.m | 39 ++++++++++++++++++++++ + 3 files changed, 102 insertions(+), 21 deletions(-) + +diff --git a/SoObjects/SOGo/SOGoGCSFolder.m b/SoObjects/SOGo/SOGoGCSFolder.m +index 19f1146..b36ba14 100644 +--- a/SoObjects/SOGo/SOGoGCSFolder.m ++++ b/SoObjects/SOGo/SOGoGCSFolder.m +@@ -1859,27 +1859,77 @@ static NSArray *childRecordFields = nil; + EOAdaptorChannel *channel; + GCSFolder *folder; + NSEnumerator *userRoles; +- NSString *SQL, *currentRole; ++ NSString *SQL, *currentRole, *sqlstr; ++ NSString *fieldName, *value; ++ EOAdaptorContext *adaptorCtx; ++ EOAdaptor *adaptor; ++ EOAttribute *attribute; + + folder = [self ocsFolder]; + channel = [folder acquireAclChannel]; +- [[channel adaptorContext] beginTransaction]; ++ adaptorCtx = [channel adaptorContext]; ++ ++ [adaptorCtx beginTransaction]; + userRoles = [roles objectEnumerator]; + while ((currentRole = [userRoles nextObject])) + { ++ int i = 0; ++ int count = 0; ++ adaptor = [adaptorCtx adaptor]; ++ attribute = [EOAttribute new]; ++ [attribute autorelease]; ++ objectPath = [NSString stringWithFormat: @"/%@", objectPath]; + if ([GCSFolderManager singleStoreMode]) +- SQL = [NSString stringWithFormat: @"INSERT INTO %@" +- @" (c_object, c_uid, c_role, c_folder_id)" +- @" VALUES ('/%@', '%@', '%@', %@)", +- [folder aclTableName], +- objectPath, uid, currentRole, [folder folderId]]; ++ { ++ sqlstr = [NSMutableString stringWithFormat: @"INSERT INTO %@" ++ @" (c_object, c_uid, c_role, c_folder_id)" ++ @" VALUES (", ++ [folder aclTableName]]; ++ NSArray *keys = [NSArray arrayWithObjects: @"c_object", @"c_uid", @"c_role", @"c_folder_id", nil]; ++ NSArray *values = [NSArray arrayWithObjects: objectPath, uid, currentRole, [folder folderId], nil]; ++ ++ for (i = 0, count = [keys count]; i < count; i++) { ++ fieldName = [keys objectAtIndex: i]; ++ if(i < 3) ++ [attribute setExternalType: @"varchar"]; ++ else ++ [attribute setExternalType: @"int"]; ++ value = [values objectAtIndex: i]; ++ if (attribute) ++ { ++ value = [adaptor formatValue: value forAttribute: attribute]; ++ [sqlstr appendString: value]; ++ if(i < 3) ++ [sqlstr appendString:@", "]; ++ } ++ } ++ [sqlstr appendString:@")"]; ++ } + else +- SQL = [NSString stringWithFormat: @"INSERT INTO %@" +- @" (c_object, c_uid, c_role)" +- @" VALUES ('/%@', '%@', '%@')", +- [folder aclTableName], +- objectPath, uid, currentRole]; +- [channel evaluateExpressionX: SQL]; ++ { ++ sqlstr = [NSMutableString stringWithFormat: @"INSERT INTO %@" ++ @" (c_object, c_uid, c_role)" ++ @" VALUES (", ++ [folder aclTableName]]; ++ NSArray *keys = [NSArray arrayWithObjects: @"c_object", @"c_uid", @"c_role", nil]; ++ NSArray *values = [NSArray arrayWithObjects: objectPath, uid, currentRole, nil]; ++ ++ for (i = 0, count = [keys count]; i < count; i++) { ++ fieldName = [keys objectAtIndex: i]; ++ [attribute setExternalType: @"varchar"]; ++ value = [values objectAtIndex: i]; ++ if (attribute) ++ { ++ value = [adaptor formatValue: value forAttribute: attribute]; ++ [sqlstr appendString: value]; ++ if(i < 2) ++ [sqlstr appendString:@", "]; ++ } ++ } ++ [sqlstr appendString:@")"]; ++ } ++ ++ [channel evaluateExpressionX: sqlstr]; + } + + [[channel adaptorContext] commitTransaction]; +diff --git a/SoObjects/SOGo/SQLSource.m b/SoObjects/SOGo/SQLSource.m +index 2a4a950..7b9d519 100644 +--- a/SoObjects/SOGo/SQLSource.m ++++ b/SoObjects/SOGo/SQLSource.m +@@ -228,13 +228,6 @@ + NSString *pass, *passwordScheme; + NSString* result; + +- // if ([_userPasswordAlgorithm caseInsensitiveCompare: @"none"] == NSOrderedSame || +- // [_userPasswordAlgorithm caseInsensitiveCompare: @"plain"] == NSOrderedSame || +- // [_userPasswordAlgorithm caseInsensitiveCompare: @"cleartext"] == NSOrderedSame) +- // { +- // pass = [pass stringByReplacingString: @"'" withString: @"''"]; +- // } +- + pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm + keyPath: _keyPath]; + +@@ -468,7 +461,6 @@ + return NO; + + // Save new password +- // login = [login stringByReplacingString: @"'" withString: @"''"]; + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: _viewURL]; + if (channel) +diff --git a/UI/Common/UIxObjectActions.m b/UI/Common/UIxObjectActions.m +index 9ade2d9..873273d 100644 +--- a/UI/Common/UIxObjectActions.m ++++ b/UI/Common/UIxObjectActions.m +@@ -26,6 +26,8 @@ + #import + #import + ++#import ++ + #import + + #import +@@ -34,6 +36,25 @@ + + @implementation UIxObjectActions + ++ ++- (BOOL) _checkUid: (NSString *) newUID ++{ ++ BOOL response; ++ SOGoUserManager *um; ++ response = NO; ++ ++ if ([newUID length] > 0) ++ { ++ um = [SOGoUserManager sharedUserManager]; ++ if ([[um getEmailForUID: newUID] length] > 0) ++ { ++ response = YES; ++ } ++ } ++ ++ return response; ++} ++ + /** + * @api {get} /so/:username/:folderPath/addUserInAcls?uid=:uid Add user to ACLs + * @apiVersion 1.0.0 +@@ -49,8 +70,17 @@ + WOResponse *response; + NSString *uid; + unsigned int code; ++ NSDictionary *jsonResponse; + + uid = [[context request] formValueForKey: @"uid"]; ++ if(![self _checkUid: uid]) ++ { ++ jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"No such user."] ++ forKey: @"message"]; ++ response = [self responseWithStatus: 403 ++ andString: [jsonResponse jsonRepresentation]]; ++ return response; ++ } + if ([[self clientObject] addUserInAcls: uid]) + code = 204; + else +@@ -77,8 +107,17 @@ + WOResponse *response; + NSString *uid; + unsigned int code; ++ NSDictionary *jsonResponse; + + uid = [[context request] formValueForKey: @"uid"]; ++ if(![self _checkUid: uid]) ++ { ++ jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"No such user."] ++ forKey: @"message"]; ++ response = [self responseWithStatus: 403 ++ andString: [jsonResponse jsonRepresentation]]; ++ return response; ++ } + if ([[self clientObject] removeUserFromAcls: uid]) + code = 204; + else diff -Nru sogo-5.12.1/debian/patches/CVE-2026-8851_2.patch sogo-5.12.1/debian/patches/CVE-2026-8851_2.patch --- sogo-5.12.1/debian/patches/CVE-2026-8851_2.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/CVE-2026-8851_2.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,37 @@ +From: Hivert Quentin +Date: Tue, 21 Apr 2026 13:52:19 +0200 +Subject: fix(acl): fix folder path + +Origin: upstream, https://github.com/Alinto/sogo/commit/d902756aaf955a9ade6061806bb372e15b673197.diff +--- + SoObjects/SOGo/SOGoGCSFolder.m | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/SoObjects/SOGo/SOGoGCSFolder.m b/SoObjects/SOGo/SOGoGCSFolder.m +index b36ba14..8b0010f 100644 +--- a/SoObjects/SOGo/SOGoGCSFolder.m ++++ b/SoObjects/SOGo/SOGoGCSFolder.m +@@ -1871,6 +1871,7 @@ static NSArray *childRecordFields = nil; + + [adaptorCtx beginTransaction]; + userRoles = [roles objectEnumerator]; ++ objectPath = [NSString stringWithFormat: @"/%@", objectPath]; + while ((currentRole = [userRoles nextObject])) + { + int i = 0; +@@ -1878,7 +1879,6 @@ static NSArray *childRecordFields = nil; + adaptor = [adaptorCtx adaptor]; + attribute = [EOAttribute new]; + [attribute autorelease]; +- objectPath = [NSString stringWithFormat: @"/%@", objectPath]; + if ([GCSFolderManager singleStoreMode]) + { + sqlstr = [NSMutableString stringWithFormat: @"INSERT INTO %@" +@@ -1928,7 +1928,6 @@ static NSArray *childRecordFields = nil; + } + [sqlstr appendString:@")"]; + } +- + [channel evaluateExpressionX: sqlstr]; + } + diff -Nru sogo-5.12.1/debian/patches/fix_message_rendering_1.patch sogo-5.12.1/debian/patches/fix_message_rendering_1.patch --- sogo-5.12.1/debian/patches/fix_message_rendering_1.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/fix_message_rendering_1.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,82 @@ +From: Hivert Quentin +Date: Fri, 8 May 2026 11:02:52 +0200 +Subject: fix(mail): correctly render mail when searching + +Origin: upstream, https://github.com/alinto/sogo/commit/0cb21f8fb95d3fcb5da5112e3dcf082fa7cb1fe3.diff +--- + UI/WebServerResources/js/Mailer/Message.service.js | 18 ++++++++++++------ + .../js/Mailer/sgMessageListItemMain.directive.js | 4 ++-- + 2 files changed, 14 insertions(+), 8 deletions(-) + +diff --git a/UI/WebServerResources/js/Mailer/Message.service.js b/UI/WebServerResources/js/Mailer/Message.service.js +index 841c6b3..b2c89ba 100644 +--- a/UI/WebServerResources/js/Mailer/Message.service.js ++++ b/UI/WebServerResources/js/Mailer/Message.service.js +@@ -492,7 +492,7 @@ + && ("UIxMailPartHTMLViewer" == parts[i].type + || "UIxMailPartTextViewer" == parts[i].type)) { + // Content +- parts[i].content = this.highlightSearchTerms(parts[i].content, false); ++ parts[i].content = this.highlightSearchTerms(parts[i].content, false, true); + // Title + this.subject = this.getHighlightSubject(); + // From +@@ -513,14 +513,20 @@ + * @desc Returns the data with highlight search + * @returns the data with highlighted search terms + */ +- Message.prototype.highlightSearchTerms = function (data, encodeEntities) { ++ Message.prototype.highlightSearchTerms = function (data, encodeEntities, isHtml) { + var i = 0; + if (this.$mailbox.getHighlightWords() + && this.$mailbox.getHighlightWords().length > 0 + && data + && -1 === data.indexOf("data-markjs")) { + var dom = document.createElement("DIV"); +- dom.textContent = encodeEntities ? data.encodeEntities() : data; ++ if(isHtml){ ++ dom.innerHTML = encodeEntities ? data.encodeEntities() : data; ++ } ++ else{ ++ dom.textContent = encodeEntities ? data.encodeEntities() : data; ++ } ++ + var markInstance = new Mark(dom); + markInstance.mark(this.$mailbox.getHighlightWords()); + data = dom.innerHTML; +@@ -540,7 +546,7 @@ + * @returns the subject with highlighted search terms + */ + Message.prototype.getHighlightSubject = function () { +- return this.highlightSearchTerms(this.subject, false); ++ return this.highlightSearchTerms(this.subject, false, false); + }; + + /** +@@ -552,8 +558,8 @@ + Message.prototype.getHighlightFrom = function () { + var i = 0; + for (i = 0; i < this.from.length; i++) { +- this.from[i].fullHighlighted = this.highlightSearchTerms(this.from[i].full, false); +- this.from[i].nameHighlighted = this.highlightSearchTerms(this.from[i].name, false); ++ this.from[i].fullHighlighted = this.highlightSearchTerms(this.from[i].full, false, false); ++ this.from[i].nameHighlighted = this.highlightSearchTerms(this.from[i].name, false, false); + } + + return this.from; +diff --git a/UI/WebServerResources/js/Mailer/sgMessageListItemMain.directive.js b/UI/WebServerResources/js/Mailer/sgMessageListItemMain.directive.js +index 4ecc6f1..1b0cfb5 100644 +--- a/UI/WebServerResources/js/Mailer/sgMessageListItemMain.directive.js ++++ b/UI/WebServerResources/js/Mailer/sgMessageListItemMain.directive.js +@@ -197,9 +197,9 @@ + + // Sender or recipient when in Sent or Draft mailbox + if ($ctrl.MailboxService.selectedFolder.isSentFolder || $ctrl.MailboxService.selectedFolder.isDraftsFolder) +- $ctrl.senderElement.innerHTML = $ctrl.message.highlightSearchTerms($ctrl.message.$shortAddress('to', Preferences.defaults.SOGoMailDisplayFullEmail), true); ++ $ctrl.senderElement.innerHTML = $ctrl.message.highlightSearchTerms($ctrl.message.$shortAddress('to', Preferences.defaults.SOGoMailDisplayFullEmail), true, false); + else +- $ctrl.senderElement.innerHTML = $ctrl.message.highlightSearchTerms($ctrl.message.$shortAddress('from', Preferences.defaults.SOGoMailDisplayFullEmail), true); ++ $ctrl.senderElement.innerHTML = $ctrl.message.highlightSearchTerms($ctrl.message.$shortAddress('from', Preferences.defaults.SOGoMailDisplayFullEmail), true, false); + } + }; + diff -Nru sogo-5.12.1/debian/patches/fix_message_rendering_2.patch sogo-5.12.1/debian/patches/fix_message_rendering_2.patch --- sogo-5.12.1/debian/patches/fix_message_rendering_2.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/fix_message_rendering_2.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,29 @@ +From: Hivert Quentin +Date: Tue, 12 May 2026 08:52:18 +0200 +Subject: fix(mail): render the subject without html when searching + +Origin: upstream, https://github.com/Alinto/sogo/commit/be440baa23fd8b6ad5d8c947f60f9105ad717214.diff +--- + UI/WebServerResources/js/Mailer/Message.service.js | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/UI/WebServerResources/js/Mailer/Message.service.js b/UI/WebServerResources/js/Mailer/Message.service.js +index b2c89ba..403648b 100644 +--- a/UI/WebServerResources/js/Mailer/Message.service.js ++++ b/UI/WebServerResources/js/Mailer/Message.service.js +@@ -522,13 +522,12 @@ + var dom = document.createElement("DIV"); + if(isHtml){ + dom.innerHTML = encodeEntities ? data.encodeEntities() : data; ++ var markInstance = new Mark(dom); ++ markInstance.mark(this.$mailbox.getHighlightWords()); + } + else{ + dom.textContent = encodeEntities ? data.encodeEntities() : data; + } +- +- var markInstance = new Mark(dom); +- markInstance.mark(this.$mailbox.getHighlightWords()); + data = dom.innerHTML; + dom.remove(); + } else if (encodeEntities) { diff -Nru sogo-5.12.1/debian/patches/fix_message_rendering_3.patch sogo-5.12.1/debian/patches/fix_message_rendering_3.patch --- sogo-5.12.1/debian/patches/fix_message_rendering_3.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/fix_message_rendering_3.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,22 @@ +From: Hivert Quentin +Date: Tue, 19 May 2026 10:01:46 +0200 +Subject: fix(mail): do not encode non-html element + +Origin: upstream, https://github.com/alinto/sogo/commit/6e590115fbce073847369495997228fba2fc3ce8.diff +--- + UI/WebServerResources/js/Mailer/Message.service.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/UI/WebServerResources/js/Mailer/Message.service.js b/UI/WebServerResources/js/Mailer/Message.service.js +index 403648b..ad1d8a5 100644 +--- a/UI/WebServerResources/js/Mailer/Message.service.js ++++ b/UI/WebServerResources/js/Mailer/Message.service.js +@@ -526,7 +526,7 @@ + markInstance.mark(this.$mailbox.getHighlightWords()); + } + else{ +- dom.textContent = encodeEntities ? data.encodeEntities() : data; ++ dom.textContent = data; + } + data = dom.innerHTML; + dom.remove(); diff -Nru sogo-5.12.1/debian/patches/fix_openid_validation.patch sogo-5.12.1/debian/patches/fix_openid_validation.patch --- sogo-5.12.1/debian/patches/fix_openid_validation.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/fix_openid_validation.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,118 @@ +From: Hivert Quentin +Date: Tue, 5 May 2026 10:39:38 +0200 +Subject: fix(openid): check the userinfo mail + avoid infinite loop + +Origin: upstream, https://github.com/Alinto/sogo/commit/93b82a0f60ce5d8b0938e3f03d86baee8d075162.diff +--- + SoObjects/SOGo/SOGoOpenIdSession.m | 43 ++++++++++++++++++++++++++++++++++++-- + UI/MainUI/SOGoRootPage.m | 14 +++++++++++++ + 2 files changed, 55 insertions(+), 2 deletions(-) + +diff --git a/SoObjects/SOGo/SOGoOpenIdSession.m b/SoObjects/SOGo/SOGoOpenIdSession.m +index a94202b..b651654 100644 +--- a/SoObjects/SOGo/SOGoOpenIdSession.m ++++ b/SoObjects/SOGo/SOGoOpenIdSession.m +@@ -814,13 +814,16 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer) + - (NSMutableDictionary *) fetchUserInfo + { + NSString *location, *auth, *content; ++ SOGoSystemDefaults *sd; + SimpleOpenIdResponse *response; + // WOResponse *response; + NSUInteger status; + NSMutableDictionary *result; + NSDictionary *profile, *headers; + NSURL *url; +- NSString *email; ++ NSString *email, *type, *user_domain; ++ NSRange r; ++ NSArray *domainsAllowed; + + result = [NSMutableDictionary dictionary]; + [result setObject: @"ok" forKey: @"error"]; +@@ -862,6 +865,36 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer) + "email":"myuser@user.com"}*/ + if (email = [profile objectForKey: self->openIdEmailParam]) + { ++ //Check the mail domain is ok ++ ++ r = [email rangeOfString: @"@"]; ++ if (r.location != NSNotFound) ++ user_domain = [email substringFromIndex: r.location+1]; ++ else ++ { ++ [self logWithFormat: @"Error mail from userInfo not a mail %@", email]; ++ [result setObject: @"mail-error" forKey: @"error"]; ++ return result; ++ } ++ ++ sd = [SOGoSystemDefaults sharedSystemDefaults]; ++ if(self->forDomain != nil && [sd doesLoginTypeByDomain]) ++ { ++ type = [sd getLoginTypeForDomain: self->forDomain]; ++ if(type != nil && [type isEqualToString: @"openid"] && ![user_domain isEqualToString: self->forDomain]) ++ { ++ [self errorWithFormat: @"Openid userinfo email is not the right domain. Excpected: %@, Got %@", self->forDomain, user_domain]; ++ [result setObject: @"mail-error" forKey: @"error"]; ++ return result; ++ } ++ } ++ else if(((domainsAllowed = [sd domainsAllowed]) && [domainsAllowed count] > 0) && ![domainsAllowed containsObject: user_domain]) ++ { ++ [self errorWithFormat: @"Openid userinfo email domain is not allowed. Got %@", user_domain]; ++ [result setObject: @"mail-error" forKey: @"error"]; ++ return result; ++ } ++ + if(self->userTokenInterval > 0) + [self _saveUserToCache: email]; + [result setObject: email forKey: @"login"]; +@@ -940,7 +973,7 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer) + } + } + +- //The acces token hasn't work, delete the session in database if needed ++ //The access token hasn't work, delete the session in database if needed + if(self->accessToken) + { + [[[GCSFolderManager defaultFolderManager] openIdFolder] deleteOpenIdSessionFor: self->accessToken]; +@@ -953,6 +986,12 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer) + //remove old session + [[[GCSFolderManager defaultFolderManager] openIdFolder] deleteOpenIdSessionFor: self->accessToken]; + } ++ if([[resultUserInfo objectForKey: @"error"] isEqualToString: @"mail-error"]) ++ { ++ //Means there is a problem with the mail get from userInfo (logs wil explained) ++ //To avoid infinite loop -> openid -> redirect sogo -> useinfo fail -> rediretc to sogo index -> redirect to openid... ++ return nil; ++ } + + return @"anonymous"; + } +diff --git a/UI/MainUI/SOGoRootPage.m b/UI/MainUI/SOGoRootPage.m +index c5cde4a..d4717c8 100644 +--- a/UI/MainUI/SOGoRootPage.m ++++ b/UI/MainUI/SOGoRootPage.m +@@ -684,8 +684,22 @@ static const NSString *kJwtKey = @"jwt"; + code = value; + [openIdSession fetchToken: code redirect: redirectLocation]; + login = [openIdSession login: @""]; ++ if(!login) ++ { ++ //login is nil only if there's a problem with the userInfo mail parameters ++ response = [self responseWithStatus: 500 andString: @"Openid wrong email, check the log"]; ++ return response; ++ } + if ([login length]) + { ++ //Check if the user exist in SOGo user source (ldap or sql) ++ loggedInUser = [SOGoUser userWithLogin: login]; ++ if(!loggedInUser) ++ { ++ [self logWithFormat: @"Mail returned by openid does not exist in user source: %@", login]; ++ response = [self responseWithStatus: 500 andString: @"Openid wrong email, check the log"]; ++ return response; ++ } + auth = [[WOApplication application] authenticatorInContext: context]; + openIdCookie = [auth cookieWithUsername: login + andPassword: [openIdSession getToken] diff -Nru sogo-5.12.1/debian/patches/fix_xss_message_subject_rendering_1.patch sogo-5.12.1/debian/patches/fix_xss_message_subject_rendering_1.patch --- sogo-5.12.1/debian/patches/fix_xss_message_subject_rendering_1.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/fix_xss_message_subject_rendering_1.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,22 @@ +From: Hivert Quentin +Date: Mon, 13 Apr 2026 16:17:41 +0200 +Subject: fix(UI): render properly the subject + +Origin: upstream, https://github.com/Alinto/sogo/commit/b7641be5c80c0c02dc1b4742ce92e4de9a948b72.diff +--- + UI/WebServerResources/js/Mailer/sgMessageListItemMain.directive.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/UI/WebServerResources/js/Mailer/sgMessageListItemMain.directive.js b/UI/WebServerResources/js/Mailer/sgMessageListItemMain.directive.js +index 0e2e920..4ecc6f1 100644 +--- a/UI/WebServerResources/js/Mailer/sgMessageListItemMain.directive.js ++++ b/UI/WebServerResources/js/Mailer/sgMessageListItemMain.directive.js +@@ -193,7 +193,7 @@ + this.defineSubjectAndSenderElements = function() { + if ($ctrl && $ctrl.message && !$ctrl.message.loading) { + // Subject +- $ctrl.subjectElement.innerHTML = $ctrl.message.getHighlightSubject(); ++ $ctrl.subjectElement.textContent = $ctrl.message.getHighlightSubject(); + + // Sender or recipient when in Sent or Draft mailbox + if ($ctrl.MailboxService.selectedFolder.isSentFolder || $ctrl.MailboxService.selectedFolder.isDraftsFolder) diff -Nru sogo-5.12.1/debian/patches/fix_xss_message_subject_rendering_2.patch sogo-5.12.1/debian/patches/fix_xss_message_subject_rendering_2.patch --- sogo-5.12.1/debian/patches/fix_xss_message_subject_rendering_2.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/fix_xss_message_subject_rendering_2.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,72 @@ +From: Hivert Quentin +Date: Sun, 3 May 2026 16:57:25 +0200 +Subject: fix(mail): render properly the subject v2 + +Origin: upstream, https://github.com/Alinto/sogo/commit/29d0bbc9eb96c2b4a0ada4d93eac79a66c789b22.diff +--- + UI/MailerUI/UIxMailListActions.m | 2 +- + UI/MailerUI/UIxMailView.m | 2 +- + UI/Templates/MailerUI/UIxMailViewTemplate.wox | 2 +- + UI/WebServerResources/js/Mailer/Message.service.js | 3 ++- + 4 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/UI/MailerUI/UIxMailListActions.m b/UI/MailerUI/UIxMailListActions.m +index 6d2f8cf..9c5ee1a 100644 +--- a/UI/MailerUI/UIxMailListActions.m ++++ b/UI/MailerUI/UIxMailListActions.m +@@ -1169,7 +1169,7 @@ + [msg addObject: [NSNumber numberWithBool: [self isMessageFlagged]]]; + + // Subject +- [msg addObject: [[self messageSubject] stringWithoutHTMLInjection: YES]]; ++ [msg addObject: [[[self messageSubject] stringWithoutHTMLInjection: YES] stringWithoutHTMLInjection: NO]]; + + // From + from = [[message objectForKey: @"envelope"] from]; +diff --git a/UI/MailerUI/UIxMailView.m b/UI/MailerUI/UIxMailView.m +index f52829a..aee7cd5 100644 +--- a/UI/MailerUI/UIxMailView.m ++++ b/UI/MailerUI/UIxMailView.m +@@ -363,7 +363,7 @@ static NSString *mailETag = nil; + if ([self formattedDate]) + [data setObject: [self formattedDate] forKey: @"date"]; + if ([self messageSubject]) +- [data setObject: [[self messageSubject] stringWithoutHTMLInjection: YES] forKey: @"subject"]; ++ [data setObject: [[[self messageSubject] stringWithoutHTMLInjection: YES] stringWithoutHTMLInjection: NO] forKey: @"subject"]; + if ((addresses = [addressFormatter dictionariesForArray: [co fromEnvelopeAddresses]])) + [data setObject: addresses forKey: @"from"]; + if ((addresses = [addressFormatter dictionariesForArray: [co toEnvelopeAddresses]])) +diff --git a/UI/Templates/MailerUI/UIxMailViewTemplate.wox b/UI/Templates/MailerUI/UIxMailViewTemplate.wox +index dc1c70d..45000a3 100644 +--- a/UI/Templates/MailerUI/UIxMailViewTemplate.wox ++++ b/UI/Templates/MailerUI/UIxMailViewTemplate.wox +@@ -194,7 +194,7 @@ + + +
+-
++
+ +
+
+diff --git a/UI/WebServerResources/js/Mailer/Message.service.js b/UI/WebServerResources/js/Mailer/Message.service.js +index c8a20b6..841c6b3 100644 +--- a/UI/WebServerResources/js/Mailer/Message.service.js ++++ b/UI/WebServerResources/js/Mailer/Message.service.js +@@ -520,7 +520,7 @@ + && data + && -1 === data.indexOf("data-markjs")) { + var dom = document.createElement("DIV"); +- dom.innerHTML = encodeEntities ? data.encodeEntities() : data; ++ dom.textContent = encodeEntities ? data.encodeEntities() : data; + var markInstance = new Mark(dom); + markInstance.mark(this.$mailbox.getHighlightWords()); + data = dom.innerHTML; +@@ -532,6 +532,7 @@ + return data; + }; + ++ + /** + * @function getHighlightSubject + * @memberof Message.prototype diff -Nru sogo-5.12.1/debian/patches/git_clean_import_event.patch sogo-5.12.1/debian/patches/git_clean_import_event.patch --- sogo-5.12.1/debian/patches/git_clean_import_event.patch 1970-01-01 00:00:00.000000000 +0000 +++ sogo-5.12.1/debian/patches/git_clean_import_event.patch 2026-06-15 19:26:37.000000000 +0000 @@ -0,0 +1,26 @@ +commit b18f1a09f59424a36f6de5aa7c30e6f27405c15d +Author: Hivert Quentin +Date: Tue May 26 10:30:02 2026 +0200 + + fix(event): clean import of event + +diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m +index f18c7ad77..f958eab51 100644 +--- a/SoObjects/Appointments/SOGoAppointmentFolder.m ++++ b/SoObjects/Appointments/SOGoAppointmentFolder.m +@@ -3521,6 +3521,15 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir + timezone = nil; + element = [components objectAtIndex: i]; + ++ //remove all attenddees, change organisator and change uid ++ //If we do not clean up, any user could impersonate someone by importing a malicious .ics ++ //and send notificaitons to attenddes or remove their event (as SOGo think the user has the rights to do so) ++ [element removeAllAttendees]; ++ [element setOrganizer: nil]; ++ [element setUid: [self globallyUniqueObjectId]]; ++ ++ ++ + if ([element isKindOfClass: iCalEventK]) + { + event = (iCalEvent *)element; diff -Nru sogo-5.12.1/debian/patches/series sogo-5.12.1/debian/patches/series --- sogo-5.12.1/debian/patches/series 2025-12-31 09:20:54.000000000 +0000 +++ sogo-5.12.1/debian/patches/series 2026-06-15 19:26:37.000000000 +0000 @@ -17,3 +17,18 @@ upstream_use_openid_libcurl.patch CVE-2025-63499.patch CVE-2025-63498.patch +CVE-2026-46445_CVE-2026-46446.patch +CVE-2025-71276.patch +CVE-2026-3054.patch +CVE-2026-33550.patch +CVE-2026-8496.patch +CVE-2026-8496_regression_fix.patch +CVE-2026-8851_1.patch +CVE-2026-8851_2.patch +fix_openid_validation.patch +fix_xss_message_subject_rendering_1.patch +fix_xss_message_subject_rendering_2.patch +git_clean_import_event.patch +fix_message_rendering_1.patch +fix_message_rendering_2.patch +fix_message_rendering_3.patch