CVE-2026-91940 is an arbitrary file write in crawl4ai's PDF scraping strategy. A crafted configuration sent to the Docker API can place attacker-controlled bytes in any directory the service account can write. NVD scores it High (7.5). Upgrade crawl4ai to 0.9.3.
What's affected
The GitHub advisory lists crawl4ai from 0.9.0 through 0.9.2 as affected and 0.9.3 as patched. The NVD record words it as before 0.9.3, while the VulnCheck page gives the range as 0.9.0 up to but not including 0.9.3. Use the narrower range if you want to be exact, and upgrade either way.
The weakness is CWE-22, path traversal. The vector is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N: no login, network reachable, integrity impact only. VulnCheck lists a CVSS v4 score of 8.7. The advisory is rated High.
The advisory also states limits. The process runs as a non-root user, only the directory is chosen by the attacker (the file name pattern is fixed), and no code execution was demonstrated.
How to check if you're exposed
Check the package version:
pip show crawl4ai
If you run the official Docker image, check the tag. The advisory says the image ships the PDF library needed to reach the vulnerable code, so no extra install is required for it to be reachable.
Then ask who can send request bodies to your crawl endpoint. The attack is submitting a configuration through the API, so an API that is open to untrusted callers, or that sits behind weak authentication, is the exposed case. Also check which directories the service account can write to, since that bounds the effect.
Paste a lockfile or SBOM into the free in-browser dependency scan to see whether this package is in your tree, including as a transitive dependency. Safeguard's reachability analysis can then show whether your code actually calls the affected path, which helps you order the work.
What to do now
- Upgrade crawl4ai to 0.9.3 or later and rebuild any image that pins an older version.
- Put authentication and network restrictions in front of the crawl API. Do not publish it openly.
- Run the container with a read-only root filesystem and one writable data volume.
- Review the service account's writable paths and remove any you do not need.
Why it matters
The Docker API treats configuration in a request body as untrusted and tries to drop unsafe fields. The advisory explains that the filter fails open: if a type has no list of allowed fields, every field that is not on a forbidden list gets through. The PDF strategy has no such list, so its image save directory setting passes straight from an untrusted request to the code that writes files.
The design lesson is to fail closed. An allow list that keeps nothing when it has no entry is safer than one that keeps everything. The advisory says this is the same class of write as an earlier fix, which confined one sink but not this one. The KEV flag in the record is false.
Try it yourself
A file write bug only matters if your code can reach it. This demo shows how reachability analysis separates reachable findings from background noise.
Click through it at your own pace, or open it full screen.
Quick check
Can the attacker run code with this bug?
The advisory says no code execution was demonstrated. It describes writing attacker-controlled bytes to a directory the service account can write.
Is authentication enough?
The advisory notes the attack was shown with authentication on. Upgrading is the fix.
Sources
Last reviewed: 18 October 2026.