Version in base suite: 6.0.28+ds1-2 Base version: tryton-sao_6.0.28+ds1-2 Target version: tryton-sao_6.0.28+ds1-2+deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/t/tryton-sao/tryton-sao_6.0.28+ds1-2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/t/tryton-sao/tryton-sao_6.0.28+ds1-2+deb12u1.dsc changelog | 12 + patches/01_xss_vulnerability_attachments_preview.patch | 116 +++++++++++++++++ patches/series | 1 3 files changed, 129 insertions(+) diff -Nru tryton-sao-6.0.28+ds1/debian/changelog tryton-sao-6.0.28+ds1/debian/changelog --- tryton-sao-6.0.28+ds1/debian/changelog 2023-03-05 09:58:36.000000000 +0000 +++ tryton-sao-6.0.28+ds1/debian/changelog 2025-10-21 10:54:14.000000000 +0000 @@ -1,3 +1,15 @@ +tryton-sao (6.0.28+ds1-2+deb12u1) bookworm-security; urgency=high + + * Add 01_xss_vulnerability_attachments_preview.patch. + Patch for security issue: + https://bugs.tryton.org/14290 + 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 12:54:14 +0200 + tryton-sao (6.0.28+ds1-2) unstable; urgency=medium * Build depend on uglifyjs instead of deprecated node-uglify (Closes: diff -Nru tryton-sao-6.0.28+ds1/debian/patches/01_xss_vulnerability_attachments_preview.patch tryton-sao-6.0.28+ds1/debian/patches/01_xss_vulnerability_attachments_preview.patch --- tryton-sao-6.0.28+ds1/debian/patches/01_xss_vulnerability_attachments_preview.patch 1970-01-01 00:00:00.000000000 +0000 +++ tryton-sao-6.0.28+ds1/debian/patches/01_xss_vulnerability_attachments_preview.patch 2025-10-21 10:51:37.000000000 +0000 @@ -0,0 +1,116 @@ +Description: Prevent XSS vulnerability in the preview function of attachments + 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. +Author: Cédric Krier +Bug: https://bugs.tryton.org/14290 +Origin: https://foss.heptapod.net/tryton/tryton/-/commit/2530ef8dbd14c8080433eff99cab2be43b9fb47c +Forwarded: not-needed + +--- a/src/sao.less ++++ b/src/sao.less +@@ -664,9 +664,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 +@@ -4229,15 +4229,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 (this.attributes.height) { ++ content.css('height', parseInt(this.attributes.height, 10)); ++ } ++ if (this.attributes.width) { ++ content.css('width', parseInt(this.attributes.width, 10)); + } +- if (attributes.width) { +- this.object.css('width', parseInt(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); +@@ -4253,26 +4280,28 @@ + filename = filename_field.get_client(record); + } + data.done(function(data) { +- var url, blob; + if (record !== this.record) { + return; + } ++ 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); + } +- this.object.attr('data', url); +- this.object.get(0).onload = function() { +- window.URL.revokeObjectURL(url); +- }; ++ let content = this._create_content(mimetype, url); ++ this.content.replaceWith(content); ++ this.content = content; + }.bind(this)); + }, + }); diff -Nru tryton-sao-6.0.28+ds1/debian/patches/series tryton-sao-6.0.28+ds1/debian/patches/series --- tryton-sao-6.0.28+ds1/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ tryton-sao-6.0.28+ds1/debian/patches/series 2025-10-21 09:57:27.000000000 +0000 @@ -0,0 +1 @@ +01_xss_vulnerability_attachments_preview.patch