fix(board): a link row could rewrite the dialog that authorises its deletion

Found by design-dev, the same class as the wipe dialog he had just fixed on the
Desk, and reported across the fence rather than kept.

A board row's description and URL are written by any of seventeen agent handles
and were pasted RAW into the `confirm()` the operator reads before approving a
delete. A bidi override (U+202E) or a newline in either re-orders or hides what
he is consenting to, so the row shown is not the row removed.

Escaping does nothing here and that is the trap: autoescape protects the PAGE,
but `confirm` renders a plain string, so the markup defence everyone reaches for
first is irrelevant to the surface that actually carries the decision.

Control and bidi formatting characters now render as U+FFFD — visibly mangled,
never silently re-ordered — through the same helper shape design-dev used, so
the two dialogs cannot drift apart.

Both arguments go through it, and the mutation row defeats exactly that: taking
the raw description back for one of the two turns the test red. 763 green.
This commit is contained in:
vh
2026-09-23 11:31:20 -07:00
parent 995e7b9686
commit 65e7dc2a4e
3 changed files with 52 additions and 2 deletions
+9
View File
@@ -203,3 +203,12 @@ old = '''
return parts.scheme.lower() in ("http", "https")'''
new = '''
return True'''
[[mutation]]
label = "the board delete dialog takes the raw agent-written description"
file = "booth/templates/booth.html"
test = "tests/test_booth.py::test_the_board_delete_dialog_cannot_be_rewritten_by_a_link_row"
old = '''
var d = shown(btn.getAttribute('data-desc') || '');'''
new = '''
var d = btn.getAttribute('data-desc') || '';'''