fix(routes): resolve DoS via SQLite SQLITE_LIMIT_VARIABLE_NUMBER overflow in DELETE /tasks/bulk (#313)#320
Open
arpanmukherjee38 wants to merge 1 commit into
Conversation
d251f21 to
929c9dc
Compare
utksh1
requested changes
May 26, 2026
Owner
utksh1
left a comment
There was a problem hiding this comment.
Requesting changes. The chunking/limit approach is the right direction for the SQLite variable-limit DoS, but this needs regression tests before merge: empty list, 500 IDs accepted, 501 IDs rejected, and delete_task_records chunking over more than one chunk. Please also keep formatting consistent on the long DELETE statements.
929c9dc to
f01418a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #313
DELETE /tasks/bulkaccepted an unbounded list of task IDs and passedthem all directly into a parameterized
WHERE id IN (?, ?, ...)query.SQLite enforces a hard limit of
SQLITE_LIMIT_VARIABLE_NUMBER = 999.Sending 1000+ IDs triggered an unhandled
OperationalErrorthatpropagated as a 500 response, leaking internal database details and
providing a reliable denial-of-service vector requiring zero
authentication.
Root Cause
Two separate code paths were vulnerable:
bulk_delete_tasks()— no length validation on the incomingtask_idslist before building the placeholder string.delete_task_records()— the shared helper also built an unboundedplaceholder string, meaning any caller (including
clear_all_tasks)inherited the same crash vector.
Changes
backend/secuscan/models.pyMAX_BULK_DELETE = 500constant (safely under the SQLite limit)BulkDeleteRequestPydantic model withField(min_length=1, max_length=500)— FastAPI rejects oversized requests with astructured
422 Unprocessable Entitybefore the function body runsbackend/secuscan/routes.pybulk_delete_tasks()to acceptBulkDeleteRequestas therequest body; Pydantic enforces the size cap at parse time
delete_task_records()to process IDs in chunks ofSQLITE_CHUNK_SIZE = 500, staying safely under the SQLite variablelimit for all callers including
clear_all_tasksfrom .models importblock; consolidated into asingle import statement
Before / After
Before
After
Testing
Security Impact Closed
OperationalErrorleak in response body — eliminateddelete_task_records()hardened for all callers