
최근 PHP의 원격 코드 실행 취약점으로 웹사이트 운영자들이 긴급 패치에 나선 가운데, Python과 Node.js에서 사용하는 압축 라이브러리에서도 원격 코드 실행으로 이어질 수 있는 취약점이 공개돼 대응이 필요하다.
PHP와 Node.js는 10월 21일 보안 패치를 내놨다. PHP2Shell, Python2Shell, Node2Shell이라는 이름이 함께 등장하지만, 운영자가 확인할 대상은 두 갈래다. PHP2Shell은 PHP 코어의 메모리 처리 문제다. Python2Shell과 Node2Shell은 압축 라이브러리 Brotli의 같은 결함을 각 실행 환경에서 부르는 이름이다. 사용하는 언어보다 취약한 코드가 어디에 들어 있고, 외부 데이터를 어떤 경로로 처리하는지가 중요하다.[1][4][7]
PHP2Shell은 애플리케이션 코드가 실행되기 전에도 위험하다
로그인 검사보다 먼저 실행될 수 있는 요청 처리 단계
mod_php뿐 아니라 PHP-FPM도 패치 대상
PHP2Shell에는 두 취약점이 있다. CVE-2026-109618은 메모리가 부족해 요청 처리를 중단할 때, 초기화가 덜 된 내부 데이터를 정리 과정에서 정상 데이터처럼 다루는 문제다. CVE-2026-109619는 이전 요청의 메모리를 해제한 뒤에도 워커에 남은 상태를 다음 요청에서 다시 사용하는 문제다. 둘 다 공격자가 웹 워커 권한으로 코드를 실행하는 결과로 이어질 수 있다.[2][3]
PHP 보안팀이 가장 위험하다고 본 구성은 아파치(Apache)의 mod_php다. 조작된 요청 본문을 자동으로 읽는 단계에서 공격이 시작될 수 있어, 애플리케이션의 로그인 검사나 입력 검증 코드가 실행되기 전에 문제가 생긴다. 파일 업로드 화면을 만들지 않았다는 이유만으로 요청 처리기의 노출을 제외해서는 안 된다.[1][2]
PHP-FPM도 패치 대상이다. FPM은 요청 시작 단계에서 메모리 부족이 발생하면 자식 프로세스를 종료해 mod_php의 일부 경로를 피한다. 그러나 정상적으로 시작된 요청 안에서 발생하는 메모리 부족 문제까지 제거하지는 않는다. 별개인 전역 상태 취약점에서는 세션 처리 경로를 이용한 원격 코드 실행이 mod_php와 FPM 모두에서 검증됐다. PHP 공식 권고는 php-cgi, FrankenPHP와 LiteSpeed를 포함해 웹 요청을 처리하는 모든 PHP 설치를 점검 대상으로 삼는다.[1][2][3]
Python과 Node.js에서는 Brotli를 푸는 경로를 찾는다
같은 Brotli 디코더 결함을 공유하는 두 실행 환경
외부 요청 본문과 외부 서버 응답 모두 점검
Brotli는 웹 데이터를 작게 전송하기 위한 압축 방식이다. CVE-2026-111497은 구글의 Brotli 디코더가 잘못된 압축 데이터를 처리하다가 허용된 메모리 범위 밖에 쓰는 결함이다. 메모리 유출이나 서비스 중단, 원격 코드 실행으로 이어질 수 있다. Node.js는 이 디코더를 런타임에 포함하고, Python에서는 Brotli와 brotlicffi 패키지가 같은 C 코드를 사용한다. Python 인터프리터만 업데이트해 끝낼 문제가 아니다.[4][6]
외부에서 들어오는 요청뿐 아니라 서버가 외부에 요청한 뒤 받는 응답도 공격 경로다. Node.js의 fetch()로 공격자가 운영하는 서버의 Brotli 응답을 읽으면 내장 디코더가 실행된다. 보안업체 임퍼바(Imperva)는 공식 Node.js 24.22.0 Linux arm64 이미지에서 응답과 요청 본문을 통한 코드 실행을 재현했고, 24.22.1에서는 같은 입력이 거부됐다고 밝혔다. 재현에는 여러 차례 시도가 필요했다.[5]
요청 본문을 처리할 때는 Express 5와 body-parser 2 계열에서 Brotli 압축 해제를 지원하는 파서를 사용하는지 확인한다. 기본 http 서버를 띄웠다는 사실만으로 압축 본문이 자동 해제되는 것은 아니다. 실제로 Content-Encoding: br 데이터를 읽고 푸는 미들웨어나 node:zlib 호출이 있어야 해당 경로에 노출된다. Express 패키지만 올리고 내장 디코더가 남은 Node.js 바이너리를 그대로 쓰는 대응은 충분하지 않다.[5]
Python의 경우 requests가 사용하는 urllib3, aiohttp, httpx 같은 HTTP 클라이언트도 Brotli 지원 의존성이 설치돼 있으면 응답을 자동으로 압축 해제할 수 있다. URL 미리보기, 크롤러, 사용자가 지정한 주소로 웹훅을 보내고 응답을 읽는 기능이 점검 대상이다. 개발자가 직접 압축 해제 함수를 호출하지 않아도 라이브러리가 대신 실행할 수 있다. 외부 요청을 받는 입구만 WAF로 보호해도, 서버가 가져오는 악성 응답까지 차단되는 것은 아니다.[6]
패치는 런타임과 패키지, 실행 중인 워커까지 적용한다
버전 고정 설정과 컨테이너까지 수정 후 재배포
임시 설정 변경이나 WAF만으로는 해결 불가
PHP는 사용하는 계열에 맞춰 8.2.35, 8.3.36, 8.4.27, 8.5.12 이상으로 올려야 한다. 배포판이나 장기 지원 업체가 이전 버전에 수정 사항을 반영한 경우에는 겉으로 보이는 버전 번호만으로 판단하지 말고 해당 패키지의 보안 공지를 확인한다. PHP 프로젝트의 지원이 끝난 8.1 이하를 쓰고 있다면 지원되는 계열로 옮기거나 공급업체의 수정 제공 여부를 확인해야 한다.[1]
Node.js의 수정 릴리스는 22.23.4, 24.22.1, 26.12.1이다. 해당 계열의 수정 버전 이상으로 런타임을 교체해야 한다. Python에서는 설치된 패키지를 기준으로 Brotli 1.2.1 이상, brotlicffi 1.2.1.0 이상을 적용한다. 두 패키지를 모두 새로 설치하라는 뜻은 아니다. 이미 사용하는 패키지를 빠짐없이 찾아 바꾸는 작업이다. Brotli 원본 라이브러리에는 1.0.10, 1.1.1, 1.2.1 수정판이 있으며, 배포판 라이브러리와 Python 패키지의 버전 체계를 구분해야 한다.[4][6][7][8][9]
운영에서는 의존성을 특정 버전에 고정한 설정과 잠금 파일도 함께 갱신하고 컨테이너 이미지를 다시 만들어 배포해야 한다. 업데이트를 마친 뒤에는 모든 웹 워커와 백그라운드 작업 프로세스를 재시작한다. 셸에서 확인한 PHP나 Node.js가 실제 서비스 바이너리와 같은지, Python 패키지를 확인한 가상환경이 서비스의 가상환경인지 대조하는 절차도 필요하다. 설치 파일을 교체해도 기존 프로세스가 메모리에 올려 둔 코드는 그대로 남을 수 있기 때문이다.
바로 패치할 수 없다면 PHP의 session.upload_progress.enabled=0을 요청 해석 전에 적용되는 php.ini, FPM 풀 또는 서버 설정에 넣고 모든 워커를 재시작할 수 있다. 이는 확인된 세션 경로를 줄이는 임시 조치다. 애플리케이션 안의 ini_set()이나 FPM의 .user.ini에 의존해서는 안 된다. PHP 8.5의 fatal_error_backtraces=0도 특정 경로만 막는다. 메모리 한도를 늘리거나 WAF 규칙을 추가하는 조치 역시 두 취약점을 완전히 해결하지 못한다.[1]
10월 23일에는 별도 세션 취약점 CVE-2026-115560에 관한 추가 안내도 나왔다. 설정의 세션 직렬화 방식을 php_binary 또는 php_serialize로 두고, 실행 중에 php로 바꾼 뒤 session_start()를 호출하며 업로드 진행 기능도 켜 둔 특수한 조합이 대상이다. PHP는 다음 정기 수정 릴리스 전까지 업로드 진행 기능을 끄도록 권고했다. 앞선 두 취약점의 패치를 적용했더라도 이 구성에 해당하면 추가 조치를 유지해야 한다.[10]
Brotli 패치를 미뤄야 한다면 신뢰할 수 없는 압축 데이터를 디코더에 전달하는 기능을 임시 중단하거나 Brotli 지원을 비활성화하는 방향으로 대응해야 한다. 요청의 Accept-Encoding에서 br을 빼는 것만으로 공격자가 Brotli 응답을 보내지 못하게 되는 것은 아니다. 들어오는 요청과 가져오는 응답 양쪽에서 실제 압축 해제 전에 차단되는지 확인해야 한다.
패치 완료와 침해 복구는 별개다
공개 전 PHP2Shell 공격 시도를 관측한 AWS
패치 적용 확인과 기존 침해 흔적 조사를 각각 수행
AWS는 MadPot 허니팟에서 공개 전인 10월 17일부터 PHP2Shell 공격 시도를 관측했다고 밝혔다. AWS는 당시 시도가 실제 운영 시스템에서도 성공했을지는 불명확하다고 설명했다. 다만 조사 시작점을 공개일로 한정하지 말고 최소 10월 17일까지 거슬러 올라가라고 권고했다. 웹 서버의 의심스러운 요청, 예상하지 못한 프로세스 실행과 파일 변경을 함께 확인할 필요가 있다.[11]
패치는 앞으로 같은 취약점을 이용하는 공격을 막는 조치다. 이미 침해됐을 가능성이 있다면 로그와 증거를 보존하고 노출 범위를 조사한 뒤, 관련 자격증명 교체와 안전한 이미지로의 복구를 진행해야 한다.
이번 PHP 취약점 발견에도 AI가 활용됐다. OpenAI는 보안업체 Calif가 GPT-5.6 Sol을 이용해 치명적인 결함을 찾았다고 밝혔다.[12] AI를 활용해 소프트웨어의 취약점을 찾아내는 사례가 나오는 만큼, 운영자도 새로운 보안 보고에 신속히 대응할 준비가 필요하다. 사용하는 런타임과 의존성의 보안 패치 소식에 귀를 기울이고, 침해 여부를 빠르게 확인할 수 있도록 로그 수집과 이상 징후 탐지 체계도 마련해야 할 때다.