Skip to content

Inconsistent visibility for private/invited users: inaccessible nodes listed in 'last edited', invited module missing from navigation, search and access menu expose users #385

Closed

Description

@rosalie1984

Context

Follow-up to #384. After completing sign-in as a private user (invited via private email, Google sign-in), the portal itself loads and generally looks OK — but node visibility is inconsistent with the user's actual access rights, in both directions (shows too much, and too little).

Problem 1 — 'Last edited' feed lists nodes the user has no access to

The portal's last-edited nodes view shows nodes that the private user cannot access. Access being denied on open is correct — but these nodes should not be listed at all. Showing their existence/titles/paths to an unauthorized user is a metadata leak; row-level security should filter the last-edited feed the same way it filters direct reads.

Problem 2 — Invited module 'Agentic Engineering' does not appear as a node

The user was explicitly invited to the educational module Agentic Engineering, but it does not show up as a node anywhere in the portal (navigation / node listings). Navigating directly via the browser URL works and access is granted as expected — so the permission itself is in place, only the discovery/navigation surface misses it. Invited-to content should be visible in navigation, otherwise invitees can only reach it via out-of-band links.

Problem 3 — Search exposes users of the educational program

When reaching the module via search instead of the direct URL, the search results included user nodes of other participants in the educational program. A private invitee should not be able to see (or enumerate) other users; these should be excluded from their search results entirely.

Problem 4 — Access menu lists all users of the space

The access menu shows the private user all users of the space. A private invitee should not be able to enumerate the space's user base from the access/sharing UI — the user picker / access list should be restricted (e.g. to users they legitimately need to see, or hidden entirely for users without manage-access rights).

Expected behavior

One consistent access model across all surfaces — direct navigation, 'last edited' feed, navigation tree, search, and the access menu should all reflect exactly what the user is entitled to see:

  • No listing of inaccessible nodes in feeds or search (Problems 1 and 3).
  • Content the user IS entitled to (invited module) discoverable in navigation, not only via direct URL (Problem 2).
  • No enumeration of the space's users via the access menu (Problem 4).

Notes

  • Problems 1, 3 and 4 are the security-relevant half (information disclosure / user enumeration); Problem 2 is a UX/consistency gap.
  • Suggests the row-level-security filter is applied on direct node reads but not (or differently) on the last-edited query, the navigation tree source, the search index results, and the access-menu user list.
  • May be worth splitting into separate issues if the fixes land in different components.

Reported by @rsalzmann (observed with a freshly invited private-email account).

Activity

  1. changed the title [-]Inconsistent visibility for private/invited users: inaccessible nodes listed in 'last edited', invited module missing from navigation, search exposes program users[/-] [+]Inconsistent visibility for private/invited users: inaccessible nodes listed in 'last edited', invited module missing from navigation, search and access menu expose users[/+] on Jul 9, 2026
  2. rbuergi commented on Jul 18, 2026

    @rbuergi
    Contributor

    Shares roots with #471 — see the full RCA there. This issue's four symptoms map to: inaccessible nodes in 'Last edited' = RC3 (the BuildPerSchemaAccessClause public_read-outside-partition-gate outlier at PostgreSqlSqlGenerator.cs:697-700, vs the documented partition_access AND (public_read OR node) invariant); search/access-menu expose users = RC2 (User is WithPublicRead + the auth-mirror route); invited module missing from navigation = RC4 (no query enumerates the caller's cross-partition AccessAssignments). RC2+RC3 land together (same auth path); RC4 is additive. Holding for maintainer greenlight given the access-model blast radius.

  3. rbuergi commented on Jul 18, 2026

    @rbuergi
    Contributor

    Resolved via #536 (merged) + #521. RC3 (inaccessible nodes in 'Last edited' / cross-partition public-read feed leak) fixed by aligning the access clause; RC4 (invited module missing from navigation) shipped as a 'Shared with me' nav tab sourcing the caller's cross-partition AccessAssignments; the search/access-menu user exposure is bounded by the email redaction (#521). The remaining user-enumeration hardening (name-only projection) was consciously declined — see the disposition on #471. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions