버전 4.7.4

릴리스 날짜: 2026년 7월 7일

CodeIgniter4 4.7.4 릴리스

보안

  • IncomingRequest: 클라이언트가 제공한 헤더를 통한 HTTPS 감지 문제를 수정했습니다. IncomingRequest::isSecure()는 이제 요청이 Config\\App::$proxyIPs에 설정된 신뢰할 수 있는 프록시로부터 온 경우에만 X-Forwarded-Proto와 Front-End-Https 헤더를 신뢰합니다. 자세한 내용은 보안 권고 GHSA-7wmf-pw8j-mc78를 참조하십시오.

  • Query Builder: deleteBatch()의 SQL 인젝션 취약점을 수정했습니다. deleteBatch()를 where() 조건과 함께 사용하면, WHERE 절의 바인딩 값이 이스케이프 플래그가 무시된 채로 생성된 SQL에 대입되어 이스케이프되거나 인용부호로 감싸지지 않았습니다. 이제 WHERE 바인딩도 일반 delete()와 동일한 방식으로 이스케이프됩니다.

    자세한 내용은 보안 권고 GHSA-c9w5-rwh3-7pm9를 참고하세요.

  • UploadedFile: 두 번째 인자 없이 호출할 경우, UploadedFile::move()가 이제 클라이언트가 제공한 파일 이름을 살균(sanitize)합니다. 이전에는 살균되지 않은 클라이언트 파일 이름이 기본값으로 사용되어, 경로 순회(path traversal) 시퀀스(예: ../../public/shell.php)로 인해 업로드된 파일이 의도한 디렉터리 밖에 기록될 수 있었습니다. 두 번째 인자로 명시적으로 전달한 이름은 살균되지 않으며, 이는 호출자의 책임으로 남습니다. 자세한 내용은 보안 권고 GHSA-hhmc-q9hp-r662를 참조하십시오.

  • Validation: is_image와 mime_in 파일 업로드 유효성 검사 규칙이 이제 비어 있지 않은 클라이언트 파일명 확장자도 함께 검증합니다. 이전에는 이 규칙들이 콘텐츠로부터 유추한 MIME 타입만으로 업로드를 판별했기 때문에, 위험한 클라이언트 확장자를 가진 파일(예: 이미지 매직 바이트가 앞에 붙은 .php 파일)이 원래 확장자를 디스크에 유지한 채로 유효성 검사를 통과할 수 있었습니다. 자세한 내용은 보안 권고 GHSA-mmj4-63m4-r6h5를 참조하십시오.

    is_image 규칙은 이제 비어 있지 않은 클라이언트 파일명 확장자가 이미지 확장자가 아니면 업로드를 거부합니다. mime_in 규칙은 이제 비어 있지 않은 클라이언트 파일명 확장자가 감지된 파일 콘텐츠와 일치하지 않으면 업로드를 거부하며, 이는 ext_in이 사용하는 확장자/콘텐츠 일치 방식과 동일합니다. 확장자가 전혀 없이 업로드된 파일(예: JavaScript Blob 업로드)은 규칙이 파일 콘텐츠를 검증하므로 여전히 허용됩니다.

버그 수정

  • API: 트랜스포머(Transformer)에서 루트 요청의 fields와 include 쿼리 파라미터가 include*() 메서드 내부에서 생성된 중첩 트랜스포머로 새어 들어가, 잘못된 필드 필터링·예상치 못한 include·무한 재귀를 유발하던 버그를 수정했습니다.

  • Commands: make:model --return entity가 관련 Entity 클래스를 생성할 때 하위 네임스페이스를 유지하지 않던 버그를 수정했습니다.

  • Common: env()에 문자열이 아닌 값을 전달했을 때 TypeError가 발생할 수 있던 버그를 수정했습니다.

  • Common: esc()가 인코딩을 올바르게 전파하고 참조 누수(reference leak)를 방지하도록 수정했습니다.

  • Commands: spark lang:find가 프레임워크나 다른 네임스페이스에서 이미 제공하는 번역 키(예: system/Language의 Errors.*)를 새로운 것으로 취급하여 --show-new목록에 나열하고, 기존 번역을 덮어쓰는 미번역 자리표시자를 app/Language에 기록하던 버그를 수정했습니다.

  • Config: BaseService::injectMock이 strtolower를 일관되게 적용하지 않아 서비스와 Mock의 등록·해석이 일관되지 않던 버그를 수정했습니다.

  • Database: 지원되지 않음에도 불구하고 쿼리 빌더 where() 조건 뒤에 updateBatch()를 호출할 수 있던 버그를 수정했습니다. 이제 이런 경우 DatabaseException이 발생합니다.

  • Database: BaseUtils::getXMLFromResult()에서 데이터베이스 값 0이나 '0'이 빈 값으로 취급되어 생성된 XML 내보내기에서 누락되던 버그를 수정했습니다.

  • Encryption: SodiumHandler에서 key 없이 런타임 blockSize를 재정의할 때 잘못 처리되던 문제, 잘못된 키 길이에서 Sodium 네이티브 오류가 그대로 노출되던 문제, 복호화 시 blockSize 값이 일치하지 않으면 EncryptionException대신 SodiumException이 발생하던 버그들을 수정했습니다.

  • Filters: InvalidChars 필터가 배열 키에 있는 잘못된 UTF-8이나 제어 문자를 검사하지 않던 버그를 수정했습니다.

  • HTTP: IncomingRequest::getPostGet()과 IncomingRequest::getGetPost()에 인덱스 배열을 전달하면 TypeError가 발생하던 버그를 수정했습니다.

  • HTTP: User Agent 라이브러리가 Version 토큰의 브라우저 버전 대신 Safari의 WebKit 버전을 보고하던 버그를 수정했습니다.

  • Model: Model::objectToRawArray()에서 $recursive 파라미터가 무시되던 버그를 수정했습니다.

  • Security: 설정된 지시자(directive) 값에 대해 ini_get_all()이 null을 반환할 때 CheckPhpIni에서 타입 오류가 발생할 수 있던 버그를 수정했습니다.

  • Session: 세션 잠금을 획득할 때 RedisHandler가 설정된 $lockMaxRetries와 $lockRetryInterval 값을 반영하지 않던 버그를 수정했습니다.

  • Testing: StreamFilterTrait도 함께 사용하는 테스트에서 MockInputOutput을 사용하면 해당 트레이트의 스트림 필터가 해제되어, MockInputOutput상호작용 이후(예: tearDown())에 출력되는 CLI 출력이 더 이상 캡처되지 않고 콘솔로 새어 나가던 버그를 수정했습니다.

  • Validation: required_without 규칙 로직에서 배열 점(dot) 표기법을 사용하면 이후 필드를 무시한 채 조기 종료되고, 누락된 키에 대해 Undefined array key 경고가 발생하던 버그들을 수정했습니다.

수정된 버그의 전체 목록은 저장소의 CHANGELOG.md를 참고하세요.