Skip to content

Harden role & permission authorization boundaries; add RLS migration and tests - #15

Open
ethandemouradev wants to merge 1 commit into
mainfrom
codex/start-security-hardening-pass
Open

Harden role & permission authorization boundaries; add RLS migration and tests#15
ethandemouradev wants to merge 1 commit into
mainfrom
codex/start-security-hardening-pass

Conversation

@ethandemouradev

Copy link
Copy Markdown
Contributor

Motivation

  • Close privilege-escalation and permission-granting gaps by enforcing server-side hierarchy and known-key checks for role and permission management.
  • Prevent browser-side grants or object-id enumeration from exposing staff/customer-sensitive data and prepare a safe migration to tighten RLS/grants.

Description

  • Add canonical hierarchy guards: canManagePermissionSet and canManageRole in src/lib/staff/userAccess.ts to refuse self-edits, equal/higher-target edits, granting unknown keys, and granting permissions the actor does not hold.
  • Enforce those guards in server routes before any privileged writes in src/app/api/staff/security/users/[id]/permissions/route.ts, src/app/api/staff/security/roles/route.ts, and src/app/api/staff/security/roles/[key]/permissions/route.ts.
  • Deduplicate incoming permission lists in routes to avoid accidental duplicate writes and make audit diffs clear.
  • Add a write-only SQL migration supabase/migrations/20260811030000_security_boundary_hardening.sql (with rollback) that tightens profiles SELECT to owner-or-staff, removes browser SELECT on base roles/permissions, and revokes TRUNCATE from service_role on several sensitive tables, and explicitly mark it MIGRATION APPROVAL REQUIRED (do not apply without review).
  • Add docs/SECURITY_HARDENING.md documenting the authorization matrix, findings, migration packet, and residual risks.
  • Add adversarial unit tests in tests/security-hardening.test.ts exercising limited-staff escalation, unknown permissions, self-overrides, stronger targets, role-rank escalation, and the owner exemption.

Testing

  • Ran the new adversarial unit tests with node --experimental-strip-types --test tests/security-hardening.test.ts and all 5 tests passed.
  • Ran npm run typecheck (TypeScript tsc --noEmit) and resolved issues introduced by changes; typecheck passed for the modified code.
  • Ran focused lint/ESLint on the changed files and the new test and no new lint errors were reported for those files.
  • Attempted wider test/build runs: npm test / full repository test and npm run build exposed unrelated baseline environment and module-resolution issues (missing NEXT_PUBLIC_SUPABASE_URL, extension/alias resolution under the local Node environment) and many preexisting lint warnings/errors; these are documented in docs/SECURITY_HARDENING.md and do not block the focused hardening verification above.

MIGRATION NOTE: The SQL migration was created and committed but NOT APPLIED; it is explicitly marked MIGRATION APPROVAL REQUIRED because replacing the open profiles policy can affect public/community pages and must be staged and approved before applying to production.


Codex Task

@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
keymoura-website Ready Ready Preview Aug 11, 2026 10:40pm

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 60411f749b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +54 to +55
const { data: targetRoleRow } = await routeServiceClient.from("user_roles").select("role").eq("user_id", id).maybeSingle();
const targetRole = String(targetRoleRow?.role ?? "member").toLowerCase();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail closed when the target role lookup errors

If the user_roles lookup fails, this silently treats the target as a rank-10 member; a staff actor with permissions.grant can therefore pass the hierarchy check for an administrator or other stronger target whenever this read errors but subsequent writes succeed. Inspect the Supabase error and reject the request instead of applying the member fallback on query failure.

Useful? React with 👍 / 👎.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant