High priority fixes: - T0: Profile page now filters comments by namespace (was leaking cross-site) - T1: URI hostnames and namespace names normalized to lowercase (was causing duplicate threads and "stock comments" bug). Includes merge script. - T2: Thread detail API now paginated with SQL-side filtering (was 502 on 267+ reply threads) Features: - T3: GDPR account deletion (tombstone user with scrubbed PII) and data export - T4: Customizable button text and comment labels per namespace - T5: Self-service namespace deletion for owners - T6: @mention notifications with profile links - T7: Webmention receiving endpoint with h-card extraction - T8: Configurable max nesting depth and collapse depth per namespace - T9: AJAX thread title search to prevent duplicates - T10: Browser push notification support (VAPID/service worker) Docs and housekeeping: - T11: Documented thread_uri behavior when moving embeds - T12/T13: Drafted community replies for resolved feature requests - Collapse depth defaults to infinite (load-more disabled unless configured) 364 tests pass, 4 skipped.
2.2 KiB
T0: User profile leaks comments across namespaces
Status: resolved
Priority: high
Source: meta cc62eb06-8e4b-11ea-93cc-040140774501
Filed: 2026-02-01
Problem
Clicking a username on any site with Remarkbox installed shows ALL that user's comments from every namespace. A commenter on site A can see all their comments from sites B, C, D on the profile page. Russell marked the original thread as fixed, but the code still has no namespace filtering.
Xii also reported that unapproved comments leaked cross-namespace. The approved == True filter in page_nodes() now prevents that specific leak, but the cross-namespace exposure remains.
Root Cause
User.page_nodes() in remarkbox/models/user.py:266-276 queries all nodes for a user with no namespace filter:
def page_nodes(self, limit=100, offset=0):
return (
self.nodes.filter(
Node.disabled == False, Node.verified == True,
Node.user_id != None, Node.approved == True
)
.order_by(Node.changed.desc())
.limit(limit)
.offset(offset)
)
The user_nodes() view in remarkbox/views/list_nodes.py:114-137 calls subject_user.page_nodes() without passing any namespace context. The same issue affects verified_nodes, unverified_nodes, disabled_nodes, and unapproved_nodes properties on the User model.
Proposed Fix
- Add a
namespaceparameter toUser.page_nodes()that filtersNode.namespace_id == namespace.id - Update
user_nodes()view to passrequest.namespace(or derive it from the embed/site context) - Apply namespace filtering to the other User node properties used in views
- Ensure namespace-specific settings (
hide_unless_approved,hide_unverified) are respected
Files
remarkbox/models/user.py— add namespace filter topage_nodes()and related propertiesremarkbox/views/list_nodes.py— pass namespace context to user queriesremarkbox/tests/test_views.py— regression test: user profile only shows same-namespace comments
Acceptance Criteria
- User profile page only shows comments from the current namespace
- Namespace moderation settings are respected on the profile page
- Regression test prevents reintroduction