Version in base suite: 7.0.28+ds1-1 Base version: tryton-sao_7.0.28+ds1-1 Target version: tryton-sao_7.0.28+ds1-1+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/t/tryton-sao/tryton-sao_7.0.28+ds1-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/t/tryton-sao/tryton-sao_7.0.28+ds1-1+deb13u1.dsc changelog | 11 + patches/01_xss_vulnerability_attachments_preview.patch | 113 +++++++++++++++++ patches/series | 1 3 files changed, 125 insertions(+) diff -Nru tryton-sao-7.0.28+ds1/debian/changelog tryton-sao-7.0.28+ds1/debian/changelog --- tryton-sao-7.0.28+ds1/debian/changelog 2025-04-28 07:59:30.000000000 +0000 +++ tryton-sao-7.0.28+ds1/debian/changelog 2025-10-21 11:12:38.000000000 +0000 @@ -1,3 +1,14 @@ +tryton-sao (7.0.28+ds1-1+deb13u1) trixie-security; urgency=high + + * Add 01_xss_vulnerability_attachments_preview.patch. + Patch for security issue: + https://discuss.tryton.org/t/security-release-for-issue-14290/8895 + The HTML element used to display the document is based on the mimetype. + And by default a sandboxed iframe is used to isolate the unsafe content from + the parent context. + + -- Mathias Behrle Tue, 21 Oct 2025 13:12:38 +0200 + tryton-sao (7.0.28+ds1-1) unstable; urgency=medium * Merging upstream version 7.0.28. diff -Nru tryton-sao-7.0.28+ds1/debian/patches/01_xss_vulnerability_attachments_preview.patch tryton-sao-7.0.28+ds1/debian/patches/01_xss_vulnerability_attachments_preview.patch --- tryton-sao-7.0.28+ds1/debian/patches/01_xss_vulnerability_attachments_preview.patch 1970-01-01 00:00:00.000000000 +0000 +++ tryton-sao-7.0.28+ds1/debian/patches/01_xss_vulnerability_attachments_preview.patch 2025-10-21 11:08:44.000000000 +0000 @@ -0,0 +1,113 @@ +--- a/src/sao.less ++++ b/src/sao.less +@@ -761,9 +761,14 @@ + } + } + .form-document { +- object { ++ object, img { + object-fit: scale-down; + object-position: center top; ++ } ++ iframe { ++ border: 0; ++ } ++ object, iframe, img { + width: 100%; + height: 75vh; + @media screen and (max-width: @screen-sm-max) { +--- a/src/view/form.js ++++ b/src/view/form.js +@@ -4510,15 +4510,42 @@ + 'class': this.class_, + }); + +- this.object = jQuery('', { ++ this.content = this._create_content().appendTo(this.el); ++ }, ++ _create_content: function(mimetype, url) { ++ let tag_name = 'iframe'; ++ if (mimetype) { ++ if (mimetype.startsWith('image/')) { ++ tag_name = 'img'; ++ } else if (mimetype == 'application/pdf') { ++ tag_name = 'object'; ++ } ++ } ++ let content = jQuery(`<${tag_name}/>`, { + 'class': 'center-block', +- }).appendTo(this.el); +- if (attributes.height) { +- this.object.css('height', parseInt(attributes.height, 10)); ++ }); ++ if (tag_name == 'iframe') { ++ content.attr('sandbox', ''); + } +- if (attributes.width) { +- this.object.css('width', parseInt(attributes.width, 10)); ++ if (this.attributes.height) { ++ content.css('height', parseInt(this.attributes.height, 10)); ++ } ++ if (this.attributes.width) { ++ content.css('width', parseInt(this.attributes.width, 10)); ++ } ++ if (url) { ++ // set onload before data/src to be always called ++ content.get().onload = function() { ++ this.onload = null; ++ window.URL.revokeObjectURL(url); ++ }; ++ if (tag_name== 'object') { ++ content.attr('data', url); ++ } else { ++ content.attr('src', url); ++ } + } ++ return content; + }, + display: function() { + Sao.View.Form.Document._super.display.call(this); +@@ -4534,34 +4561,30 @@ + filename = filename_field.get_client(record); + } + data.done(data => { +- var url, blob; + if (record !== this.record) { + return; + } + // in case onload was not yet triggered +- window.URL.revokeObjectURL(this.object.attr('data')); ++ let url = this.content.attr('data') || ++ this.content.attr('src'); ++ window.URL.revokeObjectURL(url); ++ let mimetype; + if (!data) { + url = null; + } else { +- var mimetype = Sao.common.guess_mimetype(filename); ++ mimetype = Sao.common.guess_mimetype(filename); + if (mimetype == 'application/octet-binary') { + mimetype = null; + } +- blob = new Blob([data], { ++ let blob = new Blob([data], { + 'type': mimetype, + }); + url = window.URL.createObjectURL(blob); + } + // duplicate object to force refresh on buggy browsers +- const object = this.object.clone(); +- // set onload before data to be always called +- object.get(0).onload = function() { +- this.onload = null; +- window.URL.revokeObjectURL(url); +- }; +- object.attr('data', url); +- this.object.replaceWith(object); +- this.object = object; ++ let content = this._create_content(mimetype, url); ++ this.content.replaceWith(content); ++ this.content = content; + }); + }, + }); diff -Nru tryton-sao-7.0.28+ds1/debian/patches/series tryton-sao-7.0.28+ds1/debian/patches/series --- tryton-sao-7.0.28+ds1/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ tryton-sao-7.0.28+ds1/debian/patches/series 2025-10-21 11:07:16.000000000 +0000 @@ -0,0 +1 @@ +01_xss_vulnerability_attachments_preview.patch