Summary
All 8 Supabase Edge Functions explicitly disable JWT verification via verify_jwt = false in supabase/config.toml and contain zero application-level authentication. Every function that calls a paid external API (Lovable AI gateway, Google Earth Engine, Mapbox) accepts requests from the entire internet with no identity check.
Evidence
supabase/config.toml sets verify_jwt = false for every function:
[functions.analyze-field]
verify_jwt = false
[functions.crop-planning]
verify_jwt = false
[functions.gee-analytics]
verify_jwt = false
[functions.gee-ndvi-tiles]
verify_jwt = false
[functions.get-mapbox-token]
verify_jwt = false
[functions.keepalive]
verify_jwt = false
[functions.ndvi-timeseries]
verify_jwt = false
[functions.soil-data]
verify_jwt = false
None of the handler bodies check for a Authorization header, Supabase user session, or any other credential. The pattern in every function:
serve(async (req) => {
if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders });
// No auth check — immediately processes request and calls paid external API
try { ... }
Functions that invoke paid APIs without any auth gate:
analyze-field/index.ts — calls https://ai.gateway.lovable.dev/v1/chat/completions with LOVABLE_API_KEY using google/gemini-2.5-flash
crop-planning/index.ts — calls the same Lovable gateway using google/gemini-2.5-pro (higher cost model)
gee-analytics/index.ts — calls Google Earth Engine REST API (billed per computation unit)
gee-ndvi-tiles/index.ts — calls GEE Maps API
ndvi-timeseries/index.ts — fires up to 40 sequential GEE value:compute calls per request
get-mapbox-token/index.ts — returns Deno.env.get("MAPBOX_TOKEN") unconditionally
Why this matters
Any person or bot that discovers the Supabase project URL can call all of these endpoints at will, generating unbounded charges against the project owner's billing accounts for Lovable/AI, Google Earth Engine, and Mapbox. There is no identity, quota, or cost gate.
Attack or failure scenario
- Attacker finds the Supabase project URL (visible in the committed
.env and supabase/config.toml).
- Sends POST requests to
https://ldqvretuwballytbywfc.supabase.co/functions/v1/crop-planning in a loop — each call invokes gemini-2.5-pro.
- No rate limit, no auth, no quota stops the loop.
- Project owner receives a large billing invoice from Lovable and Google Cloud.
For ndvi-timeseries, each request fires 40 GEE API calls in parallel (Promise.all), making each single HTTP request disproportionately expensive in GEE compute units.
Root cause
Supabase Edge Functions default to verify_jwt = true, which requires a valid Supabase user JWT in Authorization: Bearer <token>. The developer explicitly opted out of this for all functions and added no replacement auth mechanism — likely to avoid handling auth complexity in the frontend during development and never restored it.
Recommended fix
- Remove all
verify_jwt = false lines from supabase/config.toml (restoring Supabase's default JWT enforcement).
- Ensure the frontend passes the Supabase session token when calling Edge Functions:
const { data: { session } } = await supabase.auth.getSession();
const response = await supabase.functions.invoke('analyze-field', {
body: { ... },
headers: { Authorization: `Bearer ${session?.access_token}` },
});
- If public (unauthenticated) access is required for specific functions (e.g.
keepalive), add an application-level API key check with a secret stored in Supabase Vault, and rate-limit it.
- Functions calling paid APIs (
analyze-field, crop-planning, gee-*, ndvi-timeseries) must require a valid authenticated Supabase user.
Acceptance criteria
Suggested labels
security, bug
Priority
P0
Severity
Critical — direct, unbounded financial exposure with zero friction for an attacker. The project URL is already public on GitHub.
Confidence
Confirmed — supabase/config.toml explicitly opts out of JWT enforcement for all 8 functions; none of the handler bodies perform any credential check.
Summary
All 8 Supabase Edge Functions explicitly disable JWT verification via
verify_jwt = falseinsupabase/config.tomland contain zero application-level authentication. Every function that calls a paid external API (Lovable AI gateway, Google Earth Engine, Mapbox) accepts requests from the entire internet with no identity check.Evidence
supabase/config.tomlsetsverify_jwt = falsefor every function:None of the handler bodies check for a
Authorizationheader, Supabase user session, or any other credential. The pattern in every function:Functions that invoke paid APIs without any auth gate:
analyze-field/index.ts— callshttps://ai.gateway.lovable.dev/v1/chat/completionswithLOVABLE_API_KEYusinggoogle/gemini-2.5-flashcrop-planning/index.ts— calls the same Lovable gateway usinggoogle/gemini-2.5-pro(higher cost model)gee-analytics/index.ts— calls Google Earth Engine REST API (billed per computation unit)gee-ndvi-tiles/index.ts— calls GEE Maps APIndvi-timeseries/index.ts— fires up to 40 sequential GEEvalue:computecalls per requestget-mapbox-token/index.ts— returnsDeno.env.get("MAPBOX_TOKEN")unconditionallyWhy this matters
Any person or bot that discovers the Supabase project URL can call all of these endpoints at will, generating unbounded charges against the project owner's billing accounts for Lovable/AI, Google Earth Engine, and Mapbox. There is no identity, quota, or cost gate.
Attack or failure scenario
.envandsupabase/config.toml).https://ldqvretuwballytbywfc.supabase.co/functions/v1/crop-planningin a loop — each call invokesgemini-2.5-pro.For
ndvi-timeseries, each request fires 40 GEE API calls in parallel (Promise.all), making each single HTTP request disproportionately expensive in GEE compute units.Root cause
Supabase Edge Functions default to
verify_jwt = true, which requires a valid Supabase user JWT inAuthorization: Bearer <token>. The developer explicitly opted out of this for all functions and added no replacement auth mechanism — likely to avoid handling auth complexity in the frontend during development and never restored it.Recommended fix
verify_jwt = falselines fromsupabase/config.toml(restoring Supabase's default JWT enforcement).keepalive), add an application-level API key check with a secret stored in Supabase Vault, and rate-limit it.analyze-field,crop-planning,gee-*,ndvi-timeseries) must require a valid authenticated Supabase user.Acceptance criteria
supabase/config.tomlcontains noverify_jwt = falseentries for functions that call paid external APIs401when called without a valid Supabase JWTverify_jwt = falseentry, if kept, is documented with the reason and has an explicit application-level auth gate in the handlerSuggested labels
security, bug
Priority
P0
Severity
Critical — direct, unbounded financial exposure with zero friction for an attacker. The project URL is already public on GitHub.
Confidence
Confirmed —
supabase/config.tomlexplicitly opts out of JWT enforcement for all 8 functions; none of the handler bodies perform any credential check.