From patchwork Sun Oct 18 02:03:54 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Orling X-Patchwork-Id: 101175 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 96411CCF2C7 for ; Sun, 18 Oct 2026 02:05:56 +0000 (UTC) Received: from mail-pj1-f49.google.com (mail-pj1-f49.google.com [209.85.216.49]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.8009.1792289149048394442 for ; Sat, 17 Oct 2026 19:05:49 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20251104 header.b=f3PHZs2q; spf=pass (domain: gmail.com, ip: 209.85.216.49, mailfrom: ticotimo@gmail.com) Received: by mail-pj1-f49.google.com with SMTP id 98e67ed59e1d1-398b3c37877so658146a91.0 for ; Sat, 17 Oct 2026 19:05:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792289148; x=1792893948; darn=lists.yoctoproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=7kFjqs3hwelBPIphHklXp5Cu36PGTOKNKVbcH/MaEFw=; b=f3PHZs2qfWfBskUbXGX6g94InBr4BLKOgI2zSEHFtQg+H+E0C2o8DHWXGLpZW8rPJ0 wWK+sToMxG36oYAXNYGlWo4hfF9PKRaPyt0nAumDf+oD4S5HCkAjqSt77NlAWXQptoE6 fgtPj278XkEHc3ONLlc/a9SVMNojRxH5CK0vvrj+LVim0C202vdxYJ0PTy/UfJa2M1Xf tAT2JvZlC/UdZrnmoWLnMQyp92A5eNoyP4ccWLwxCnFEKGxA3aj0ONfvsPDDDA3fI68+ nDN7UiMmrSkQTQe/5lRQ/K2B/WlZOlTs93Y+x5DikY3KtHQWCqfeqRKZ6y+UGGYd9o9q DTug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792289148; x=1792893948; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=7kFjqs3hwelBPIphHklXp5Cu36PGTOKNKVbcH/MaEFw=; b=bwC16Ov5jaYJrRo1Df3qi2k/n4oy0I8Z9bWLHeF7QIMkA8BFtH1VXE83PZlCB6r1gD xaFwusc7RxJLrkyaItQJ48xaTVOlpBB11dCiTPI1A8qX7heNZbGuK3fTjZIr/Sp2AU9K ON4D+xUdktUyR59sEJ/sKVs0Q4xQpifO1N7/yTTW7ltcNPPL+btZfajN+s4KkfjgdYHg qWDtuzzlBPNnoa1sQQMjcIwuG23i+4Gjcr6LWsKJhFDnurVHDwwfTNlawU37+NRnac25 n/W4TfDIw9gMu4bZynAKkUksEKRDLNfSF9foqxcRzLS5CguRNQ/Mbgc5x8y49yepXIU0 HsNQ== X-Gm-Message-State: AFq9FYIHNCFhs/GEWdD6s1DQ9T+c8zgd4p4xwSiz29d/r8NSMpKMWQf+ fNEmQ3wEPeYJDZDKo7PNpwX08xjfu+fwzWrmSgnbt0LEmnwJu2ZV8m4sUI+EWY8t X-Gm-Gg: AYBFou0ZdwwNjzk4Y6+fjc+WJfCFS2izaeufk7O4BnNklQNZNmPCZQjTAyYqCBq1ALH Ct8GzjuJuhlu9iSG1x+/RjKu2wOCnh7boIiU/IFdbYOUYbldA8h4mmvJtehMDguuKooe41a3Lhn AWtwCCx6QWEUxI8hJTzLbnIt0a8Dfu758tMGBG2agiNZt9B5womhO6P1e3w2mhiZNOPhHMIPw0q x+OVKup8ywzSBrrSYuI0GVZfikbbOc0t20A3Gfu4i42aH5Q+8qPkZCeV7cY/nO3bWTbFsDXcQ0W kzDVoKVrXDjONa4H0YRGebzZ/jYiTX+6TQrzWMntZkzDP2pR9cbBkdBxCcle8DXeWVN5e2LJVPK i3yAhLiuKx+ewAaN0x+DSRDgQgNnaoCe+MfzHOp2ATomCpAxBlpG0TDsCB2KSKZ4ChdGjnPK+O5 A9+8z6CrB3HBVmP4qI07aZTrFwwtxMEz3/ltyRiNx+uTVSqZ373kkEaOG0wDqraUCa+KygzsIbL OkUZAyp1WOKtZDI7AfVvVCgERjncYg= X-Received: by 2002:a17:90b:582d:b0:3ac:8897:7b98 with SMTP id 98e67ed59e1d1-3acef1455edmr3579754a91.32.1792289148330; Sat, 17 Oct 2026 19:05:48 -0700 (PDT) Received: from localhost.localdomain ([69.9.132.159]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3acc98139ccsm5775584a91.0.2026.10.17.19.05.47 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sat, 17 Oct 2026 19:05:47 -0700 (PDT) From: Tim Orling X-Google-Original-From: Tim Orling To: yocto-patches@lists.yoctoproject.org Cc: Tim Orling Subject: [error-report-web][PATCH 1/2] Don't let Bootstrap insert submitted data as HTML. Date: Sat, 17 Oct 2026 19:03:54 -0700 Message-ID: <20261018020518.76802-3-tim.orling@konsulko.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261018020518.76802-1-tim.orling@konsulko.com> References: <20261018020518.76802-1-tim.orling@konsulko.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Sun, 18 Oct 2026 02:05:56 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/5067 The filter tooltips used html: true, and their titles hold the submitted recipe and task, which bleach doesn't clean, so a report could inject HTML (the CSP stopped scripts). Drop html: true, and build the commit popover from DOM nodes so the commit is inserted as text. AI-Generated: Claude Opus 5.5 Signed-off-by: Tim Orling --- Post/static/js/main.js | 14 +++++++++++--- Post/test.py | 35 +++++++++++++++++++++++++++++++++++ templates/latest-errors.html | 7 +------ 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/Post/static/js/main.js b/Post/static/js/main.js index 5c07ad5..546aabe 100644 --- a/Post/static/js/main.js +++ b/Post/static/js/main.js @@ -219,9 +219,16 @@ $(document).ready(function(){ $("#errors-table").show(); + /* Insert the submitted commit as text, not HTML. */ $('.commit > div').popover({ placement:'left', - html: true + html: true, + content: function () { + var commit = $(this).attr('data-commit'); + var link = $('Filter by commit') + .attr('data-filter', commit); + return $('
').append($('').text(commit), $('

').append(link)); + } }); $(".recipe_version a.tooltip-me").tooltip(); @@ -267,8 +274,9 @@ $(document).ready(function(){ e.stopPropagation(); }); - $(".icon-filter").tooltip({ container: 'body', html: true }); + /* Titles hold submitted data: keep them text. */ + $(".icon-filter").tooltip({ container: 'body' }); // initialise the remove filter tooltips - $("th .btn-mini").tooltip({ container: 'body', html: true, title:'Clear filter' }); + $("th .btn-mini").tooltip({ container: 'body', title:'Clear filter' }); }); diff --git a/Post/test.py b/Post/test.py index f48beec..0a358d1 100755 --- a/Post/test.py +++ b/Post/test.py @@ -432,6 +432,41 @@ class AccountPagesRemovedTest(TestCase): self.assertEqual(client.get("/admin/login/").status_code, 200) +@override_settings(ALLOWED_HOSTS=["testhost"]) +class SubmittedHtmlTest(TestCase): + """Submitted data must only ever reach the page escaped.""" + + def submit(self, **fields): + with open("test-data/test-payload.json") as f: + payload = json.load(f) + payload.update(fields) + payload['failures'][0]['package'] = 'evil-1.0' + payload['failures'][0]['task'] = 'do_evil' + client = Client(HTTP_HOST="testhost") + data = urllib.parse.urlencode({'data': json.dumps(payload)}) + self.assertEqual(client.post("/ClientPost/", data, "application/json").status_code, 200) + return client, BuildFailure.objects.get() + + def test_failure_fields_are_escaped(self): + client, bf = self.submit() + response = client.get("/Errors/Latest/") + self.assertNotContains(response, "evil") + self.assertContains(response, "Filter by <b>evil</b>: do_<b>evil</b>") + + def test_commit_is_not_in_html_attributes(self): + client, bf = self.submit(branch_commit="master: evil") + response = client.get("/Errors/Latest/") + self.assertNotContains(response, "evil") + self.assertContains(response, 'data-commit="<b>evil</b>"') + # With html enabled, Bootstrap inserts these as HTML. + self.assertNotContains(response, "data-content") + self.assertNotContains(response, "data-html") + + def test_tooltips_are_not_html(self): + with open("Post/static/js/main.js") as f: + self.assertNotRegex(f.read(), r"tooltip\(\{[^}]*html: true") + + @patch("Post.management.commands.culldb.time.sleep") class CullDbTest(TestCase): def setUp(self): diff --git a/templates/latest-errors.html b/templates/latest-errors.html index 2080210..d9c2890 100644 --- a/templates/latest-errors.html +++ b/templates/latest-errors.html @@ -189,12 +189,7 @@ -

+
{{ build_fail.BUILD.COMMIT|truncatechars:10}}
From patchwork Sun Oct 18 02:03:56 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Orling X-Patchwork-Id: 101176 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9723CCCF2C4 for ; Sun, 18 Oct 2026 02:06:26 +0000 (UTC) Received: from mail-pj1-f45.google.com (mail-pj1-f45.google.com [209.85.216.45]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.8016.1792289178525945327 for ; Sat, 17 Oct 2026 19:06:18 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20251104 header.b=PR74bS8W; spf=pass (domain: gmail.com, ip: 209.85.216.45, mailfrom: ticotimo@gmail.com) Received: by mail-pj1-f45.google.com with SMTP id 98e67ed59e1d1-398a4dcf289so569684a91.2 for ; Sat, 17 Oct 2026 19:06:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792289178; x=1792893978; darn=lists.yoctoproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=RlT13S1OEXMnwWEPOPM5zDklmSAdD00qmkKyU2B6cVA=; b=PR74bS8WQycq66mzef4qOMPLHC3OBM2qLgK8QEMcDhjBD6/KUbE4GDZZM8UGWuhMPJ DVXqloy2YK8++UWoF0RQKXOVIyK3bmenNHKEce1f8Yt5Xn+n0ElogvSCv9peufXGDZuX CHvbf1qZJqha8hiVvr+nwwalM2tZkan0M0H8aHVAdtXpuG8MxrLjgCwTexczh4Waa99C Vv3ilGgHrcptdl3/PBPxzA5j5lbnaZcCzbPkDifZL81b+jxEV3yMAUNn0srM/xbXgcbQ AyqeMh3Qdn8gUOVDR/17IPUp87dfZRkyltdEPVObhIiPoKSQUkAYRQ9nHhSNJZ/EP/fr mYhw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792289178; x=1792893978; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=RlT13S1OEXMnwWEPOPM5zDklmSAdD00qmkKyU2B6cVA=; b=jH1Om6lZ4gJTBI2fi0d6Yp9p4eSxmLYs8LKgMJxk/fyGPQkOLwN1G1NH96iusgPLJa OKf9FfzeiEOYJEJl9o/5MXSoBs7xRkZmduqGLvOuvz2FEzPXMsn+44QI3hqcTa+3XAXD dxc6JDX5cRdHyPTt+sS5+mzMx757ofM237HrCj4YB6Q7Qt6azYm0j3hD4AFn4a3dyfO5 ceDtqyHv+gu3FIVu/srxdYJrLqdJKeXN5hj/+VVSxKIlxCMLJPQH3quQRSOFNzXQhLyM atp0pLsmznXrXNTJSWTcIdfpobQ0y0POVor1XcJMS/cdayGqo616M4JU1TDqpmtTxzgE a68Q== X-Gm-Message-State: AFq9FYL/8M9klwKCRs/4Ug/16xTCNaP4lsZxSIFDGtH97UaU9HzB2RQR y/jdteahSzVL39vJMT2op5xPPkXsnbPk4zNHcpoqJZuVMXYoatxIpw0L3mooFnc/ X-Gm-Gg: AYBFou3FvnBCgH/oWqVbnRbzLRl6ENloGO7smtdkuT6oPCxQds4B4OrVW4Cy++AXIAJ hRokgYy4IwWBmBh7HNRmtSESTbm8lzpB8c7MrbZB4g3la8LTleJt8+AFZ+W0sLmRLNfw6hvYW/C 7GwqKKFfRcsb9wSEC5F0MCVzc1Sr1H+Zx/V+4yVdVmljvxCyTKc7lV0f1RqL/Q3vy/RjYM7BYRm m2LSHN8i2SRFDR4CkrCBU3e51vQZsSSxLiwefnoLDHDxeSo9ccPj7pqprAimakEX+l0ZuBfgh4J zXD7+4gxiSWdw3fxPqwNx7l3iTy5P1nYCd99yb/7TmuEb1B2O0SxoxluqzoXBqeSBZX8wV012Hx ULYeFrI5EGf9Kno7y6kV7w2khI/+JnOi0rlKSgji1OhPmkMrtvqlAMjcmz3rhA2SNTUyAf+9kDd y2MdpyI++amn+hv0BneRqvZkH5eC0FuJZtEM4nF+xgjb8IX6Jq9V7nuakuHiUpUHeYuzm/ywepn 1qooLKAtA9nkHJGeW0p7QlBO40yoDk= X-Received: by 2002:a17:90b:3ec5:b0:3a8:13d6:f740 with SMTP id 98e67ed59e1d1-3aceec259d1mr3594047a91.22.1792289177863; Sat, 17 Oct 2026 19:06:17 -0700 (PDT) Received: from localhost.localdomain ([69.9.132.159]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3acc98139ccsm5775584a91.0.2026.10.17.19.06.14 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sat, 17 Oct 2026 19:06:16 -0700 (PDT) From: Tim Orling X-Google-Original-From: Tim Orling To: yocto-patches@lists.yoctoproject.org Cc: Tim Orling Subject: [error-report-web][PATCH 2/2] Remove bleach and store submitted data as sent. Date: Sat, 17 Oct 2026 19:03:56 -0700 Message-ID: <20261018020518.76802-5-tim.orling@konsulko.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261018020518.76802-1-tim.orling@konsulko.com> References: <20261018020518.76802-1-tim.orling@konsulko.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Sun, 18 Oct 2026 02:06:26 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/5068 bleach stored escaped text, so "<" or "&" showed as "<" or "&". Escaping on output covers every place the data is shown, and bleach is deprecated. Existing reports keep their escaped text. AI-Generated: Claude Opus 5.5 Signed-off-by: Tim Orling --- Post/parser.py | 10 ---------- Post/test.py | 10 ++++++++++ requirements.txt | 1 - 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Post/parser.py b/Post/parser.py index 092ce24..e221bcf 100644 --- a/Post/parser.py +++ b/Post/parser.py @@ -10,7 +10,6 @@ import json import re -import bleach from Post.models import Build, BuildFailure, ErrorType from Post.validators import clean_link_back from django.conf import settings @@ -30,15 +29,6 @@ class Parser: except Exception: return { 'error' : 'Invalid json' } - # Bleach data going directly into the database so that - # displaying in any of the graphing doesn't introduce XSS - for key,val in jsondata.items(): - if key == 'failures': - continue - if not isinstance(val, str): - continue - jsondata[key] = bleach.clean(val) - b = Build.objects.create() try: b.MACHINE = str(jsondata['machine']) diff --git a/Post/test.py b/Post/test.py index 0a358d1..51ae0b9 100755 --- a/Post/test.py +++ b/Post/test.py @@ -462,6 +462,16 @@ class SubmittedHtmlTest(TestCase): self.assertNotContains(response, "data-content") self.assertNotContains(response, "data-html") + def test_build_fields_are_stored_as_sent_and_escaped(self): + client, bf = self.submit(machine="") + # Stored as sent; escaped on output. + self.assertEqual(bf.BUILD.MACHINE, "") + for url in ("/Errors/Latest/", "/Errors/Details/%d/" % bf.id, + "/Errors/Statistics/MACHINE"): + response = client.get(url) + self.assertEqual(response.status_code, 200, url) + self.assertNotContains(response, "