Summary
The search endpoints take q as an unbounded query string with no Pydantic constraints, allowing arbitrarily long or empty queries through to upstream APIs and scrapers.
Reproduction
curl 'http://localhost:8000/api/search/seo?q='
# returns HTTP 400 (handled)
curl 'http://localhost:8000/api/search/seo?q='$(python -c "print('a'*10000)")
# accepted - 10k char query passed to SerpAPI and all 3 scrapers
Current code
Expected fix
Add Field constraints with min/max length. For GET endpoints:
@router.get('/seo')
async def get_seo(q: str = Query(..., min_length=1, max_length=500)):
...
For the Pydantic request model in ai.py:
class ContextualAIRequest(BaseModel):
query: str = Field(..., min_length=1, max_length=500)
persona: Literal['default', 'chatgpt', 'gemini', 'perplexity', 'claude'] = 'default'
context: Optional[Dict] = None
region: str = Field(default='us', max_length=4)
Acceptance Criteria
GSSoC Points
level:beginner (+20) + type:bug (+10) + type:security (+20) + gssoc:approved (+50) = 100 base pts
Summary
The search endpoints take
qas an unbounded query string with no Pydantic constraints, allowing arbitrarily long or empty queries through to upstream APIs and scrapers.Reproduction
Current code
async def get_seo(q: str = Query(default=None))async def get_community(q: str = Query(default=None))async def get_ai(q: str, ...)ContextualAIRequestPydantic model has noFieldconstraintsExpected fix
Add
Fieldconstraints with min/max length. For GET endpoints:For the Pydantic request model in ai.py:
Acceptance Criteria
GSSoC Points
level:beginner(+20) +type:bug(+10) +type:security(+20) +gssoc:approved(+50) = 100 base pts