From 045a0b9c0ac57aeea1b619f281acff0427cd81c7 Mon Sep 17 00:00:00 2001 From: Jan Kahmen <36455663+kah-ja@users.noreply.github.com> Date: Mon, 17 Aug 2026 23:43:06 +0200 Subject: [PATCH] fix(mail): escape mail data placed in attributes of a compiled part the generic attribute writer used for these two spots does not escape what it writes, so a value taken from the message ends the attribute and starts a new one. both are inside a part that is compiled, which is where an injected handler runs. * the organizer link took inEvent.organizer.email verbatim. a value such as mailto:x@y" onpointerover="... produced a live handler on the anchor, and an entity encoded scheme such as javascript: reached the href, where the browser decodes it. the href is now built as mailto: plus the parsed address and escaped as an attribute value. * the attachment name paragraph of the image and the link viewer took filenameForDisplay verbatim. a quote inside an RFC 2231 encoded filename ended the title attribute. the writer escapes & < > there but not the quote, so the accessor drops the quote instead of escaping it, which keeps a plain filename such as A&B.pdf unchanged in the tooltip. the img title of the image viewer is left alone: attributes of that element are escaped by the framework already. --- UI/MailPartViewers/UIxMailPartICalViewer.h | 1 + UI/MailPartViewers/UIxMailPartICalViewer.m | 12 ++++++++++++ UI/MailPartViewers/UIxMailPartViewer.h | 1 + UI/MailPartViewers/UIxMailPartViewer.m | 8 ++++++++ .../MailPartViewers/UIxMailPartICalViewer.wox | 4 ++-- .../MailPartViewers/UIxMailPartImageViewer.wox | 2 +- .../MailPartViewers/UIxMailPartLinkViewer.wox | 2 +- 7 files changed, 26 insertions(+), 4 deletions(-) diff --git a/UI/MailPartViewers/UIxMailPartICalViewer.h b/UI/MailPartViewers/UIxMailPartICalViewer.h index bf12be30a..dada2cb3e 100644 --- a/UI/MailPartViewers/UIxMailPartICalViewer.h +++ b/UI/MailPartViewers/UIxMailPartICalViewer.h @@ -46,6 +46,7 @@ - (BOOL) isEndDateOnSameDay; - (BOOL) hasLocation; - (NSString *)location; +- (NSString *) organizerHref; - (NSString *) userComment; - (NSString *) eventDescription; diff --git a/UI/MailPartViewers/UIxMailPartICalViewer.m b/UI/MailPartViewers/UIxMailPartICalViewer.m index d6dedac4b..6d214485e 100644 --- a/UI/MailPartViewers/UIxMailPartICalViewer.m +++ b/UI/MailPartViewers/UIxMailPartICalViewer.m @@ -418,6 +418,18 @@ return YES; } +- (NSString *) organizerHref +{ + NSString *address; + + address = [[[self inEvent] organizer] rfc822Email]; + if (![address length]) + return nil; + + return [[NSString stringWithFormat: @"mailto:%@", address] + stringByEscapingHTMLAttributeValue]; +} + - (NSString *) organizerDisplayName { iCalPerson *organizer; diff --git a/UI/MailPartViewers/UIxMailPartViewer.h b/UI/MailPartViewers/UIxMailPartViewer.h index 0cb3622e3..7a3c230c2 100644 --- a/UI/MailPartViewers/UIxMailPartViewer.h +++ b/UI/MailPartViewers/UIxMailPartViewer.h @@ -86,6 +86,7 @@ - (NSString *)preferredPathExtension; - (NSString *)filename; - (NSString *)filenameForDisplay; +- (NSString *)filenameForTitle; - (NSFormatter *)sizeFormatter; /* caches */ diff --git a/UI/MailPartViewers/UIxMailPartViewer.m b/UI/MailPartViewers/UIxMailPartViewer.m index 38e80422f..0501908c9 100644 --- a/UI/MailPartViewers/UIxMailPartViewer.m +++ b/UI/MailPartViewers/UIxMailPartViewer.m @@ -340,6 +340,14 @@ : (id)@"untitled"; } +- (NSString *) filenameForTitle +{ + /* the generic attribute writer escapes & but not the quote, so a quote in the + filename would end the title attribute and start a new one */ + return [[self filenameForDisplay] stringByReplacingOccurrencesOfString: @"\"" + withString: @""]; +} + - (NSFormatter *) sizeFormatter { return [UIxMailSizeFormatter sharedMailSizeFormatter]; diff --git a/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox b/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox index 5ebf7a6b3..d18f5c8db 100644 --- a/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox +++ b/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox @@ -137,7 +137,7 @@
@@ -147,7 +147,7 @@
+