Skip to content

Make the untrusted timeout ceiling configurable - #2212

Open
damusix wants to merge 1 commit into
unclecode:developfrom
damusix:fix/configurable-max-timeout
Open

Make the untrusted timeout ceiling configurable#2212
damusix wants to merge 1 commit into
unclecode:developfrom
damusix:fix/configurable-max-timeout

Conversation

@damusix

@damusix damusix commented Aug 28, 2026

Copy link
Copy Markdown

Closes #2211.

_clamp_untrusted caps page_timeout, wait_for_timeout and body_visibility_timeout at 60s for any config arriving over HTTP. The bound is right for a server reachable by untrusted callers — the problem is that it was a module literal with no env var, no config.yml key, and no way for an operator to change it, so a private deployment could not crawl a page that legitimately takes longer. The failure is also confusing: Page.goto: Timeout 60000ms exceeded quotes a number the caller never sent.

CRAWL4AI_MAX_TIMEOUT_MS now sets the ceiling and defaults to the same 60000ms, so nothing changes for anyone who does not set it. A smaller value tightens the bound; a request still only ever gets the timeout it asks for.

A value that is not a positive integer warns and keeps the default rather than being coerced. A typo in this particular variable would silently widen a DoS bound, which seemed worth being loud about.

The lookup happens per call rather than being captured at import, so the setting applies wherever the process picked its environment up, and a test can set it without reloading the module. _MAX_TIMEOUT_MS is renamed to _DEFAULT_MAX_TIMEOUT_MS to stop the name claiming something it no longer is; it is private and had no references outside this module.

Verified

Against unclecode/crawl4ai:0.9.2 in docker, crawling a server that answers after 90s with page_timeout: 300000:

result
stock HTTP 500 in 60.7s — Page.goto: Timeout 60000ms exceeded
ceiling raised HTTP 200 in 90.9s, markdown returned

15 new tests in tests/test_config_defaults.py cover the default, raising, tightening, a request above a raised ceiling, every invalid value, the warning, and that trusted configs stay unclamped. tests/test_config_defaults.py passes (58). Reverting the source change fails 8 of them.

black --diff leaves the added lines unchanged; the existing reformat suggestions in both files are pre-existing and left alone.

page_timeout, wait_for_timeout and body_visibility_timeout are clamped to
60s for any config arriving over HTTP, and the value was a module literal
with no env var, no config.yml key, and no way for an operator to change
it. A deployment that is not public could not crawl a page that
legitimately takes longer.

CRAWL4AI_MAX_TIMEOUT_MS now sets the ceiling, defaulting to the same
60000ms. A value that is not a positive integer warns and keeps the
default, since a typo would otherwise silently widen a DoS bound.

Read per call rather than captured at import, so the setting applies
wherever the process picked its environment up.

Closes unclecode#2211
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant