From aed94fa5442812ff3da843fa3d7abcdf5d346a89 Mon Sep 17 00:00:00 2001
From: seonghobae <8172694+seonghobae@users.noreply.github.com>
Date: Sun, 27 Sep 2026 19:01:09 +0000
Subject: [PATCH 01/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?=
=?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?=
=?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?=
=?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.jules/palette.md | 4 ++++
scanner/dashboard/index.html | 2 +-
tests/test_dashboard_core.py | 6 ++++++
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.jules/palette.md b/.jules/palette.md
index ea004e2d2..be75988f2 100644
--- a/.jules/palette.md
+++ b/.jules/palette.md
@@ -81,3 +81,7 @@
## 2026-08-12 - Skip to Content Accessibility
**Learning:** Screen reader and keyboard-only users experience significant friction when forced to navigate through repetitive header controls on every page load.
**Action:** Keep a visible-on-focus skip link as the first interactive element, target a programmatically focusable main container, and give the focused link a high-contrast outline.
+
+## 2026-09-02 - target=_blank external link accessibility
+**Learning:** Links opening in a new tab without context are inaccessible. Users using screen readers may not realize they have opened a new tab and lose the navigation history. Using an English-only `aria-label` override breaks translations.
+**Action:** When creating `target="_blank"` external links, add an assistive-technology warning via `.sr-only` text and a visible indicator (like an `aria-hidden` icon) inside the anchor tag to ensure WCAG compliance and preserve localization logic.
diff --git a/scanner/dashboard/index.html b/scanner/dashboard/index.html
index 132bc31b2..24cbdf36d 100644
--- a/scanner/dashboard/index.html
+++ b/scanner/dashboard/index.html
@@ -281,7 +281,7 @@
Dashboard
function openDetail(f){
lastFocus = document.activeElement;
const s = String(f.severity||'INFO').toUpperCase();
- const refs = (f.references||[]).map(r=>`${esc(r)}`).join('
');
+ const refs = (f.references||[]).map(r=>`${esc(r)} (opens in a new tab)↗`).join('
');
const owasp = (f.owasp||[]).join(', ');
const cwe = (f.cwe||[]).join(', ');
const d = document.getElementById('detail');
diff --git a/tests/test_dashboard_core.py b/tests/test_dashboard_core.py
index 75a5809f8..597203ea1 100644
--- a/tests/test_dashboard_core.py
+++ b/tests/test_dashboard_core.py
@@ -302,3 +302,9 @@ def test_dashboard_search_escape_clears_input():
assert "e.key === 'Escape'" in html
assert "query = '';" in html
assert "render();" in html
+
+def test_dashboard_external_links_have_a11y_warnings():
+ """External links with target=_blank must warn screen readers and visual users."""
+ html = dashboard_index_path().read_text(encoding="utf-8")
+ assert '(opens in a new tab)' in html
+ assert '↗' in html
From 3e95c23e00e63861d42784eed92334dd8cd743a9 Mon Sep 17 00:00:00 2001
From: seonghobae <8172694+seonghobae@users.noreply.github.com>
Date: Sun, 27 Sep 2026 21:23:28 +0000
Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?=
=?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?=
=?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?=
=?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From 7d15f73ea75f91cc77889486d41ce8185fcbd262 Mon Sep 17 00:00:00 2001
From: seonghobae <8172694+seonghobae@users.noreply.github.com>
Date: Sun, 27 Sep 2026 23:31:50 +0000
Subject: [PATCH 03/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?=
=?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?=
=?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?=
=?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From fc6f7e477ea9f5a24bb83b0307025b9f8b023c4d Mon Sep 17 00:00:00 2001
From: seonghobae <8172694+seonghobae@users.noreply.github.com>
Date: Mon, 28 Sep 2026 02:13:06 +0000
Subject: [PATCH 04/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?=
=?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?=
=?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?=
=?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From be18d56f400da4b45c427c3bd45d1491a9832a2e Mon Sep 17 00:00:00 2001
From: seonghobae <8172694+seonghobae@users.noreply.github.com>
Date: Mon, 28 Sep 2026 13:27:12 +0000
Subject: [PATCH 05/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?=
=?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?=
=?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?=
=?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From 07374318849eaa3b1be815af561b5ced346133de Mon Sep 17 00:00:00 2001
From: seonghobae <8172694+seonghobae@users.noreply.github.com>
Date: Mon, 28 Sep 2026 20:05:50 +0000
Subject: [PATCH 06/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?=
=?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?=
=?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?=
=?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From 6c6c990be6bde459fc394745808965454afe1658 Mon Sep 17 00:00:00 2001
From: seonghobae <8172694+seonghobae@users.noreply.github.com>
Date: Tue, 29 Sep 2026 04:22:58 +0000
Subject: [PATCH 07/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?=
=?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?=
=?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?=
=?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From ab76202cbb00c913a3ae2e0b817b144ca193c432 Mon Sep 17 00:00:00 2001
From: seonghobae <8172694+seonghobae@users.noreply.github.com>
Date: Wed, 30 Sep 2026 05:31:25 +0000
Subject: [PATCH 08/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?=
=?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?=
=?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?=
=?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From b12542fb7381456fafeb6c9f1728c460a2035a28 Mon Sep 17 00:00:00 2001
From: Seongho Bae
Date: Sat, 3 Oct 2026 17:56:46 +0900
Subject: [PATCH 09/11] chore: retire duplicate .jules/palette.md delta in
favor of #1361
---
.jules/palette.md | 4 ----
1 file changed, 4 deletions(-)
diff --git a/.jules/palette.md b/.jules/palette.md
index be75988f2..ea004e2d2 100644
--- a/.jules/palette.md
+++ b/.jules/palette.md
@@ -81,7 +81,3 @@
## 2026-08-12 - Skip to Content Accessibility
**Learning:** Screen reader and keyboard-only users experience significant friction when forced to navigate through repetitive header controls on every page load.
**Action:** Keep a visible-on-focus skip link as the first interactive element, target a programmatically focusable main container, and give the focused link a high-contrast outline.
-
-## 2026-09-02 - target=_blank external link accessibility
-**Learning:** Links opening in a new tab without context are inaccessible. Users using screen readers may not realize they have opened a new tab and lose the navigation history. Using an English-only `aria-label` override breaks translations.
-**Action:** When creating `target="_blank"` external links, add an assistive-technology warning via `.sr-only` text and a visible indicator (like an `aria-hidden` icon) inside the anchor tag to ensure WCAG compliance and preserve localization logic.
From 9b559723732cda77e71b43028dc22874ff6171fe Mon Sep 17 00:00:00 2001
From: Seongho Bae
Date: Sat, 3 Oct 2026 17:56:48 +0900
Subject: [PATCH 10/11] chore: retire duplicate scanner/dashboard/index.html
delta in favor of #1361
---
scanner/dashboard/index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scanner/dashboard/index.html b/scanner/dashboard/index.html
index 24cbdf36d..132bc31b2 100644
--- a/scanner/dashboard/index.html
+++ b/scanner/dashboard/index.html
@@ -281,7 +281,7 @@ Dashboard
function openDetail(f){
lastFocus = document.activeElement;
const s = String(f.severity||'INFO').toUpperCase();
- const refs = (f.references||[]).map(r=>`${esc(r)} (opens in a new tab)↗`).join('
');
+ const refs = (f.references||[]).map(r=>`${esc(r)}`).join('
');
const owasp = (f.owasp||[]).join(', ');
const cwe = (f.cwe||[]).join(', ');
const d = document.getElementById('detail');
From 63c4a40618a7bfa4ccead6d948de0c593e6fafd1 Mon Sep 17 00:00:00 2001
From: Seongho Bae
Date: Sat, 3 Oct 2026 17:56:50 +0900
Subject: [PATCH 11/11] chore: retire duplicate tests/test_dashboard_core.py
delta in favor of #1361
---
tests/test_dashboard_core.py | 6 ------
1 file changed, 6 deletions(-)
diff --git a/tests/test_dashboard_core.py b/tests/test_dashboard_core.py
index 597203ea1..75a5809f8 100644
--- a/tests/test_dashboard_core.py
+++ b/tests/test_dashboard_core.py
@@ -302,9 +302,3 @@ def test_dashboard_search_escape_clears_input():
assert "e.key === 'Escape'" in html
assert "query = '';" in html
assert "render();" in html
-
-def test_dashboard_external_links_have_a11y_warnings():
- """External links with target=_blank must warn screen readers and visual users."""
- html = dashboard_index_path().read_text(encoding="utf-8")
- assert '(opens in a new tab)' in html
- assert '↗' in html