CVE-2026-109618
요청 초기화 중 메모리 한도 초과
PHP 는 폼 데이터를 해시 테이블에 담습니다. 칸을 하나 늘릴 때 키를 할당하기 전에 개수 카운터를 먼저 올리는 구간이 있습니다.
그 할당이 memory_limit 에 걸리면 PHP 는 치명적 오류를 내고 삽입을 포기합니다. 카운터는 이미 올라간 뒤라, 값이 들어가지 않은 칸이 테이블에 남습니다.
요청 종료 시점에 PHP 는 그 테이블을 정리하면서 빈 칸의 잔여 바이트를 정상적인 PHP 값으로 해석합니다. 이 지점에서 공격자가 영향을 줄 수 있는 호출이 일어납니다.
발생 시점이 요청 파싱 도중입니다. 대상 스크립트가 실행되기 전이라 애플리케이션 코드에는 막을 자리가 없습니다.
트리거중첩 배열 표기와 비정상적으로 긴 필드 이름을 포함한 POST
CVE-2026-109619
요청 간 전역 상태 잔존
PHP 워커 하나는 요청을 여러 번 처리합니다. 워커 전역 변수 중 일부는 특정 요청이 소유한 메모리를 가리킵니다.
그 메모리를 해제하면서 참조를 비우지 않으면 다음 요청이 이미 해제된 메모리를 따라갑니다. use-after-free 입니다.
상태가 남는 경로는 둘입니다. 치명적 오류가 정리 도중에 끼어드는 경우, 그리고 종료 단계의 진단 출력이 정리된 상태를 되살리는 경우입니다.
업로드 경로가 특히 문제입니다. session.upload_progress 는 기본값이 활성이고, 애플리케이션이 session_start() 를 호출하지 않아도 동작합니다.
트리거치명적 오류 발생 후 동일 워커로 전달되는 업로드 요청
로그에 남는 흔적
php-fpm error log
PHP Fatal error: Allowed memory size of 16777216 bytes exhausted (tried to allocate 3500032 bytes) in Unknown on line 0
apache error log
[mpm_prefork:notice] AH00052: child pid 3421 exit signal Segmentation fault (11)
access log
POST /index.php HTTP/1.1" 500 - "-" "-" 동일 워커에서 짧게 몰린 뒤 소강
in Unknown on line 0 — 스크립트가 아니라 요청 초기화 중에 발생했다는 표시입니다. 메모리 오류만으로 공격을 단정할 수는 없습니다. 반대로 로그가 조용하다고 안전한 것도 아닙니다. 성공한 공격은 워커를 종료시키지 않고 지나갈 수 있습니다.
임시 완화 조치
노출면을 줄이는 임시 조치입니다. 변종을 모두 막지는 못합니다.
- post_max_size 하향
- 파서가 점유하는 메모리를 줄입니다. 업로드 한도와 함께 검토해야 합니다.
- max_input_nesting_level 하향
- 중첩 배열 표기로 메모리를 밀어 올리는 경로를 좁힙니다.
- session.upload_progress.enabled = 0
- 109619 의 업로드 경로를 막습니다. 기본값이 활성이라 대부분 그대로 둔 상태입니다.
- display_errors = 0
- 오류 본문을 통한 정보 노출을 줄입니다.
- pm.max_requests 하향
- 워커를 자주 교체해 손상된 상태가 오래 남지 않게 합니다. 성능 저하는 일부 감수해야 합니다.