Skip to content

Restrict public execution of API key oracle RPCs#1758

Open
riderx wants to merge 3 commits intomainfrom
riderx/fix-rpc-oracles
Open

Restrict public execution of API key oracle RPCs#1758
riderx wants to merge 3 commits intomainfrom
riderx/fix-rpc-oracles

Conversation

@riderx
Copy link
Member

@riderx riderx commented Mar 8, 2026

Summary (AI generated)

  • Added a follow-up migration to revoke PUBLIC and lock down direct get_user_id and get_org_perm_for_apikey execute rights, preventing anonymous caller access to API-key validation oracles.
  • Re-granted execute rights to authenticated and service_role only, preserving intended internal access patterns.

Motivation (AI generated)

  • The exposed RPC behavior allowed unauthenticated clients with publishable keys to validate leaked API keys and infer user/org/app entitlement data.

Business Impact (AI generated)

  • This reduces key-exfiltration blast radius and blocks key enumeration/permission-oracle abuse.

Test plan (AI generated)

  • bun lint:backend

Screenshots (AI generated)

  • Not applicable (backend migration change only).

Checklist (AI generated)

  • My code follows the code style of this project and passes bun run lint:backend && bun run lint.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • My change has adequate E2E test coverage.
  • I have tested my code manually, and I have provided steps how to reproduce my tests.

Summary by CodeRabbit

  • Chores
    • Restricted public access to sensitive database operations while preserving access for authenticated and service roles.
  • Tests
    • Added an automated permission test suite verifying anonymous access is denied and authenticated/service-role access works as expected.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 8, 2026

📝 Walkthrough

Walkthrough

Revoke PUBLIC execute on three apikey-related functions and re-grant execute to authenticated and service_role; add tests validating permission behavior for anonymous, authenticated, and service_role callers.

Changes

Cohort / File(s) Summary
Migration: restrict API key function public access
supabase/migrations/20260308203222_restrict_apikey_oracle_public_access.sql
Revoke EXECUTE FROM PUBLIC for public.get_user_id(apikey text), public.get_user_id(apikey text, app_id text), and public.get_org_perm_for_apikey(apikey text, app_id text); then GRANT EXECUTE to authenticated and service_role.
Tests: apikey/oracle permission checks
supabase/tests/45_test_apikey_oracle_permissions.sql
Add 8-test SQL script verifying permission denied for anonymous, and successful execution for authenticated and service_role for the three functions (with and without app_id).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I nibble logs beneath the moon,
I hide the keys in carrot dune,
Public doors I softly close,
Trusted hops the access knows,
A quiet thump — the garden's tune. 🥕🔐

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main objective of restricting public execution of the API key oracle RPCs mentioned in the migration file.
Description check ✅ Passed The description addresses the summary, motivation, and business impact well, includes a test plan (linting), and properly marks checklist items. However, the pull request lacks a comprehensive manual testing plan and reproducible steps as suggested by the template's checklist requirement.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch riderx/fix-rpc-oracles

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 SQLFluff (4.0.4)
supabase/tests/45_test_apikey_oracle_permissions.sql

User Error: No dialect was specified. You must configure a dialect or specify one on the command line using --dialect after the command. Available dialects:
ansi, athena, bigquery, clickhouse, databricks, db2, doris, duckdb, exasol, flink, greenplum, hive, impala, mariadb, materialize, mysql, oracle, postgres, redshift, snowflake, soql, sparksql, sqlite, starrocks, teradata, trino, tsql, vertica


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@supabase/migrations/20260308203222_restrict_apikey_oracle_public_access.sql`:
- Around line 9-11: The three GRANTs reopen parameterized oracle helpers to the
authenticated role; remove the GRANT EXECUTE statements for
"public"."get_user_id" (both overloads: ("apikey" "text") and ("apikey" "text",
"app_id" "text")) and for "public"."get_org_perm_for_apikey" ("apikey" "text",
"app_id" "text") so these functions remain service_role-only; if client access
is required, instead expose or GRANT only no-argument wrapper functions that
perform authentication checks (create/ensure wrappers that call the service_role
helpers internally and grant those wrappers to authenticated).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 673dacae-151b-486b-b317-44cd9693c3a5

📥 Commits

Reviewing files that changed from the base of the PR and between 2af3a08 and ceffb00.

📒 Files selected for processing (1)
  • supabase/migrations/20260308203222_restrict_apikey_oracle_public_access.sql

Comment on lines +9 to +11
GRANT EXECUTE ON FUNCTION "public"."get_user_id" ("apikey" "text") TO "authenticated";
GRANT EXECUTE ON FUNCTION "public"."get_user_id" ("apikey" "text", "app_id" "text") TO "authenticated";
GRANT EXECUTE ON FUNCTION "public"."get_org_perm_for_apikey" ("apikey" "text", "app_id" "text") TO "authenticated";
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't re-open these oracle helpers to all authenticated sessions.

Lines 9-11 still make the parameterized API-key lookup functions callable by any logged-in client. That preserves the oracle for authenticated users, which is the same class of exposure these low-level helpers usually need to avoid. Prefer keeping these functions service_role-only and exposing only a checked wrapper if client access is required.

🔒 Suggested change
-GRANT EXECUTE ON FUNCTION "public"."get_user_id" ("apikey" "text") TO "authenticated";
-GRANT EXECUTE ON FUNCTION "public"."get_user_id" ("apikey" "text", "app_id" "text") TO "authenticated";
-GRANT EXECUTE ON FUNCTION "public"."get_org_perm_for_apikey" ("apikey" "text", "app_id" "text") TO "authenticated";

Based on learnings, "API key identities resolve through the authenticated role via JWT, not the anon role" and parameterized helper functions "should NOT be granted to anon/authenticated roles ... only the no-argument wrapper functions should be public as they perform authentication checks."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
GRANT EXECUTE ON FUNCTION "public"."get_user_id" ("apikey" "text") TO "authenticated";
GRANT EXECUTE ON FUNCTION "public"."get_user_id" ("apikey" "text", "app_id" "text") TO "authenticated";
GRANT EXECUTE ON FUNCTION "public"."get_org_perm_for_apikey" ("apikey" "text", "app_id" "text") TO "authenticated";
-- (previous lines in migration file)
-- Remove the GRANT EXECUTE statements for parameterized helpers
-- These functions should remain service_role-only to prevent oracle access
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@supabase/migrations/20260308203222_restrict_apikey_oracle_public_access.sql`
around lines 9 - 11, The three GRANTs reopen parameterized oracle helpers to the
authenticated role; remove the GRANT EXECUTE statements for
"public"."get_user_id" (both overloads: ("apikey" "text") and ("apikey" "text",
"app_id" "text")) and for "public"."get_org_perm_for_apikey" ("apikey" "text",
"app_id" "text") so these functions remain service_role-only; if client access
is required, instead expose or GRANT only no-argument wrapper functions that
perform authentication checks (create/ensure wrappers that call the service_role
helpers internally and grant those wrappers to authenticated).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
supabase/tests/45_test_apikey_oracle_permissions.sql (1)

54-68: Inconsistent test coverage for service_role.

The authenticated tests (lines 33-52) verify all three function signatures: get_user_id(apikey), get_user_id(apikey, app_id), and get_org_perm_for_apikey(apikey, app_id). However, the service_role tests omit get_user_id(apikey, app_id).

Consider adding the missing test for consistency:

🔧 Proposed fix
 SELECT tests.authenticate_as_service_role();

 SELECT
     is(
         get_user_id('ae6e7458-c46d-4c00-aa3b-153b0b8520ea'),
         '6aa76066-55ef-4238-ade6-0b32334a4097',
         'service role should still call get_user_id'
     );

+SELECT
+    is(
+        get_user_id('ae6e7458-c46d-4c00-aa3b-153b0b8520ea', 'com.demo.app'),
+        '6aa76066-55ef-4238-ade6-0b32334a4097',
+        'service role should still call get_user_id with app_id'
+    );
+
 SELECT
     is(
         get_org_perm_for_apikey('ae6e7458-c46d-4c00-aa3b-153b0b8520ea', 'com.demo.app'),
         'perm_owner',
         'service role should still call get_org_perm_for_apikey'
     );

Update the plan count accordingly:

-SELECT plan(8);
+SELECT plan(9);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@supabase/tests/45_test_apikey_oracle_permissions.sql` around lines 54 - 68,
Add the missing service_role test for the two-argument variant of get_user_id:
inside the service-role authenticated block (where tests.call
authenticate_as_service_role() and other assertions run) add an is(...)
assertion that calls get_user_id('ae6e7458-c46d-4c00-aa3b-153b0b8520ea',
'com.demo.app') and compares it to the expected user id (same expected value
used for the single-arg test), and update any test plan/expect count if present
to reflect the additional assertion; reference the existing get_user_id(apikey)
and get_org_perm_for_apikey(apikey, app_id) tests to mirror formatting and
expected value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@supabase/tests/45_test_apikey_oracle_permissions.sql`:
- Around line 54-68: Add the missing service_role test for the two-argument
variant of get_user_id: inside the service-role authenticated block (where
tests.call authenticate_as_service_role() and other assertions run) add an
is(...) assertion that calls get_user_id('ae6e7458-c46d-4c00-aa3b-153b0b8520ea',
'com.demo.app') and compares it to the expected user id (same expected value
used for the single-arg test), and update any test plan/expect count if present
to reflect the additional assertion; reference the existing get_user_id(apikey)
and get_org_perm_for_apikey(apikey, app_id) tests to mirror formatting and
expected value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fda628bf-343a-45c7-99ab-423c1702d598

📥 Commits

Reviewing files that changed from the base of the PR and between ceffb00 and cf8744b.

📒 Files selected for processing (1)
  • supabase/tests/45_test_apikey_oracle_permissions.sql

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 8, 2026

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant