Skip to content

Latest commit

 

History

History
287 lines (228 loc) · 11.9 KB

File metadata and controls

287 lines (228 loc) · 11.9 KB

Crawl4AI Chromium launch argument injection RCE (CVE-2026-57572)

메타데이터

항목 내용
CVE ID CVE-2026-57572
영향 제품 Crawl4AI Docker API server
영향 버전 crawl4ai 0.8.9 이하
수정 버전 crawl4ai 0.9.0
CVSS v3.1 10.0 Critical - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
CWE CWE-88, CWE-94
공개일 2026-06-18
분석 기준 GitHub Security Advisory 및 v0.8.9/v0.9.0 공개 코드 정적 확인

개요

CVE-2026-57572는 Crawl4AI Docker API가 네트워크 요청 본문에서 전달된 browser_config.extra_args를 Chromium 실행 인자로 넘기면서 발생한 원격 코드 실행 취약점이다. 공식 GitHub Security Advisory에 따르면 Docker API는 기본적으로 인증 없이 노출될 수 있고, /crawl, /crawl/stream, /crawl/job 경로가 요청 제공 browser_config.extra_args를 받을 수 있었다.

핵심은 "브라우저 설정"처럼 보이는 값이 실제로는 OS 프로세스 생성 정책을 바꾸는 권한 있는 입력이라는 점이다. Chromium의 일부 launch switch는 단순 기능 토글이 아니라 renderer, utility, GPU 같은 자식 프로세스를 어떤 명령으로 실행할지에 영향을 준다. 신뢰할 수 없는 HTTP 요청이 이 필드를 설정할 수 있으면, 웹 크롤링 API가 컨테이너 내부 명령 실행 인터페이스로 바뀐다.

사전 지식

Crawl4AI Docker API의 신뢰 경계

Crawl4AI는 Python SDK로도 사용할 수 있고, Docker API 서버로도 사용할 수 있다. SDK 내부 호출자는 대개 같은 애플리케이션 코드 안에서 설정 객체를 만든다. 반면 Docker API의 요청 본문은 네트워크 클라이언트가 보낸 JSON이다. 같은 BrowserConfig 구조를 쓰더라도 출처가 다르다.

신뢰 가능한 경로

  애플리케이션 코드
        │
        ▼
  BrowserConfig(...) 직접 생성
        │
        ▼
  크롤러가 브라우저 실행

신뢰 불가능한 경로

  원격 HTTP 클라이언트
        │
        ▼
  JSON request body
        │
        ▼
  BrowserConfig.load(...)
        │
        ▼
  크롤러가 브라우저 실행

두 경로의 보안 요구사항은 다르다. SDK 호출자는 extra_args, proxy, user_data_dir, cdp_url 같은 강력한 필드를 쓸 수 있어야 한다. 그러나 원격 요청 본문에서 같은 필드를 허용하면 서버 운영자가 정해야 할 브라우저 실행 정책을 외부 사용자가 덮어쓰게 된다.

Chromium launch argument가 위험한 이유

Chromium은 단일 프로세스 프로그램처럼 보이지만 실제로는 여러 역할의 프로세스를 띄운다. 브라우저 프로세스가 전체 생명주기를 조정하고, renderer는 웹 콘텐츠를 처리하며, utility와 GPU 프로세스는 별도 기능을 수행한다.

Chromium 실행 모델의 단순화

  [browser process]
        │
        ├─ exec renderer process
        ├─ exec utility process
        └─ exec gpu process

launch argument는 이 구조의 동작 방식을 바꾼다. 대부분의 switch는 기능 플래그지만, advisory가 지목한 --utility-cmd-prefix, --renderer-cmd-prefix, --gpu-launcher, --browser-subprocess-path 같은 switch는 자식 프로세스 실행 명령에 관여한다. 또한 --no-zygote는 Chromium의 zygote 기반 자식 프로세스 생성 경로를 우회하거나 바꾸는 데 쓰일 수 있다. 따라서 이 인자들은 단순한 크롤링 옵션이 아니라 프로세스 실행 제어면에 가깝다.

평범한 크롤링 설정

  headless=true
  viewport_width=1280
  user_agent="..."

프로세스 실행에 가까운 설정

  extra_args=[
    "--utility-cmd-prefix=...",
    "--renderer-cmd-prefix=...",
    "--browser-subprocess-path=..."
  ]

보안 설계 관점에서 이 차이는 중요하다. 전자는 브라우저 동작의 범위를 조절하지만, 후자는 서버가 어떤 프로그램을 실행할 수 있는지에 영향을 준다. 외부 요청자가 후자를 설정할 수 있으면 "크롤링 작업 요청"과 "프로세스 실행 정책 변경"의 경계가 무너진다.

Denylist가 약한 이유

0.8.9에는 extra_args를 완전히 금지하는 대신 proxy/DNS 관련 플래그를 scrub하는 방어가 있었다. 이 접근은 특정 SSRF 경로에는 도움이 될 수 있지만, Chromium switch 전체를 안전하게 분류하기에는 불리하다. 브라우저 런타임의 launch switch는 많고, 새 switch가 추가될 수 있으며, 어떤 switch는 조합될 때만 위험해진다.

Denylist 모델

  요청 extra_args
        │
        ├─ 알려진 위험 플래그면 제거
        └─ 모르는 플래그면 통과

문제: "모르는 플래그"가 실행 경로를 바꿀 수 있다.

이 취약점은 바로 이 모델의 한계를 보여준다. advisory는 0.8.9의 denylist가 proxy/DNS 플래그에 초점을 맞췄고, command-execution switch를 포괄하지 못했다고 설명한다.

취약점 분석

확인된 사실

공식 GitHub Security Advisory와 공개 코드에서 확인되는 사실은 다음과 같다.

  • 취약점은 요청 제공 browser_config.extra_args가 Chromium launch argument로 흘러가면서 발생한다.
  • 영향 경로는 /crawl, /crawl/stream, /crawl/job이다.
  • 영향 버전은 crawl4ai 0.8.9 이하이고, 수정 버전은 0.9.0이다.
  • 0.8.9의 deploy/docker/api.py는 요청의 browser_configBrowserConfig.load(browser_config)로 역직렬화한 뒤 _enforce_proxy_safety()에서 scrub_browser_extra_args()를 적용한다.
  • 0.9.0의 deploy/docker/api.py는 요청 설정을 BrowserConfig.load(..., provenance=Provenance.UNTRUSTED)로 로드한다.
  • 0.9.0의 crawl4ai/async_configs.pyUNTRUSTED_FORBIDDEN_FIELDS["BrowserConfig"]extra_args, proxy, proxy_config, user_data_dir, cdp_url, init_scripts 등 power field를 포함하고, 금지 필드가 있으면 UntrustedConfigError를 발생시킨다.

취약 동작 원리

패치 전 모델은 다음과 같다.

공격자 HTTP 요청
  {
    "browser_config": {
      "extra_args": ["Chromium child-process launch switch ..."]
    }
  }
        │
        ▼
Docker API handler
        │
        ▼
BrowserConfig.load(browser_config)
        │
        ▼
_enforce_proxy_safety()
  └─ proxy/DNS 중심 scrub
        │
        ▼
AsyncWebCrawler / Playwright
        │
        ▼
Chromium launch args
        │
        ▼
Chromium이 자식 프로세스 실행 경로를 변경
        │
        ▼
컨테이너 런타임 사용자 권한의 명령 실행 가능

여기서 깨진 불변식은 "원격 요청자는 서버의 브라우저 실행 정책을 바꿀 수 없어야 한다"이다. extra_args가 크롤링 편의 기능처럼 노출되었지만 실제 의미는 더 강했다. 특히 자식 프로세스 실행을 바꾸는 launch switch는 서버 내부 프로세스 생성 경로에 직접 닿는다.

이 취약점은 문자열 command injection과 다르다. 쉘 명령 줄을 문자열로 이어 붙이다가 quoting이 깨진 문제가 아니라, 구조화된 설정 필드가 Chromium의 합법적인 process launch switch로 전달된 문제다. 그래서 특정 문자를 escape하는 방식보다 "이 필드는 untrusted request에서 설정할 수 없다"는 출처 기반 정책이 더 알맞다.

일반적인 shell injection

  "cmd " + user_input
        │
        ▼
  shell metacharacter 해석

이번 취약점의 성격

  user JSON field
        │
        ▼
  BrowserConfig.extra_args
        │
        ▼
  Chromium이 정의한 launch switch 의미로 해석

영향

advisory는 영향도를 컨테이너 런타임 사용자 권한의 unauthenticated RCE로 설명한다. 성공하면 애플리케이션 데이터, 마운트된 secret, 환경 변수, 토큰을 읽거나 수정할 수 있고, HTTP 응답 경로와 무관하게 외부로 데이터를 유출할 수도 있다.

컨테이너에서 실행된다는 사실은 중요하지만, 취약점이 사라지는 것은 아니다. 컨테이너 내부에는 크롤러 설정, API 토큰, 작업 데이터, 마운트된 볼륨이 있을 수 있다. 또한 컨테이너가 과도한 권한이나 넓은 네트워크 egress를 갖고 있으면 내부망 접근이나 후속 이동의 발판이 될 수 있다.

수정 방법

0.9.0의 수정 방향은 denylist 확장이 아니라 신뢰 경계 재정의다. Docker API 요청 본문을 Provenance.UNTRUSTED로 표시하고, untrusted 설정에서 power field를 설정하면 HTTP 400으로 거부한다. SDK나 서버 내부 코드처럼 trusted 경로에서 extra_args를 쓰는 기능은 유지된다.

패치 후 모델

원격 HTTP 요청
  {
    "browser_config": {
      "extra_args": [...]
    }
  }
        │
        ▼
BrowserConfig.load(..., provenance=UNTRUSTED)
        │
        ▼
UNTRUSTED_FORBIDDEN_FIELDS 검사
        │
        ├─ extra_args 존재 → UntrustedConfigError
        │                  → HTTP 400 Rejected request
        │
        └─ 허용된 scalar field만 통과
                           │
                           ▼
                  Chromium 실행

이 패치는 두 가지 설계 원칙을 보여준다.

첫째, 설정 객체를 재사용하더라도 출처를 함께 전달해야 한다. 같은 BrowserConfig라도 SDK에서 직접 만든 객체와 원격 JSON에서 역직렬화한 객체는 권한이 다르다.

둘째, 보안상 강한 필드는 scrub보다 거부가 낫다. extra_args처럼 하위 런타임의 큰 제어면을 노출하는 필드는 안전한 값 목록을 계속 추적하기 어렵다. 0.9.0은 extra_args뿐 아니라 proxy, proxy_config, user_data_dir, cdp_url, init_scripts 같은 필드도 untrusted request에서 금지한다.

운영자는 crawl4ai를 0.9.0 이상으로 업데이트해야 한다. 즉시 업데이트가 어렵다면 Docker API에 CRAWL4AI_API_TOKEN 인증을 켜고, API 접근 네트워크를 제한하며, 컨테이너 egress와 seccomp 정책을 강하게 제한해야 한다. 다만 advisory가 지적하듯 인증과 네트워크 제한은 보완책이며, 취약한 버전에서 extra_args 신뢰 경계가 고쳐지는 것은 아니다.

PoC 관련 언급

이 리포트는 PoC를 실행하지 않았다. 공식 advisory는 보고자들이 --no-zygote--utility-cmd-prefix, --renderer-cmd-prefix 계열의 재현 체인을 보고했다고 설명하지만, 여기서는 공격 문자열이나 실행 가능한 요청 본문을 재구성하지 않는다. 신뢰도 판단은 공개 advisory와 v0.8.9/v0.9.0 코드의 정적 차이에 근거한다.

미해결/불확실 지점

  • 이 분석은 공개 GitHub advisory와 공개 태그 코드 기준이다. 별도 private report 원문은 확인하지 않았다.
  • advisory가 언급한 개별 Chromium switch의 실제 조합별 동작은 이 저장소에서 실행 검증하지 않았다.
  • NVD 상세 페이지는 후보 상태 파일의 요약과 일치하지만, 본문 작성 시점의 핵심 근거는 GitHub Security Advisory와 upstream 코드다.

참고 자료