From f2cf801cd252555e97316c2d9e67332eaeddc065 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Mon, 2 Nov 2026 01:08:35 +0800 Subject: [PATCH] Prep for 4.7.6 release --- CHANGELOG.md | 75 +++++++++++++++++++ admin/generate-changelog.php | 8 +- admin/update-upgrade-guide.php | 21 +++++- phpdoc.dist.xml | 2 +- system/CodeIgniter.php | 2 +- user_guide_src/source/changelogs/v4.7.6.rst | 2 +- user_guide_src/source/conf.py | 2 +- .../source/installation/upgrade_476.rst | 16 ++-- 8 files changed, 109 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddac0375df83..366b82d095f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,80 @@ # Changelog +## [v4.7.6](https://github.com/codeigniter4/CodeIgniter4/tree/v4.7.6) (2026-11-01) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.7.5...v4.7.6) + +### Security + +* **Cache:** ``FileHandler::deleteMatching()`` now matches the pattern against cache + file names only. Previously, a pattern such as ``../*`` could delete files outside + the cache directory. Patterns can no longer match files in subdirectories of the + cache directory, so those files are no longer deleted. Special characters in the + cache path, such as ``[``, are no longer interpreted as part of the pattern. + See the `Security advisory GHSA-9hf2-g3w9-pfmp `_ + for more information. See :ref:`upgrade-476-cache-delete-matching` for migration + instructions. +* **Model:** Fixed a mass assignment vulnerability in ``replace()``. + The method now discards fields not listed in ``$allowedFields`` when field + protection is enabled, while retaining a supplied primary key. Input emptied + by filtering, or reduced to only its primary key, now throws a ``DataException``. + Previously, applications passing untrusted input to ``replace()`` could write + protected columns. See :doc:`Upgrading from 4.7.5 to 4.7.6 ` + for migration instructions. + See the `Security advisory GHSA-jv74-fx4h-m63x `_ + for more information. +* **Security Helper:** Fixed a path traversal vulnerability in ``sanitize_filename()``. + Backslashes were only removed by a final ``stripslashes()`` call after filtering. + When ``$relativePath`` was ``true``, input such as ``.\./`` became ``../`` on all + platforms. In both modes, repeated backslashes could survive as Windows path + separators, and ``\0`` could become a NUL byte. + Backslashes are now removed during filtering, and ``stripslashes()`` is no longer + called. Forward slashes are still preserved when ``$relativePath`` is ``true``. + The same applies to ``Security::sanitizeFilename()``. + See :doc:`Upgrading from 4.7.5 to 4.7.6 ` and the + `Security advisory GHSA-9j59-qcxw-q7qm `_ + for more information. +* **Database:** Fixed a SQL injection vulnerability in named query bindings. + When a query combined named binds (``:name:``) with a value that was already + escaped and rendered into the SQL (for example a subquery passed to ``where()``, + ``union()``, ``fromSubquery()`` or ``selectSubquery()``, a custom ``where()`` + string built with ``$db->escape()``, the ``WHERE`` binds of ``deleteBatch()``, + or a manually escaped fragment in ``$db->query()``), a placeholder inside that + value was replaced with the bind of the same name, which could break out of the + string literal. Placeholders are now ignored inside quoted strings, quoted + identifiers and SQL comments, and the ``WHERE`` binds of ``deleteBatch()`` are + substituted only after the batch data has been rendered into the query. + Plain ``where()``, ``like()``, ``insert()`` and ``update()`` calls were not affected. + See the `Security advisory GHSA-25rf-99hr-7pmr `_ + and :ref:`upgrade-476-named-binds` for more information. + +### Fixed Bugs + +* fix: preserve JSON request body when CSRF token is not in it by @gr8man in https://github.com/codeigniter4/CodeIgniter4/pull/10620 +* fix: sort generator imports in templates with CRLF line endings by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/10622 +* fix: handle invalid values and empty tag names in XMLFormatter by @gr8man in https://github.com/codeigniter4/CodeIgniter4/pull/10626 +* fix: detect X-Forwarded-Proto case-insensitively in isSecure() by @gr8man in https://github.com/codeigniter4/CodeIgniter4/pull/10627 +* fix: refresh REQUEST after URI GET normalization by @rahul05ranjan in https://github.com/codeigniter4/CodeIgniter4/pull/10606 +* fix: widen accepted values in `set_value()`'s `$default` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/10641 +* fix: fix array handling in ContentSecurityPolicy::setDefaultSrc() and add addDefaultSrc() by @gr8man in https://github.com/codeigniter4/CodeIgniter4/pull/10635 +* fix: reject missing keys in `CLI::promptByMultipleKeys()` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/10654 +* fix: normalize string values and keys in `ContentSecurityPolicy::addOption()` by @gr8man in https://github.com/codeigniter4/CodeIgniter4/pull/10636 +* fix(HTTP): read request body when `post_max_size` is unlimited by @gr8man in https://github.com/codeigniter4/CodeIgniter4/pull/10646 +* fix: apply `ContentSecurityPolicy::reportOnly()` to config sources after construction by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/10663 +* fix: stop prompts from asking forever when the input ends by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/10658 +* fix: ignore media ranges without a subtype in `Negotiate::media()` by @wleeaf in https://github.com/codeigniter4/CodeIgniter4/pull/10660 +* fix: clear transaction state when reconnect() replaces the socket by @KevinBlakeLopez in https://github.com/codeigniter4/CodeIgniter4/pull/10650 +* fix: do not let wildcards select values excluded with q=0 in `Negotiate` by @wleeaf in https://github.com/codeigniter4/CodeIgniter4/pull/10661 +* fix: keep writes transactional after MySQL deadlock 1213 by @KevinBlakeLopez in https://github.com/codeigniter4/CodeIgniter4/pull/10651 +* fix(Cache): isolate the factories cache files used by the tests by @gr8man in https://github.com/codeigniter4/CodeIgniter4/pull/10647 +* fix: restore the timezone, locale and string format when unserializing `Time` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/10682 +* fix: preserve subclass types in route group callbacks by @maniaba in https://github.com/codeigniter4/CodeIgniter4/pull/10644 +* fix(HTTP): remove invalid `CURLOPT_HTTPHEADER` string assignment in `CURLRequest` by @gr8man in https://github.com/codeigniter4/CodeIgniter4/pull/10695 + +### Refactoring + +* refactor: remove `@see` test annotations in source by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/10624 +* refactor: fix `null` checks that are always `false` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/10670 + ## [v4.7.5](https://github.com/codeigniter4/CodeIgniter4/tree/v4.7.5) (2026-10-09) [Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.7.4...v4.7.5) diff --git a/admin/generate-changelog.php b/admin/generate-changelog.php index f6578cb1372f..521d2744669e 100644 --- a/admin/generate-changelog.php +++ b/admin/generate-changelog.php @@ -140,7 +140,13 @@ exit(0); } -$updated = preg_replace('/\A# Changelog\n\n/', "# Changelog\n\n{$entry}\n", $changelog, 1, $count); +$updated = preg_replace_callback( + '/\A# Changelog\n\n/', + static fn (): string => "# Changelog\n\n{$entry}\n", + $changelog, + 1, + $count, +); if ($count !== 1) { echo 'Could not find the "# Changelog" header in CHANGELOG.md.' . "\n"; diff --git a/admin/update-upgrade-guide.php b/admin/update-upgrade-guide.php index c80f0a75b635..19d42bed64d9 100644 --- a/admin/update-upgrade-guide.php +++ b/admin/update-upgrade-guide.php @@ -79,10 +79,23 @@ function bullets(array $items): string // Paths that are not part of the project space. Keep in sync with the // distribution repos: `tests/` is not used there, see "admin/starter/tests". $excludes = [ - ':!.github/', ':!admin/', ':!changelogs/', ':!contributing/', - ':!system/', ':!tests/', ':!user_guide_src/', ':!utils/', - ':!*.json', ':!*.xml', ':!*.dist', ':!rector.php', ':!structarmed.php', - ':!phpstan*', ':!psalm*', ':!.php-cs-fixer.*', ':!LICENSE', ':!CHANGELOG.md', + ':!.github/', + ':!admin/', + ':!changelogs/', + ':!contributing/', + ':!system/', + ':!tests/', + ':!user_guide_src/', + ':!utils/', + ':!.*', + ':!*.md', + ':!*.json', + ':!*.xml', + ':!phpstan*', + ':!psalm*', + ':!rector.php', + ':!structarmed*', + ':!LICENSE', ]; $command = sprintf( diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml index 0f25b06d5f66..1cb9e6c2c4b3 100644 --- a/phpdoc.dist.xml +++ b/phpdoc.dist.xml @@ -10,7 +10,7 @@ api/build/ api/cache/ - + system diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 18847fcb67a8..03b4fca3b05c 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -53,7 +53,7 @@ class CodeIgniter /** * The current version of CodeIgniter Framework */ - public const CI_VERSION = '4.7.6-dev'; + public const CI_VERSION = '4.7.6'; /** * App startup time. diff --git a/user_guide_src/source/changelogs/v4.7.6.rst b/user_guide_src/source/changelogs/v4.7.6.rst index 4ee64bd8369c..ba7c18f6043f 100644 --- a/user_guide_src/source/changelogs/v4.7.6.rst +++ b/user_guide_src/source/changelogs/v4.7.6.rst @@ -2,7 +2,7 @@ Version 4.7.6 ############# -Release Date: Unreleased +Release Date: November 1, 2026 **4.7.6 release of CodeIgniter4** diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py index 0dd8d46130e9..690f5ee8fe5e 100644 --- a/user_guide_src/source/conf.py +++ b/user_guide_src/source/conf.py @@ -26,7 +26,7 @@ version = '4.7' # The full version, including alpha/beta/rc tags. -release = '4.7.5' +release = '4.7.6' # -- General configuration --------------------------------------------------- diff --git a/user_guide_src/source/installation/upgrade_476.rst b/user_guide_src/source/installation/upgrade_476.rst index d4e60c053e49..99677d4d827b 100644 --- a/user_guide_src/source/installation/upgrade_476.rst +++ b/user_guide_src/source/installation/upgrade_476.rst @@ -12,18 +12,14 @@ Please refer to the upgrade instructions corresponding to your installation meth :local: :depth: 2 -********************** -Mandatory File Changes -********************** - **************** Breaking Changes **************** .. _upgrade-476-cache-delete-matching: -File Cache deleteMatching() No Longer Matches Subdirectories -============================================================ +File Cache ``deleteMatching()`` No Longer Matches Subdirectories +================================================================ For security reasons, ``FileHandler::deleteMatching()`` now matches the pattern against the names of files in the cache directory only. See the @@ -44,8 +40,8 @@ the :php:func:`delete_files()` helper function. .. _upgrade-476-model-replace: -Model Field Protection for replace() -==================================== +Model Field Protection for ``replace()`` +======================================== For security reasons, ``Model::replace()`` now applies field protection: @@ -144,7 +140,7 @@ and it is recommended that you merge the updated versions with your application: Config ------ -- @TODO +- No config files were changed in this release. All Changes =========== @@ -152,4 +148,4 @@ All Changes This is a list of all files in the **project space** that received changes; many will be simple comments or formatting that have no effect on the runtime: -- @TODO +- No project files were changed in this release.