Skip to content

Security: anonymous summarize-article requests can drive LLM provider spend #4675

Description

@koala73

Summary

Static validation confirms an expensive API abuse path in /api/news/v1/summarize-article: anonymous/basic-session callers can trigger LLM provider calls on cache misses. The current premium check only controls the optional systemAppend field and does not gate the LLM call itself. The route is also missing from the endpoint-specific fail-closed rate-limit registry.

Validated against revision 52cc48fa2d91d5851cb04db77bc5424794c7ccc9.

Affected surface

  • Gateway-routed Sebuf endpoint: /api/news/v1/summarize-article
  • Source: user-controlled headlines, bodies, geoContext, mode, provider, variant, and lang
  • Sink: paid/expensive outbound LLM provider request inside summarizeArticle()
  • Policy basis: SECURITY.md lists Edge function abuse controls and rate limiting as security considerations

Static evidence

  • api/news/v1/[rpc].ts routes the News service through createDomainGateway(...).
  • server/worldmonitor/news/v1/handler.ts exposes summarizeArticle.
  • server/worldmonitor/news/v1/summarize-article.ts calls isCallerPremium(ctx.request), but only uses the result to decide whether req.systemAppend is honored:
const isPremium = await isCallerPremium(ctx.request);
const systemAppend = isPremium && typeof req.systemAppend === 'string' ? req.systemAppend : '';
  • The LLM call inside cachedFetchJsonWithMeta(..., async () => { ... fetch(apiUrl, ...) }) is unconditional on cache miss when provider credentials exist and the provider health gate passes.
  • The cache key includes user-controlled headline/body/context inputs, so callers can force cache misses with unique headline text.
  • src/shared/premium-paths.ts does not include /api/news/v1/summarize-article.
  • server/_shared/entitlement-check.ts does not include /api/news/v1/summarize-article in ENDPOINT_ENTITLEMENTS.
  • server/_shared/rate-limit.ts includes /api/news/v1/summarize-article-cache, but not /api/news/v1/summarize-article, in ENDPOINT_RATE_POLICIES.
  • api/wm-session.js intentionally mints anonymous wms_ session tokens behind a broad per-IP cap; those tokens satisfy the gateway's basic non-premium auth path.

Compensating controls checked

  • The sibling api/chat-analyst.ts is Pro-gated with isCallerPremium() and calls checkRateLimit(..., { failClosed: true }) before LLM work. That stronger pattern is not applied here.
  • The endpoint uses a 24h cache, sanitization, max headline/body sizes, and provider health checks, but those do not prevent unbounded unique cache misses.

Exploit sketch

  1. Call /api/wm-session to obtain a basic anonymous session cookie.
  2. Call /api/news/v1/summarize-article with a valid provider and unique headline/body text per request.
  3. Each unique input generates a fresh cache key and can trigger a fresh provider call.
  4. The route inherits only the global per-IP fallback limiter, not a fail-closed LLM-specific policy.

No dynamic exploit probe was run; this is static validation only.

Recommended fix

Pick one product decision and enforce it consistently:

  • If article summarization is premium: add /api/news/v1/summarize-article to PREMIUM_RPC_PATHS and/or ENDPOINT_ENTITLEMENTS, and require a Pro/API entitlement before the LLM fetcher runs.
  • If some summarization remains free: add an explicit endpoint policy for /api/news/v1/summarize-article with a low budget and fail-closed semantics, and consider a per-session/user/IP cache-miss budget.
  • Keep systemAppend premium-only regardless.

Acceptance criteria

  • Anonymous wms_ sessions cannot drive unlimited LLM cache misses.
  • The endpoint has an explicit ENDPOINT_RATE_POLICIES entry or an equivalent scoped limiter with fail-closed behavior.
  • Add focused tests for anonymous/basic-session behavior, Pro behavior, and Redis-degraded rate-limit behavior.
  • Ensure the cache-read sibling /api/news/v1/summarize-article-cache remains a read-only cache lookup and does not call providers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High priority, fix soonarea: AI/intelAI analysis, intelligence findings, summarizationarea: APIBackend API, sidecar, keysarea:newsNews ingestion, taxonomy, signal filteringbugSomething isn't workingcodexsecuritySecurity-related

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions