Skip to content

[finding] GET /api/v1/ui/view/:object/:type resolves a UI view with no identity resolution and no anonymous-deny at the REST seam #13214

Description

@os-trump

Found out of scope by the #13160 dev (PR #13213) while driving every mounted route of RestServer under an absent execution context. ⛔ Reported, not touched — access-control behaviour is a human floor, and this is outside that card by construction (it is not a resolveExecCtx consumer, which is exactly why the census surfaced it: it is the one metadata-touching route in the table that resolves no identity at all).

Ungraded and unrouted. Severity not judged here.

Measured

packages/rest/src/rest-server.ts, registerUiEndpoints (the handler for GET /api/v1/ui/view/:object/:type):

  • it calls this.resolveProtocol(...) and then p.getUiView({ object, type, environmentId });
  • it does not call this.resolveExecCtx;
  • it does not call this.enforceAuth;
  • it passes no execution context to getUiView, so the protocol cannot apply RLS/FLS/tenant scoping on the caller's behalf.

Driven on the real registerRoutes() route table with a stub protocol: the route answers 200 identically with an absent context and with an entitled one, and records zero resolveExecCtx calls. Every other identity-touching route in that table answers 401 UNAUTHENTICATED under an absent context (that is PR #13213's census, 52 of 52 plus the metadata umbrella).

⚠️ What is NOT measured

Whether getUiView applies authorization of its own downstream. The reading above is about the REST seam only. It is entirely possible this route is deliberately public, or gated inside the protocol — neither was checked, and ⛔ this card asserts no vulnerability.

Two specific things worth checking before grading:

  1. isAuthGateAllowlisted (packages/core/src/security/auth-gate.ts) does not name a /ui path, so this is not the declared control-plane exemption.
  2. packages/qa/dogfood/test/authz-conformance.matrix.ts carries no row for this route. Its header says a new ungated route is UNCLASSIFIED and breaks CI — so either discover()'s curated per-file probe table does not reach registerUiEndpoints, or this route is covered by a row that does not name it. Which of those is true decides whether this is a route gap or a ratchet gap, and the second would be the larger finding.

Re-check

git grep -n "registerUiEndpoints" -- packages/rest/src/rest-server.ts
git grep -n "getUiView" -- packages/rest/src packages/qa
git grep -n "ui" -- packages/core/src/security/auth-gate.ts

⛔ Reverse-check any zero with a term known present in the same file — enforceAuth is present in rest-server.ts and registerUiEndpoints sits directly above registerCrudEndpoints, whose handlers all carry the guard.

Refs

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions