test: lock attribute-context quote escaping in web_ui hostile-field test

The escaping regression lock asserted only the element-context vector
(raw <script> absent, &lt;script&gt; present) while its docstring claimed
quotes were covered -- the payload's " and ' were never asserted on, so
a quote-escaping regression on the onclick row-link sink (attribute
breakout -> event-handler injection) would have passed green.
/sh-security-review finding WC-01 (confirmed medium, test-integrity).

Add assertions that the onclick sink's JSON string renders its opening
quote as &quot; (raw " after window.location= fails), that the
payload's quote characters appear only entity-escaped, and that the
raw payload never appears anywhere in the body. Mutation-verified: the
test now fails when the sink's quote-escaping is dropped.
This commit is contained in:
Adam Moussa 2026-07-20 14:53:17 -04:00
parent cdc7f30c4a
commit d48f06e20e
No known key found for this signature in database

View file

@ -116,13 +116,27 @@ def test_authenticated_render_path(web_ui, monkeypatch):
def test_hostile_fields_are_escaped_not_reflected_raw(web_ui, monkeypatch):
"""Regression lock: hostile field values must reach the HTML only as escaped
entities -- no raw <script>, and the payload's angle brackets must appear
escaped."""
entities -- no raw <script> in element context, and the payload's quotes
must be entity-escaped in attribute context (the onclick row-link sink), or
a " breaks out of the attribute value and injects an event handler."""
monkeypatch.setattr(web_ui.mod, "is_authenticated", lambda event: True)
monkeypatch.setattr(
web_ui.mod, "dynamodb", _WebFakeDynamo({web_ui.table: [web_ui.hostile_item]})
)
body = web_ui.mod.handler({}, None)["body"]
# element context: angle brackets escaped
assert "<script>alert(1)</script>" not in body # never reflected raw
assert "&lt;script&gt;alert(1)&lt;/script&gt;" in body # escaped form present
# attribute context: the id flows through json.dumps into
# onclick="window.location={esc(..., quote=True)}", so the JSON string's
# opening quote must render as &quot; -- a raw " right after the = means
# quote-escaping regressed and the attribute is breakable
assert "window.location=&quot;" in body
assert 'window.location="' not in body
# the payload's own quote characters appear only entity-escaped
assert "&quot;" in body
assert "&#x27;" in body
assert _HOSTILE not in body