From dad21ff257c9c294348ab83ab3634e7f4bf9dac4 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 18:19:16 +0000 Subject: [PATCH] sec(tasks): draft task for zero-trust scope guards Drafts a comprehensive task specification for implementing zero-trust scope guards on internal API routes and SSR UI pages, as requested. The file adheres strictly to the repository's Kanban and Markdown metadata guidelines. Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com> --- ...c.auth-api.zero-trust-scope-guards-1805.md | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tasks/new/2026-0825.01.jul.sec.auth-api.zero-trust-scope-guards-1805.md diff --git a/tasks/new/2026-0825.01.jul.sec.auth-api.zero-trust-scope-guards-1805.md b/tasks/new/2026-0825.01.jul.sec.auth-api.zero-trust-scope-guards-1805.md new file mode 100644 index 0000000..cc1c90d --- /dev/null +++ b/tasks/new/2026-0825.01.jul.sec.auth-api.zero-trust-scope-guards-1805.md @@ -0,0 +1,56 @@ +# TASK METADATA + +- **Target Files:** `server/auth-session.ts`, `server/routes/sessions.ts`, `server/routes/events.ts`, `server/main.ts`, `ui/mod.ts`, `server/main.test.ts` +- **Core Objective:** Implement strict Zero-Trust scope enforcement and permission guards across all Auth-Yes internal API routes and SSR UI pages to ensure delegated and read-only sessions cannot escalate privileges, perform unauthorized mutations, or access admin interfaces. +- **Dependencies:** None +- **Additional Important Notes:** Delegated sessions (`is_agent = true`) must hold strictly the intersection of user permissions and assigned `custom_scopes`. Self-revocation of a delegated session is permitted, but revoking other sessions is prohibited without `write:sessions` or `*`. + +--- + +## Architectural Considerations & Risks + +- **Risks:** + - **Backward-Compatibility with Cached Sessions:** Existing delegated sessions in the Valkey cache might lack explicit scopes if they were created before this strict enforcement. The middleware must default to a safe deny state for unknown or missing scopes but handle legacy `is_agent = true` sessions gracefully by denying mutating actions unless explicitly permitted. + - **Self-Revocation Edge Case:** The guard logic must correctly distinguish between a session revoking itself (which is always allowed for clean logouts) and a session attempting to revoke a sibling or parent session. + - **Global Admin Resolution:** The `isGlobalAdmin` check relies on database queries or cache. Ensure that the new middleware does not introduce significant latency by repeatedly querying PostgreSQL on every protected route. Use Valkey caching where possible. + +- **Alternatives:** + - Instead of injecting `customScopes` into the Valkey cache session payload, we could perform a database lookup on every privileged API request to determine exact grants. However, this violates the Auth-Yes architectural principle of fast-path caching at the edge and would significantly degrade performance. The chosen approach of checking scopes from the cached `AuthenticatedUser` object is highly modular and performant. + +## Proposed Implementation + +### 1. Scope Guard Helpers (`server/auth-session.ts`) +Implement reusable composable functions to evaluate the current user's capabilities. +- `hasScope(auth: AuthenticatedUser, requiredScope: string): boolean`: Evaluates if `auth.customScopes` contains `*` or the `requiredScope`. If `!auth.isAgent`, returns `true` (primary sessions have all capabilities). +- Create Hono middleware helpers: + - `requirePrimarySession()`: Denies access with `403 Forbidden` if `auth.isAgent === true`. + - `requireScope(scope: string)`: Denies access if `hasScope(auth, scope)` returns false. + - `requireAdmin(auth: AuthenticatedUser)`: Uses `isGlobalAdmin(auth.userId)` and verifies `!auth.isAgent` OR `auth.customScopes.includes("*")`. + +### 2. Guard Internal API Routes +Apply the newly created guards to critical endpoints. + +- **`server/routes/sessions.ts`** + - `DELETE /api/sessions/:id`: Allow if target `id === auth.sessionId`. Otherwise, require `write:sessions` scope. + - `PUT /api/sessions/:id/scopes`: Require `admin` or `*` scope, OR `write:sessions`. + - `POST /api/sessions/:id/extend`: Require `write:sessions` or `*`. + - `POST /api/sessions/delegate`: Prevent privilege escalation. Require `admin` or `*` scope to delegate an `admin` mode session. If creating a `read_only` or `operator` session, require the delegator to have at least those equivalent scopes. + +- **`server/routes/events.ts`** + - `POST /api/events`: Require `write:events` or `*`. + - `POST /api/events/:id/end`: Require `write:events` or `*`. + - `POST /api/events/:id/extend`: Require `write:events` or `*`. + +- **`server/main.ts`** + - Apply `requirePrimarySession()` or `requireAdmin()` to `/api/admin/*` and `/api/passkeys/*` endpoints. + +### 3. SSR UI Gates (`ui/mod.ts`) +Guard the user interfaces against unauthorized delegated sessions. +- `/admin/*`: Verify `isAdmin && (!auth.isAgent || auth.customScopes.includes("*"))`. Redirect unauthorized sessions to `/dashboard` or return a `403 Forbidden` page. +- `/dashboard/passkeys`: Verify `!auth.isAgent`. Delegated sessions cannot manage passkeys. + +### 4. Testing (`server/main.test.ts`) +- Write tests that create a delegated session with only `read_only` scopes. +- Assert that this session gets a `403 Forbidden` when attempting to call `POST /api/sessions/delegate`, `DELETE /api/sessions/:other_id`, and `POST /api/events`. +- Assert that the delegated session can successfully call `DELETE /api/sessions/:own_id`. +- Write tests verifying that a delegated session attempting to access `/admin/users` is redirected/blocked. \ No newline at end of file