Summary
No Edge Function implements rate limiting, per-IP quotas, or request throttling. Several endpoints are expensive in compute units per call: ndvi-timeseries fires up to 40 parallel GEE API requests per HTTP request; gee-analytics fires 4–8 GEE computations; analyze-field and crop-planning invoke Gemini 2.5 Pro/Flash. Any caller can drive unbounded API spend with a trivial loop.
Evidence
supabase/functions/ndvi-timeseries/index.ts — 40 GEE calls per request:
const imageCount = Math.min(count, 20);
const promises: Promise<...>[] = [];
for (let i = 0; i < imageCount; i++) {
const { timestamp, ndviVal } = buildImageNdviAtIndex(listExpr, i, geometry);
promises.push(
Promise.all([
computeValue(token, projectId, timestamp), // GEE call 1
computeValue(token, projectId, ndviVal), // GEE call 2
])...
);
}
const rawTimeseries = await Promise.all(promises); // all 40 fired at once
supabase/functions/gee-analytics/index.ts — up to 4 parallel sub-analyses, each with multiple computeValue calls (e.g., computeVegetationIndices fires 3 parallel GEE calls, computeLandSuitability fires 4).
Neither function, nor any other function in the project, contains:
- Rate limiting headers or logic
- Request counter / token bucket
- Per-user or per-IP throttle
- Supabase Edge Function concurrency limit configuration
- Any cost-guard check before invoking the external API
supabase/config.toml has no [functions.<name>] max_requests_per_second or equivalent setting.
Why this matters
Cost amplification attack: a single HTTP request to ndvi-timeseries generates 40 GEE compute-unit requests. Sending 100 HTTP requests/second (trivial for a bot) generates 4,000 GEE API calls per second against the project owner's account. GEE's non-commercial usage tier has strict quotas; commercial overages are billed to the Google Cloud project. The same applies to Lovable AI gateway (per-token billing for Gemini 2.5 Pro).
Attack or failure scenario
- Attacker discovers the public Supabase URL from the committed
.env.
- Runs:
while true; do curl -X POST .../functions/v1/ndvi-timeseries -d '{"polygon":...}' & done
- Each iteration spawns 40 parallel GEE API calls.
- GEE quota exhausted for the day or Google Cloud billing spikes within minutes.
- All legitimate users are denied GEE service for the rest of the quota period.
Root cause
The application was built without a budget constraint mindset. The assumption is that callers are legitimate app users, not adversarial bots. With no auth (see related issue) and no rate limiting, cost-amplification attacks require zero sophistication.
Recommended fix
Immediate: Fix the auth issue first — requiring a Supabase JWT removes anonymous abuse. Authenticated users are rate-limited by their session identity.
Additional hardening:
- Implement a server-side request counter using Supabase's Redis-compatible
pg_redis or a simple Postgres counter with a time window, keyed by authenticated user ID.
- Set per-user daily limits for GEE and AI calls (e.g., 10 GEE time-series analyses per user per day).
- For
ndvi-timeseries, cap imageCount to a lower value (e.g., 10) and add a per-field cooldown to prevent re-fetching the same data within a short window.
- Consider Supabase Edge Runtime's built-in request rate limiting via the dashboard (Project Settings → Edge Functions → Rate Limits).
- Set
maxPixels to a realistic value rather than 1_000_000_000 — this allows GEE to fail fast on excessively large polygons rather than running to quota exhaustion.
Acceptance criteria
Suggested labels
security, bug
Priority
P1
Severity
High — cost-amplification attack possible with zero credentials. Severity is High rather than Critical only because fixing the auth issue substantially mitigates the attack surface.
Confidence
Confirmed — no rate limiting code exists in any Edge Function; ndvi-timeseries makes up to 40 GEE API calls per HTTP request.
Summary
No Edge Function implements rate limiting, per-IP quotas, or request throttling. Several endpoints are expensive in compute units per call:
ndvi-timeseriesfires up to 40 parallel GEE API requests per HTTP request;gee-analyticsfires 4–8 GEE computations;analyze-fieldandcrop-planninginvoke Gemini 2.5 Pro/Flash. Any caller can drive unbounded API spend with a trivial loop.Evidence
supabase/functions/ndvi-timeseries/index.ts— 40 GEE calls per request:supabase/functions/gee-analytics/index.ts— up to 4 parallel sub-analyses, each with multiplecomputeValuecalls (e.g.,computeVegetationIndicesfires 3 parallel GEE calls,computeLandSuitabilityfires 4).Neither function, nor any other function in the project, contains:
supabase/config.tomlhas no[functions.<name>] max_requests_per_secondor equivalent setting.Why this matters
Cost amplification attack: a single HTTP request to
ndvi-timeseriesgenerates 40 GEE compute-unit requests. Sending 100 HTTP requests/second (trivial for a bot) generates 4,000 GEE API calls per second against the project owner's account. GEE's non-commercial usage tier has strict quotas; commercial overages are billed to the Google Cloud project. The same applies to Lovable AI gateway (per-token billing for Gemini 2.5 Pro).Attack or failure scenario
.env.while true; do curl -X POST .../functions/v1/ndvi-timeseries -d '{"polygon":...}' & doneRoot cause
The application was built without a budget constraint mindset. The assumption is that callers are legitimate app users, not adversarial bots. With no auth (see related issue) and no rate limiting, cost-amplification attacks require zero sophistication.
Recommended fix
Immediate: Fix the auth issue first — requiring a Supabase JWT removes anonymous abuse. Authenticated users are rate-limited by their session identity.
Additional hardening:
pg_redisor a simple Postgres counter with a time window, keyed by authenticated user ID.ndvi-timeseries, capimageCountto a lower value (e.g., 10) and add a per-field cooldown to prevent re-fetching the same data within a short window.maxPixelsto a realistic value rather than1_000_000_000— this allows GEE to fail fast on excessively large polygons rather than running to quota exhaustion.Acceptance criteria
ndvi-timeseriescaps parallel image processing to ≤ 10 imagesSuggested labels
security, bug
Priority
P1
Severity
High — cost-amplification attack possible with zero credentials. Severity is High rather than Critical only because fixing the auth issue substantially mitigates the attack surface.
Confidence
Confirmed — no rate limiting code exists in any Edge Function;
ndvi-timeseriesmakes up to 40 GEE API calls per HTTP request.