Skip to content

fix: Unauthenticated search endpoints allow any website to drain Groq and SerpAPI quota #82

Description

@PandyaJeet

Summary

The /api/context/* router correctly enforces a per-session token on every route. The three search routers — /api/search/seo, /api/search/ai, and /api/search/community — have no authentication. While the SuperBrowser app is running, any webpage the user opens in any other browser on the same machine can silently call these endpoints and drain the user's paid Groq and SerpAPI quota by firing requests in a loop.

Where it is

  • backend/routers/seo.py:91
  • backend/routers/ai.py:33 and :44
  • backend/routers/community.py:26

What the code looks like today

Context router (protected)

## backend/routers/context.py:22-26

def verify_token(x_session_token: str = Header(default="")):
    if not VALID_TOKEN or not secrets.compare_digest(x_session_token, VALID_TOKEN):
        raise HTTPException(status_code=401, detail="Unauthorized")

router = APIRouter(dependencies=[Depends(verify_token)])

Search routers (unprotected)

## backend/routers/ai.py:33-41

@router.get("/ai", response_model=AIResponse, ...)
async def get_ai(q: str, session_id: str = "", persona: str = "default", gl: str = "us"):
    return await get_ai_consensus(query=q, persona=persona, gl=gl)

Why this is dangerous

When SuperBrowser is running the backend listens on 127.0.0.1:8000. Any webpage open in any browser on the same machine can fire requests like:

fetch('http://127.0.0.1:8000/api/search/ai?q=expensive+query', { mode: 'no-cors' })

CORS prevents the attacker from reading the response but does not stop the request from executing. The request still reaches FastAPI, triggers expensive operations (ask_groq, _scrape_all_engines), and consumes the user's paid Groq and SerpAPI credits. A simple loop can exhaust the monthly quota in seconds and cause real billing costs for the user.

Fix

Apply the existing verify_token dependency to all three search routers in backend/main.py (example):

from routers.context import verify_token

app.include_router(
    seo.router, prefix="/api/search", tags=["SEO"],
    dependencies=[Depends(verify_token)]
)
app.include_router(
    ai.router, prefix="/api/search", tags=["AI"],
    dependencies=[Depends(verify_token)]
)
app.include_router(
    community.router, prefix="/api/search", tags=["Community"],
    dependencies=[Depends(verify_token)]
)

The renderer already routes context calls through IPC which injects the token (see main.cjs:340-344). Search calls should follow the same pattern — route through IPC instead of calling the backend URL directly from the renderer.

Acceptance criteria

  • /api/search/seo, /api/search/ai, and /api/search/community all return HTTP 401 when called without a valid x-session-token header
  • All three endpoints return correct results when called with the valid token
  • A fetch('http://127.0.0.1:8000/api/search/ai?q=test', {mode:'no-cors'}) from an external browser page returns 401 (verify in backend logs)
  • No regression on SuperSEO, SuperAI, or Community mode functionality in the app

How to claim

Do not comment "assign me" without a proposed approach. The contributor with the strongest proposed approach gets assigned.

To propose: comment on this issue with your approach — which files you'd touch, how you'd pass the token from the renderer to the backend for search calls — OR email jeetpandya2006@gmail.com

Read CONTRIBUTING.md before proposing.

GSSoC Points

gssoc:approved (+50) + level:intermediate (+35) + type:security (+20) = 105 base pts

Metadata

Metadata

Labels

GSSoCUnder GirlScript Summer of Codelevel:intermediateModerate complexity (+35 pts)type:securitySecurity improvement (+20 pts)

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions