From bb9833be11c9bdf106c2542391dcae949ac1a80e Mon Sep 17 00:00:00 2001 From: Etienne Stalmans Date: Tue, 24 Mar 2026 12:27:27 +0100 Subject: [PATCH 1/2] chore: restrict local paths edge_functions --- .../src/tools/database-operation-tools.ts | 9 ++++++++- .../src/tools/edge-function-tools.ts | 13 ++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server-supabase/src/tools/database-operation-tools.ts b/packages/mcp-server-supabase/src/tools/database-operation-tools.ts index 0692e8d..f5fee30 100644 --- a/packages/mcp-server-supabase/src/tools/database-operation-tools.ts +++ b/packages/mcp-server-supabase/src/tools/database-operation-tools.ts @@ -84,7 +84,14 @@ const listMigrationsOutputSchema = z.object({ const applyMigrationInputSchema = z.object({ project_id: z.string(), - name: z.string().describe('The name of the migration in snake_case'), + name: z + .string() + .describe('The name of the migration in snake_case') + .refine( + (name) => + !name.includes('/') && !name.includes('\\') && !name.includes('..'), + { message: 'Name cannot contain path separators or traversal' } + ), query: z.string().describe('The SQL query to apply'), }); diff --git a/packages/mcp-server-supabase/src/tools/edge-function-tools.ts b/packages/mcp-server-supabase/src/tools/edge-function-tools.ts index 19a6ed1..b3d1e14 100644 --- a/packages/mcp-server-supabase/src/tools/edge-function-tools.ts +++ b/packages/mcp-server-supabase/src/tools/edge-function-tools.ts @@ -6,6 +6,7 @@ import { edgeFunctionWithBodySchema, } from '../platform/types.js'; import { injectableTool, type ToolDefs } from './util.js'; +import path from 'path'; type EdgeFunctionToolsOptions = { functions: EdgeFunctionsOperations; @@ -48,7 +49,17 @@ const deployEdgeFunctionInputSchema = z.object({ files: z .array( z.object({ - name: z.string(), + name: z.string().refine( + (filePath) => { + const resolved = path.resolve(process.cwd(), filePath); + const normalized = path.normalize(resolved); + const cwd = process.cwd(); + return normalized.startsWith(cwd + path.sep) || normalized === cwd; + }, + { + message: 'Name must be a path inside the current working directory', + } + ), content: z.string(), }) ) From 82616616bf58df2127d1e5a5e92db0b4ebeeb5b7 Mon Sep 17 00:00:00 2001 From: Etienne Stalmans Date: Tue, 24 Mar 2026 12:36:42 +0100 Subject: [PATCH 2/2] chore: update types --- .../src/management-api/types.ts | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/packages/mcp-server-supabase/src/management-api/types.ts b/packages/mcp-server-supabase/src/management-api/types.ts index 9f23b0c..ab11a5f 100644 --- a/packages/mcp-server-supabase/src/management-api/types.ts +++ b/packages/mcp-server-supabase/src/management-api/types.ts @@ -1545,6 +1545,26 @@ export interface paths { patch?: never; trace?: never; }; + "/v1/projects/{ref}/database/openapi": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get PostgREST OpenAPI spec + * @description Returns the PostgREST OpenAPI specification for the project. This is the replacement for querying `/rest/v1/` directly with the anon key. + */ + get: operations["v1-get-database-openapi"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/v1/projects/{ref}/functions": { parameters: { query?: never; @@ -4310,6 +4330,8 @@ export interface components { name: string; /** @enum {string} */ status: "AVAILABLE" | "PENDING" | "REMOVED" | "FAILED"; + /** Format: date-time */ + completed_on: string | null; }; V1UndoBody: { name: string; @@ -9949,6 +9971,59 @@ export interface operations { }; }; }; + "v1-get-database-openapi": { + parameters: { + query?: { + /** @description The database schema to generate the OpenAPI spec for */ + schema?: string; + }; + header?: never; + path: { + /** @description Project ref */ + ref: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden action */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Failed to fetch PostgREST OpenAPI spec */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; "v1-list-all-functions": { parameters: { query?: never;