v4.7.4 (2026-07-07)
-
IncomingRequest: HTTPS detection via client-supplied headers was fixed.
IncomingRequest::isSecure()now trusts theX-Forwarded-ProtoandFront-End-Httpsheaders only when the request comes from a trusted proxy configured inConfig\App::$proxyIPs. See theSecurity advisory GHSA-7wmf-pw8j-mc78 <https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-7wmf-pw8j-mc78>_ for more information. -
Query Builder: Fixed a SQL injection vulnerability in
deleteBatch(). WhendeleteBatch()was used together withwhere()conditions, the bound values from the WHERE clause were substituted into the generated SQL with their escape flag ignored, so they were never escaped or quoted. The WHERE binds are now escaped in the same way as a regulardelete().See the
Security advisory GHSA-c9w5-rwh3-7pm9 <https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-c9w5-rwh3-7pm9>_ for more information. -
UploadedFile:
UploadedFile::move()now sanitizes the client-provided filename when called without a second argument. Previously, the unsanitized client filename was used as the default, allowing path traversal sequences (e.g.../../public/shell.php) to write the uploaded file outside the intended directory. A name explicitly passed as the second argument is not sanitized and remains the caller's responsibility. See theSecurity advisory GHSA-hhmc-q9hp-r662 <https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-hhmc-q9hp-r662>_ for more information. -
Validation: The
is_imageandmime_infile upload validation rules now also verify non-empty client filename extensions. Previously, these rules classified an upload solely by its content-derived MIME type, so a file with a dangerous client extension (for example, a.phpfile prepended with image magic bytes) could pass validation while keeping its original extension on disk. See theSecurity advisory GHSA-mmj4-63m4-r6h5 <https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-mmj4-63m4-r6h5>_ for more information.The
is_imagerule now rejects uploads when a non-empty client filename extension is not an image extension. Themime_inrule now rejects uploads when a non-empty client filename extension does not match the detected file content, matching the same extension/content agreement used byext_in. Files uploaded without any extension (such as JavaScriptBlobuploads) are still accepted, since the rules validate the file content.
- fix: prevent updateBatch with existing where conditions by @michalsn in codeigniter4#10236
- fix: detect Safari version from Version token by @memleakd in codeigniter4#10251
- fix: nested transformer request scope leakage by @michalsn in codeigniter4#10281
- fix(model): pass $recursive parameter to parent in objectToRawArray by @gr8man in codeigniter4#10258
- fix: preserve enclosing stream filter when using
MockInputOutputby @paulbalandan in codeigniter4#10307 - fix: skip already-translated keys in
spark lang:findby @paulbalandan in codeigniter4#10308 - fix(Filters): check both keys and values in
InvalidCharsarrays by @gr8man in codeigniter4#10303 - fix: use dynamic lockMaxRetries limit in RedisHandler by @gr8man in codeigniter4#10295
- fix: preserve sub-namespace when generating Entity from Model (i.e.,
--return entity) by @xgrind in codeigniter4#10232 - fix:
env()TypeError for non-string$_SERVERvalues +esc()fixes by @gr8man in codeigniter4#10305 - fix: unify casing in BaseService::injectMock by @ThomasMeschke in codeigniter4#10316
- fix: normalize SodiumHandler params and padding failures by @gr8man in codeigniter4#10321
- fix(Validation): correct required_without logic and prevent array key warnings by @gr8man in codeigniter4#10328
- fix: handle null ini values in phpini check by @Will-thom in codeigniter4#10233
- fix: preserve zero values in XML export by @gr8man in codeigniter4#10367
- fix: support array indexes in
getPostGet()andgetGetPost()by @michalsn in codeigniter4#10362
- refactor: narrow
Imageoriginal dimension types tointby @michalsn in codeigniter4#10326 - refactor(HTTP): optimize file path parsing in
download()method by @gr8man in codeigniter4#10330 - refactor(database): optimize groupGetType by caching it inside BaseBuilder loops by @gr8man in codeigniter4#10340
- refactor: bump to phpstan-codeigniter v2.1 by @paulbalandan in codeigniter4#10312
- refactor: replace type
mixedwith more specific types by @paulbalandan in codeigniter4#10345 - refactor: optimize
prepQuotedPrintable()with hash lookup and int-length tracking by @gr8man in codeigniter4#10344 - refactor: add precise
arrayphpdocs forCLIby @paulbalandan in codeigniter4#10354 - refactor(database): optimize
_processForeignKeys()string allocations and loop invariants by @gr8man in codeigniter4#10351
v4.7.3 (2026-05-22)
-
Validation: Uploaded file extension validation bypass in
ext_inrule Theext_infile upload validation rule now validates the client filename extension and verifies that it matches the detected MIME type. Previously,ext_inonly checked the MIME-derived guessed extension, so a file with a mismatched client extension could pass validation.See the GHSA-2gr4-ppc7-7mhx security advisory for more information. Credits to @z3moo and @teebow1e for reporting the issue.
- fix: make Autoloader composer path injectable to fix parallel test race condition by @michalsn in codeigniter4#10082
- fix: store SPL closures in
register()sounregister()can remove them by @michalsn in codeigniter4#10097 - fix: ensure output buffer is closed after use of
command()by @paulbalandan in codeigniter4#10099 - fix: preserve null values in Validation::getValidated() by @michalsn in codeigniter4#10101
- fix: refactor inconsistent behavior on
CLI::write()andCLI::error()by @paulbalandan in codeigniter4#10106 - fix: ensure calling
envcommand with options only would not throw by @paulbalandan in codeigniter4#10114 - fix: suppress stty stderr leak in
CLI::generateDimensions()when stdin is not a TTY by @paulbalandan in codeigniter4#10124 - fix: reset Kint CSP state in worker mode by @memleakd in codeigniter4#10139
- fix: make
Time::createFromTimestamplocale-independent by @michalsn in codeigniter4#10151 - fix: SQLSRV driver's
decrement()method by @patel-vansh in codeigniter4#10155 - fix: suppress tput stderr leak when TERM is not present by @paulbalandan in codeigniter4#10167
- fix: support third-party loggers in toolbar logs collector by @michalsn in codeigniter4#10173
- fix: PostgreSQL Builder's
increment()anddecrement()methods not working for numeric columns by @patel-vansh in codeigniter4#10172 - fix: preserve cached table list shape by @memleakd in codeigniter4#10179
- fix: harden regex matching on
key:generatecommand by @paulbalandan in codeigniter4#10183 - fix: restore deep dot-notation traversal in
Language::getLine()by @paulbalandan in codeigniter4#10189 - fix: make frankenphp-worker.php template idempotent on watcher restart by @paulbalandan in codeigniter4#10191
- fix:
Entity::normalizeValue()must handleUnitEnumbeforetoArray()by @maniaba in codeigniter4#10137 - fix: recognize off zlib output compression value by @memleakd in codeigniter4#10193
- fix: escape
--hostoption inservecommand by @paulbalandan in codeigniter4#10203
- refactor: add full testing for
logs:clearcommand by @paulbalandan in codeigniter4#10090 - refactor: add full testing for
debugbar:clearcommand by @paulbalandan in codeigniter4#10093 - refactor: pass
--do-not-cache-resultto prevent shared cache corruption by @michalsn in codeigniter4#10098 - refactor: add full testing for
cache:clearcommand by @paulbalandan in codeigniter4#10094 - refactor: rename
-hoption ofroutescommand as--handlerby @paulbalandan in codeigniter4#10113 - refactor: further rename
--handlerto--sort-by-handlerforroutesby @paulbalandan in codeigniter4#10125 - refactor: UX:
ClearLogs::execute()error message is misleading after interactive'n'by @paulbalandan in codeigniter4#10126 - refactor: simplify
FileLocator::listFiles()by @paulbalandan in codeigniter4#10142 - refactor: reduce PHPStan child return type baseline by @memleakd in codeigniter4#10165
- refactor: remove PHPStan callable signature baseline by @memleakd in codeigniter4#10166
v4.7.2 (2026-03-24)
- fix: preserve JSON body when CSRF token is sent in header by @michalsn in codeigniter4#10064
v4.7.1 (2026-03-22)
- fix: SQLite3 config type handling for
.envoverrides by @michalsn in codeigniter4#10037
- fix: escape CSP nonce attributes in JSON responses by @michalsn in codeigniter4#9938
- fix: correct
savePathcheck inMemcachedHandlerconstructor by @michalsn in codeigniter4#9941 - fix: preserve index field in
updateBatch()whenupdateOnlyChangedistrueby @michalsn in codeigniter4#9944 - fix: Hardcoded CSP Nonce Tags in ResponseTrait by @patel-vansh in codeigniter4#9937
- fix: initialize standalone toolbar by @michalsn in codeigniter4#9950
- fix: add fallback for
appOverridesFolderconfig in View by @michalsn in codeigniter4#9958 - fix: avoid double-prefixing in
BaseConnection::callFunction()by @michalsn in codeigniter4#9959 - fix: generate inputs for all route params in Debug Toolbar by @michalsn in codeigniter4#9964
- fix: preserve Postgre casts when converting named placeholders in prepared queries by @michalsn in codeigniter4#9960
- fix: prevent extra query and invalid size in
Model::chunk()by @michalsn in codeigniter4#9961 - fix: worker mode events cleanup by @michalsn in codeigniter4#9997
- fix: add nonce to script-src-elem and style-src-elem when configured by @michalsn in codeigniter4#9999
- fix:
FeatureTestTrait::withRoutes()may throw all sorts of errors on invalid HTTP methods by @paulbalandan in codeigniter4#10004 - fix: validation when key does not exists by @michalsn in codeigniter4#10006
- fix: handle HTTP/2 responses without a reason phrase in CURLRequest by @michalsn in codeigniter4#10050
- chore: signature for the
$headersparam inFeatureTestTrait::withHeaders()by @michalsn in codeigniter4#9932 - refactor: implement development versions for
CodeIgniter::CI_VERSIONby @paulbalandan in codeigniter4#9951 - feat: Add
builds nextoption by @neznaika0 in codeigniter4#9946 - refactor: use
__unserializeinstead of__wakeupinTimeTraitby @paulbalandan in codeigniter4#9957 - refactor: remove
Exceptions::isImplicitNullableDeprecationErrorby @paulbalandan in codeigniter4#9965 - refactor: fix
Securitytest fail by itself by @paulbalandan in codeigniter4#9969 - refactor: make random-order API tests deterministic by @michalsn in codeigniter4#9983
- refactor: make random-order CLI tests deterministic by @michalsn in codeigniter4#9998
- refactor: fix phpstan no type specified ValidationModelTest by @adiprsa in codeigniter4#10008
- refactor: fix dependency on test execution order by @michalsn in codeigniter4#10014
- refactor: update tests with old entities definition by @michalsn in codeigniter4#10026
v4.7.0 (2026-02-01)
- feat: require double curly braces for placeholders in
regex_matchrule by @michalsn in codeigniter4#9597 - feat(cache): add
deleteMatchingmethod definition in CacheInterface by @yassinedoghri in codeigniter4#9809 - feat(cache): add native types to all CacheInterface methods by @yassinedoghri in codeigniter4#9811
- feat(entity): deep change tracking for objects and arrays by @michalsn in codeigniter4#9779
- feat(model): primary key validation by @michalsn in codeigniter4#9840
- feat(entity): properly convert arrays of entities in
toRawArray()by @michalsn in codeigniter4#9841 - feat: add configurable status code filtering for
PageCachefilter by @michalsn in codeigniter4#9856 - fix: inconsistent
keyhandling in encryption by @michalsn in codeigniter4#9868 - refactor: complete
QueryInterfaceby @paulbalandan in codeigniter4#9892 - feat: add
remember()toCacheInterfaceby @datamweb in codeigniter4#9875 - refactor: Use native return types instead of using
#[ReturnTypeWillChange]by @paulbalandan in codeigniter4#9900
- fix: ucfirst all cookie samesite values by @paulbalandan in codeigniter4#9564
- fix: controller attribute filters with parameters by @michalsn in codeigniter4#9769
- fix: Fixed test Transformers by @neznaika0 in codeigniter4#9778
- fix: signal trait by @michalsn in codeigniter4#9846
- feat: signals by @michalsn in codeigniter4#9690
- feat(app): Added controller attributes by @lonnieezell in codeigniter4#9745
- feat: API transformers by @lonnieezell in codeigniter4#9763
- feat: FrankenPHP Worker Mode by @michalsn in codeigniter4#9889
- feat: add email/smtp plain auth method by @ip-qi in codeigniter4#9462
- feat: rewrite
ImageMagickHandlerto rely solely on the PHPimagickextension by @michalsn in codeigniter4#9526 - feat: add
Time::addCalendarMonths()andTime::subCalendarMonths()methods by @christianberkman in codeigniter4#9528 - feat: add
clearMetadata()method to provide privacy options when using imagick handler by @michalsn in codeigniter4#9538 - feat: add
dns_cache_timeoutfor optionCURLRequestby @ddevsr in codeigniter4#9553 - feat: added
fresh_connectoptions toCURLRequestby @ddevsr in codeigniter4#9559 - feat: update
CookieInterface::EXPIRES_FORMATto use date format per RFC 7231 by @paulbalandan in codeigniter4#9563 - feat: share connection & DNS Cache to
CURLRequestby @ddevsr in codeigniter4#9557 - feat: add option to change default behaviour of
JSONFormattermax depth by @ddevsr in codeigniter4#9585 - feat: customizable
.envdirectory path by @totoprayogo1916 in codeigniter4#9631 - feat: migrations lock by @michalsn in codeigniter4#9660
- feat: uniform rendering of stack trace from failed DB operations by @paulbalandan in codeigniter4#9677
- feat: make
insertBatch()andupdateBatch()respect model rules by @michalsn in codeigniter4#9708 - feat: add enum casting by @michalsn in codeigniter4#9752
- feat(app): Added pagination response to API ResponseTrait by @lonnieezell in codeigniter4#9758
- feat: update robots definition for
UserAgentclass by @michalsn in codeigniter4#9782 - feat: added
async&persistentoptions to Cache Redis by @ddevsr in codeigniter4#9792 - feat: Add support for HTTP status in
ResponseCacheby @sk757a in codeigniter4#9855 - feat: prevent
Maximum call stack size exceededon client-managed requests by @datamweb in codeigniter4#9852 - feat: add
isPast()andisFuture()time convenience methods by @datamweb in codeigniter4#9861 - feat: allow overriding namespaced views via
app/Viewsdirectory by @datamweb in codeigniter4#9860 - feat: make DebugToolbar smarter about detecting binary/streamed responses by @datamweb in codeigniter4#9862
- feat: complete
Superglobalsimplementation by @michalsn in codeigniter4#9858 - feat: encryption key rotation by @michalsn in codeigniter4#9870
- feat: APCu caching driver by @sk757a in codeigniter4#9874
- feat: added
persistentconfig item to redis handlerSessionby @ddevsr in codeigniter4#9793 - feat: Add CSP3
script-src-elemdirective by @mark-unwin in codeigniter4#9722 - feat: Add support for CSP3 keyword-sources by @paulbalandan in codeigniter4#9906
- feat: enclose hash-based CSP directive values in single quotes by @paulbalandan in codeigniter4#9908
- feat: add support for more CSP3 directives by @paulbalandan in codeigniter4#9909
- feat: add support for CSP3
report-todirective by @paulbalandan in codeigniter4#9910
- refactor: cleanup code in
Emailby @ddevsr in codeigniter4#9570 - refactor: remove deprecated types in random_string() helper by @michalsn in codeigniter4#9592
- refactor: do not use future-deprecated
DATE_RFC7231constant by @paulbalandan in codeigniter4#9657 - refactor: remove
curl_closehas no effect since PHP 8.0 by @ddevsr in codeigniter4#9683 - refactor: remove
finfo_closehas no effect since PHP 8.1 by @ddevsr in codeigniter4#9684 - refactor: remove
imagedestroyhas no effect since PHP 8.0 by @ddevsr in codeigniter4#9688 - refactor: deprecated PHP 8.5 constant
FILTER_DEFAULTforfilter_*()by @ddevsr in codeigniter4#9699 - chore: bump minimum required
PHP 8.2by @ddevsr in codeigniter4#9701 - refactor: add the
SensitiveParameterattribute to methods dealing with sensitive info by @paulbalandan in codeigniter4#9710 - fix: Remove check ext-json by @neznaika0 in codeigniter4#9713
- refactor(app): Standardize subdomain detection logic by @lonnieezell in codeigniter4#9751
- refactor: Types for
BaseModel,Modeland dependencies by @neznaika0 in codeigniter4#9830 - chore: remove IncomingRequest deprecations by @michalsn in codeigniter4#9851
- refactor: Session library by @neznaika0 in codeigniter4#9831
- refactor: Superglobals - remove property promotion and fix PHPDocs by @paulbalandan in codeigniter4#9871
- refactor: Rework
Entityclass by @neznaika0 in codeigniter4#9878 - refactor: compare
$db->connIDtofalseby @paulbalandan in codeigniter4#9891 - refactor: cleanup
ContentSecurityPolicyby @paulbalandan in codeigniter4#9904 - refactor: deprecate
CodeIgniter\HTTP\ContentSecurityPolicy::$noncessince never used by @paulbalandan in codeigniter4#9905
For the changelog of v4.6, see CHANGELOG_4.6.md.
For the changelog of v4.5, see CHANGELOG_4.5.md.
For the changelog of v4.4, see CHANGELOG_4.4.md.
For the changelog of v4.3, see CHANGELOG_4.3.md.
For the changelog of v4.2, see CHANGELOG_4.2.md.
For the changelog of v4.1, see CHANGELOG_4.1.md.
For the changelog of v4.0, see CHANGELOG_4.0.md.