fix(web-sources): close crawler DoS vector (#399) - #1252
Merged
Merged
Conversation
Three related fixes so a flood of crawl requests can no longer freeze the container:
1. Concurrency guard: POST /assistants/{id}/web-sources/crawl now rejects with
409 if a crawl is already running for that assistant (checked via
list_active_crawls before any write, so no orphan document/job rows). This
is DynamoDB-backed, so the guard is cross-container.
2. Offload CPU-bound parsing: trafilatura.extract() and BeautifulSoup() in the
crawler now run via run_in_executor instead of blocking the shared event loop.
3. Offload DynamoDB: every boto3 table call in crawl_repository.py (put/get/
query/update/delete) now runs via run_in_executor (new _run_ddb helper),
so per-page counter writes no longer stall the loop on network I/O.
Added a route test for the 409 guard (asserts no writes happen on rejection)
and patched the existing happy-path tests for the new list_active_crawls call.
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
Closes the web-crawler DoS vector described in #399. Three related fixes so a flood of crawl requests can no longer freeze the container serving all HTTP traffic.
1. Concurrency guard (highest impact)
POST /assistants/{id}/web-sources/crawlnow checkslist_active_crawlsbefore any write and returns 409 Conflict if a crawl is already running for that assistant. This closes the amplification vector — a script (or a user double-clicking on a slow connection) can no longer launch unbounded simultaneous crawls._BACKGROUND_CRAWLSset never did — see the issue's Additional Notes).list_active_crawlsalready self-heals stalerunningrows, so a crawl whose owning process died is auto-failed and does not wrongly block a new one.create_document/create_crawl_job, so a rejected request leaves no orphan rows.2. Offload CPU-bound parsing
trafilatura.extract()andBeautifulSoup()incrawler.pynow run viarun_in_executor(thread pool) instead of directly on the shared event loop, so parsing a large page can't stall auth/chat/other requests.3. Offload blocking DynamoDB
Every
boto3table call incrawl_repository.py(put/get/query/update/delete — 9 call sites) now runs viarun_in_executorthrough a small_run_ddbhelper. This matters most forincrement_counters, which the crawler hits per page. Choserun_in_executoroveraioboto3to avoid a new dependency and match the existing pattern already used for the S3 put.Scope note
The issue's two Additional Notes (cross-container crawl count, lazy stale-reaping) are effectively addressed by fix #1 using the DynamoDB-backed guard. The S3 upload (
_put_markdown) was already offloaded and is unchanged.Testing
list_active_crawlscall.53 passedacrosstest_routes.py,test_crawler.py,test_crawl_repository.py; ruff clean on all three source files.Fixes #399 (will close manually after merge —
Fixesonly auto-closes on merge to the default branch).