summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/tests/test_security_regressions.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/tests/test_security_regressions.py')
-rw-r--r--packages/meshbay-node/tests/test_security_regressions.py23
1 files changed, 23 insertions, 0 deletions
diff --git a/packages/meshbay-node/tests/test_security_regressions.py b/packages/meshbay-node/tests/test_security_regressions.py
index 6bb680c..dcd9cf6 100644
--- a/packages/meshbay-node/tests/test_security_regressions.py
+++ b/packages/meshbay-node/tests/test_security_regressions.py
@@ -579,3 +579,26 @@ def test_admin_ui_escapes_filenames(tmp_path):
assert payload not in html, "filename rendered unescaped — stored XSS (H2)"
assert "<img" in html, "filename should appear escaped"
+
+def test_admin_ui_escapes_roster_usernames(tmp_path):
+ """
+ H2 again, for the roster: usernames originate at the hub and land on the
+ operator's own admin page, which can re-key groups and read the audit log.
+ """
+ from meshbay_node.ui.app import _render_page
+
+ payload = '<img src=x onerror="fetch(1)">'
+ html = _render_page(
+ {"status": "running", "groups_ctx": {}, "indexes": {}},
+ {
+ "identities": {"u1": {"user_id": "u1", "username": payload,
+ "pk_ed25519": "AAA", "pinned_at": "now",
+ "pinned_via": "code"}},
+ "members": [{"group_id": "", "user_id": "u1", "role": "operator",
+ "status": "active"}],
+ "invites": [],
+ },
+ )
+
+ assert payload not in html, "username rendered unescaped — stored XSS (H2)"
+ assert "&lt;img" in html