Back to Blog
critical SEVERITY7 min read

Local File Inclusion in Crawl4AI Docker API via file:// URL Injection

CVE-2026-26217 is a critical Local File Inclusion (LFI) vulnerability in Crawl4AI versions prior to 0.8.0, where the Docker API fails to restrict `file://` URL schemes, allowing attackers to read arbitrary files from the host filesystem. The fix upgrades `crawl4ai` from `0.7.6` to `0.8.0` in `pyproject.toml` and `uv.lock`, closing a direct path to sensitive file exfiltration in any containerized deployment using this library.

O
By Orbis AppSec
Published May 29, 2026Reviewed June 3, 2026

Answer Summary

CVE-2026-26217 is a critical Local File Inclusion (LFI) vulnerability (CWE-73) in Crawl4AI versions prior to 0.8.0, where the Docker API fails to restrict `file://` URL schemes, allowing unauthenticated attackers to read arbitrary files from the host filesystem. The fix upgrades the `crawl4ai` dependency from `0.7.6` to `0.8.0` in `pyproject.toml` and `uv.lock`, which introduces URL scheme validation that blocks `file://` requests before they reach the crawling engine.

Vulnerability at a Glance

cweCWE-73 (External Control of File Name or Path)
fixUpgrade crawl4ai from 0.7.6 to 0.8.0, which enforces URL scheme validation to block file:// and other non-HTTP(S) schemes
riskAttackers can read arbitrary files from the host filesystem, including secrets, credentials, and configuration files
languagePython
root causeCrawl4AI's Docker API accepted user-supplied URLs without validating or restricting the URL scheme, allowing file:// URIs
vulnerabilityLocal File Inclusion (LFI) via file:// URL scheme

Local File Inclusion in Crawl4AI's Docker API via file:// URL Injection (CVE-2026-26217)

Introduction

The uv.lock and pyproject.toml files in this production codebase pinned Crawl4AI to a version range (>=0.4.0,<1.0.0) that included a critically vulnerable release — 0.7.6. In that version, Crawl4AI's Docker-exposed API accepted file:// URLs as crawl targets without sanitization, meaning any caller with network access to the Docker service could instruct the crawler to read files directly off the host filesystem and return their contents in the API response.

This is not a theoretical edge case. Web scraping and crawling libraries are designed to fetch and return content from URLs — that's their core job. When a file:// scheme slips through input validation, the library does exactly what it's built to do: fetches the "page" and returns the content. The attacker just points it at /etc/passwd, /app/.env, or any secrets mounted into the container.


The Vulnerability Explained

What Is Local File Inclusion (LFI)?

Local File Inclusion occurs when an application uses attacker-controlled input to access files on the local filesystem without proper validation. In web contexts, LFI often appears in path traversal bugs (../../etc/passwd), but in this case the vector is a URL scheme bypass — passing a file:// URI to a component that expects HTTP/HTTPS URLs.

How Crawl4AI 0.7.6 Was Exploited

Crawl4AI is a Python-based web crawling library commonly deployed as a Docker service. Its API accepts a URL parameter specifying what to crawl. In versions prior to 0.8.0, the API endpoint responsible for processing crawl requests did not validate or restrict the URL scheme.

A malicious request targeting the Docker API could look like:

POST /crawl HTTP/1.1
Host: crawl4ai-service:11235
Content-Type: application/json

{
  "urls": ["file:///etc/passwd"],
  "priority": 10
}

Because Crawl4AI's underlying browser automation (Playwright/Chromium) is fully capable of rendering file:// URIs, it would dutifully open the local file, extract its text content, and return it in the API response — no authentication bypass required, no memory corruption needed.

Real-World Impact in This Application

This codebase runs as a web service with Crawl4AI embedded as a production dependency. Any component or endpoint that passes user-influenced URLs to Crawl4AI's crawl function becomes a remote file read primitive. Depending on what's mounted into the Docker container, an attacker could exfiltrate:

  • /etc/passwd — user enumeration
  • /app/.env — API keys, database credentials, OAuth secrets
  • /run/secrets/* — Docker secrets mounted at runtime
  • /proc/self/environ — environment variables including injected credentials
  • Service account tokens at /var/run/secrets/kubernetes.io/serviceaccount/token in Kubernetes deployments

The severity rating of CRITICAL is well-justified: a single unauthenticated POST request can yield credentials that pivot an attacker from the container to backend databases, cloud providers, or internal APIs.


The Fix

What Changed in pyproject.toml

The vulnerable version constraint was:

# BEFORE (vulnerable)
"Crawl4AI>=0.4.0,<1.0.0",

This range permitted any 0.x release, including 0.7.6 — the last vulnerable version. The fix pins to a safe minimum:

# AFTER (fixed)
"crawl4ai>=0.8.0",

Two things changed here beyond the version bump:
1. The package name casing was normalized (Crawl4AIcrawl4ai) for consistency with PyPI canonical naming.
2. The upper bound <1.0.0 was removed, allowing future 0.8.x and 1.x releases to be adopted without manually updating the constraint — important for receiving future security patches automatically.

What Changed in uv.lock

The uv.lock file records the exact resolved dependency graph including hashes for supply-chain integrity. Upgrading crawl4ai also pulled in a minor update to alibabacloud-tea-openapi (0.4.30.4.4), reflected in updated SHA-256 hashes:

# BEFORE
sdist = { ..., hash = "sha256:12aef036ed993637b6f141abbd1de9d6199d5516f4a901588bb65d6a3768d41b" }

# AFTER  
sdist = { ..., hash = "sha256:1b0917bc03cd49417da64945e92731716d53e2eb8707b235f54e45b7473221ce" }

These hash changes are expected and verified — they confirm the lockfile reflects the actual packages being installed, not a tampered supply chain artifact.

How the Fix Resolves the LFI

Crawl4AI 0.8.0 introduces URL scheme validation in the crawl request handler. Before dispatching a URL to the browser engine, the library now checks that the scheme is within an allowlist (e.g., http, https). A file:// URL is rejected at the input validation layer, never reaching Playwright, and the API returns an error rather than file contents.


Prevention & Best Practices

1. Always Validate URL Schemes Before Crawling

Any code that accepts URLs from external sources and passes them to a fetch/crawl/render function must validate the scheme:

from urllib.parse import urlparse

ALLOWED_SCHEMES = {"http", "https"}

def validate_crawl_url(url: str) -> str:
    parsed = urlparse(url)
    if parsed.scheme not in ALLOWED_SCHEMES:
        raise ValueError(f"Disallowed URL scheme: {parsed.scheme!r}")
    return url

This is a one-line defense that blocks file://, ftp://, data://, javascript://, and other dangerous schemes.

2. Pin Dependencies to Safe Minimum Versions, Not Ranges

The original constraint >=0.4.0,<1.0.0 was dangerously permissive. It allowed the resolver to pick any version in a two-year release window, including ones with known CVEs. Best practice:

  • Do use >=0.8.0 to enforce a safe minimum.
  • Don't use open upper bounds like <1.0.0 when you haven't reviewed all intermediate versions.
  • Do use lockfiles (uv.lock, poetry.lock, requirements.txt with hashes) to pin exact versions in production.

3. Treat Crawling Services as High-Risk Attack Surface

Docker-exposed crawling APIs are particularly dangerous because:
- They have broad filesystem/network access by design.
- They often run with elevated privileges to launch browser processes.
- They're frequently deployed without authentication on internal networks.

Apply defense-in-depth: network policies to restrict who can reach the crawl service, read-only filesystem mounts where possible, and seccomp/AppArmor profiles to limit syscall surface.

4. Use Automated Dependency Scanning

This vulnerability was caught by Trivy (CVE-2026-26217), a container and dependency scanner. Integrate scanners into your CI pipeline:

# Example GitHub Actions step
- name: Run Trivy vulnerability scanner
  uses: aquasecurity/trivy-action@master
  with:
    scan-type: 'fs'
    scan-ref: '.'
    severity: 'CRITICAL,HIGH'
    exit-code: '1'

Failing the build on CRITICAL findings ensures vulnerabilities like this are caught before deployment.

5. Relevant Security Standards

  • OWASP Top 10 A01:2021 – Broken Access Control: LFI is a classic broken access control issue where the application fails to restrict access to local resources.
  • CWE-73: External Control of File Name or Path: Directly applicable — the URL path is externally controlled and used to access local files.
  • CWE-184: Incomplete List of Disallowed Inputs: The root cause in 0.7.6 was the absence of a scheme denylist/allowlist.

Key Takeaways

  • file:// URLs are a red flag in any crawling or fetch context. Crawl4AI 0.7.6's Docker API accepted them without question, turning the crawler into a remote file read tool. Always validate URL schemes before dispatching to a browser engine or HTTP client.

  • The version constraint >=0.4.0,<1.0.0 in pyproject.toml was the root enabler. It silently permitted a vulnerable version to be resolved. Pinning to >=0.8.0 closes the window and ensures the safe minimum is enforced at install time.

  • Lockfile hashes in uv.lock are your supply-chain integrity check. The updated SHA-256 values for alibabacloud-tea-openapi confirm the dependency graph is consistent and untampered after the upgrade.

  • Docker-exposed crawling services deserve the same threat modeling as public APIs. Internal network placement is not a security boundary — any compromised service or SSRF in another component can reach it.

  • Trivy caught this before it became an incident. Static dependency scanning in CI is a low-cost, high-value control that surfaces CVEs like this one automatically, without requiring manual review of every transitive dependency.


Conclusion

CVE-2026-26217 is a sharp reminder that the attack surface of a web service extends to every library it depends on — including seemingly "safe" utility libraries like web crawlers. Crawl4AI's core feature (fetching and returning URL content) became a critical vulnerability the moment file:// URLs were allowed through. The fix is a single version bump in pyproject.toml and a lockfile refresh, but the lesson is architectural: never trust URL input, always validate schemes, and let your dependency scanner catch what code review misses.

Upgrading to crawl4ai>=0.8.0 closes this specific hole. Combining that with URL scheme validation in your own code, network-level access controls on crawl services, and automated CVE scanning in CI ensures you're not one malformed URL away from leaking your production secrets.


This vulnerability was identified and remediated automatically by OrbisAI Security. Automated security fixes reduce mean time to remediation for dependency CVEs from days to minutes.

Frequently Asked Questions

What is Local File Inclusion (LFI)?

Local File Inclusion (LFI) is a vulnerability where an attacker can trick an application into reading and exposing files from the server's local filesystem, typically by supplying a crafted file path or URL scheme like file://.

How do you prevent LFI in Python web APIs?

Validate and allowlist URL schemes before processing any user-supplied URL. Only permit http:// and https:// schemes, and reject or sanitize any input containing file://, ftp://, or other non-web schemes using explicit checks before passing URLs to crawling or fetching libraries.

What CWE is Local File Inclusion?

Local File Inclusion is most commonly classified as CWE-73: External Control of File Name or Path, which covers cases where user-controlled input is used to determine what file the application accesses.

Is running Crawl4AI in Docker enough to prevent this LFI?

No. Without URL scheme validation, an attacker can still supply a file:// URL that causes the crawler to read files inside the container, which may include mounted secrets, environment files, or host-mapped volumes. Containerization reduces but does not eliminate the risk without the patch.

Can static analysis detect this type of LFI vulnerability?

Yes. Static analysis tools like Semgrep and Bandit can detect patterns where user-supplied input flows into URL-fetching functions without scheme validation. Orbis AppSec automatically detected this specific vulnerability by tracing tainted URL input to the crawl sink.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #15415

Related Articles

critical

How arbitrary code execution via injected protobuf definition type fields happens in Node.js and how to fix it

A critical arbitrary code execution vulnerability (CVE-2026-41242) was discovered in protobufjs versions prior to 7.5.5 and 8.0.1, allowing attackers to inject malicious code through crafted protobuf definition type fields. The fix upgrades the dependency from the vulnerable version 6.11.4 to 7.5.5, which properly sanitizes type field inputs during protobuf parsing. This vulnerability is especially dangerous because protobufjs is widely used in Node.js applications for serialization, meaning a s

critical

How WebSocket protocol length header abuse happens in Node.js and how to fix it

A critical vulnerability (CVE-2026-54466) in websocket-driver versions prior to 0.7.5 allows attackers to corrupt WebSocket messages by manipulating protocol length headers. This can lead to data integrity issues, denial of service, or potentially arbitrary code execution in affected Node.js applications. The fix involves upgrading the websocket-driver dependency to version 0.7.5.

critical

How unsafe token deserialization happens in Node.js Temml parser and how to fix it

A critical vulnerability in the Temml math library's parser allowed unsafe token deserialization that could lead to remote code execution when processing user-supplied mathematical expressions. The fix adds strict type validation on fetched token properties before use, preventing exploitation of malformed or crafted payloads.

critical

How DOM-based XSS via jQuery .html() happens in JavaScript and how to fix it

A critical DOM-based Cross-Site Scripting (XSS) vulnerability was discovered in CustomRankingInterface.js where user-imported JSON data containing malicious filter names could execute arbitrary JavaScript in victims' browsers. The fix replaces jQuery's unsafe `.html()` method with the safe `.text()` method, preventing script injection while preserving the intended functionality.

critical

How predictable key material generation happens in Node.js pbkdf2 and how to fix it

A critical vulnerability (CVE-2025-6545) in pbkdf2 version 3.1.2 caused the library to silently return predictable key material instead of cryptographically secure keys. This Node.js dependency issue was discovered in the website/package-lock.json file and fixed by upgrading to pbkdf2 3.1.3, preventing potential authentication bypass and data exposure in production systems.

critical

How integer overflow in CsoundMYFLTArray constructor happens in C++ and how to fix it

A critical integer overflow vulnerability was discovered in `Java/cs_glue.cpp` at line 324, where the `CsoundMYFLTArray` constructor multiplied a user-controlled integer `n` by `sizeof(MYFLT)` without checking for overflow before passing the result to `malloc`. An attacker supplying a value near `INT_MAX` could trigger the overflow, causing an undersized heap allocation that subsequent writes would overflow. The fix adds an explicit `SIZE_MAX / sizeof(MYFLT)` guard and replaces `malloc` with `ca