Skip to content

All 8 Edge Functions disable JWT auth and expose paid AI/GEE/Mapbox APIs to unauthenticated callers #3

@tg12

Description

@tg12

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

  1. Attacker finds the Supabase project URL (visible in the committed .env and supabase/config.toml).
  2. Sends POST requests to https://ldqvretuwballytbywfc.supabase.co/functions/v1/crop-planning in a loop — each call invokes gemini-2.5-pro.
  3. No rate limit, no auth, no quota stops the loop.
  4. 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

  1. Remove all verify_jwt = false lines from supabase/config.toml (restoring Supabase's default JWT enforcement).
  2. 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}` },
    });
  3. 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.
  4. Functions calling paid APIs (analyze-field, crop-planning, gee-*, ndvi-timeseries) must require a valid authenticated Supabase user.

Acceptance criteria

  • supabase/config.toml contains no verify_jwt = false entries for functions that call paid external APIs
  • All functions calling Lovable AI gateway or GEE return 401 when called without a valid Supabase JWT
  • Frontend code passes session tokens when invoking Edge Functions
  • A verify_jwt = false entry, if kept, is documented with the reason and has an explicit application-level auth gate in the handler

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions