All vulnerabilities
GHSA-j843-8p47-rhxp

crawl4ai: ReDoS via untrusted regex patterns freezes the Docker server

crawl4ai
CVSS
6.5Medium
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed in0.9.5Fixed versionGitHub
Published15 Oct 2026Updated 15 Oct 2026GitHub

What fixes it

A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.

Description

Summary

The Docker API server lets an untrusted request body supply regular expressions in three places: RegexExtractionStrategy.custom, the regex field type in a JsonCssExtractionStrategy / JsonXPathExtractionStrategy schema, and RegexChunking.patterns. An authenticated API client can send a pattern with catastrophic backtracking and a page that triggers it. Python's re holds the interpreter lock while it matches, so one request stops the whole server, for all users, for as long as the match runs.

Details

RegexExtractionStrategy and RegexChunking are in UNTRUSTED_ALLOWED_TYPES in crawl4ai/async_configs.py but have no entry in UNTRUSTED_FIELD_ALLOWLIST, so _filter_untrusted_fields() keeps their custom and patterns fields. RegexExtractionStrategy.__init__() compiles each custom pattern and extract() runs it with finditer() over the crawled content. JsonCssExtractionStrategy runs re.search(pattern, value) for every schema field of type regex. RegexChunking.chunk() runs re.split(pattern, ...). None of these bound the pattern or the run time.

Extraction runs in a worker thread, but Python's re engine does not release the GIL during a match, so the event loop cannot serve any other request. The crawl deadline (asyncio.wait_for) cannot interrupt the match either. With the pattern (a+)+$ and a page containing "a" * n + "X", the run time grows about 4x for every 2 more characters: about 1.5 s at n=24, and hours at n=40.

Proof of concept

Server: crawl4ai 0.9.4 Docker image with default settings and a valid API token in $TOKEN.

Serve a page at https://attacker.example/ whose text holds aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaX.

curl -s http://localhost:11235/crawl -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{
  "urls": ["https://attacker.example/"],
  "crawler_config": {"type": "CrawlerRunConfig", "params": {
    "extraction_strategy": {"type": "RegexExtractionStrategy", "params": {"custom": {"evil": "(a+)+$"}}}
  }}
}'

Result: the request is accepted. The match backtracks exponentially, and the whole server stops answering, including /health, because re holds the GIL. The crawl deadline does not stop it.

The same works with RegexChunking ("chunking_strategy": {"type": "RegexChunking", "params": {"patterns": ["(a+)+$"]}}) and with a "type": "regex", "pattern": "(a+)+$" field in a JsonCssExtractionStrategy schema.

Library-level timing, no network: with 24 a characters each case takes 1 to 3 seconds, and every 2 more characters is about 4 times slower.

Impact

Any authenticated API client can make the Docker server stop answering every request, including health checks, with one /crawl request. No optional extras are needed. Confidentiality and integrity are not affected.

The library used directly is not affected unless an application passes untrusted regular expressions into these strategies.

Patch

Untrusted request bodies may no longer supply regular expressions: RegexExtractionStrategy.custom, RegexChunking.patterns, and schema fields of type regex in JsonCssExtractionStrategy, JsonXPathExtractionStrategy and JsonLxmlExtractionStrategy are refused. The built-in RegexExtractionStrategy patterns stay available. Fixed in 0.9.5.

Workaround

At your reverse proxy, reject crawler_config bodies that contain RegexExtractionStrategy, RegexChunking, or a schema field with "type": "regex". Give API tokens only to trusted clients.

Credit

Reported by Zhixi "Jace" Sun (manus-use), independent security researcher.

Text from GitHub Advisory Database

Affected versions 1

  • crawl4ai, pip>= 0.9.0, <= 0.9.4GitHub