Repository navigation
fix: disable session.upload_progress for new and existing sites - #246
Merged
mrrobot47 merged 4 commits intoOct 21, 2026
Merged
Conversation
The session upload progress handler is not needed by WordPress or most apps; turning it off removes it as an attack surface (php2shell hardening). Apps that need it can set it back to On in custom.ini.
Adds session.upload_progress.enabled = Off to the custom.ini of every wp site, enabled or disabled, unless it already sets it. Files are edited in place (owner, mode and inode kept), originals are backed up under EE_BACKUP_DIR and restored if the upgrade rolls back. Running sites get a graceful php-fpm reload after the image migration, skipped for php containers it recreated; disabled sites pick it up when enabled. Per-site problems are warnings so they don't block the upgrade.
There was a problem hiding this comment.
🟡 Changes recommended
Scoped settings and silent container-discovery failures can leave the intended security mitigation unapplied.
2 open issues
What changed in this PR
Adds PHP session upload-progress hardening to WordPress site provisioning and existing-site upgrades.
Changes:
- Disables upload progress in both PHP configuration templates.
- Adds a migration with backups, rollback, and conditional PHP-FPM reloads.
| File | Description |
|---|---|
| templates/config/php-fpm/php.ini.mustache | Disables upload progress for new sites. |
| templates/config/php-fpm/php.ini-56.mustache | Applies the same default for PHP 5.6. |
| migrations/container/20261021120000_site-type-wp_disable_wp_session_upload_progress.php | Updates existing WordPress sites and manages restoration and reloads. |
Review effort: Balanced
…ns set it custom.ini is now read with PHP's own ini parser (same mode as php.ini) to find a global session.upload_progress.enabled, so a value set only inside a [PATH=] or [HOST=] section no longer counts. The new lines go at the very top of the file, where neither such a section nor a multi-line quoted value can capture them; for a file with a syntax error only the lines above it count, matching what PHP applies. A failed docker-compose ps is now a warning with the reload command instead of being treated as a stopped container.
PHP treats any section whose name starts with PATH or HOST (case-insensitive, spaces allowed before the =) as scoped, and entries under a later ordinary header stay in that scope. Only the part before the first such header now counts as global, so a scoped-only setting no longer stops the global Off from being added.
mrrobot47
added a commit
to EasyEngine/easyengine
that referenced
this pull request
Oct 21, 2026
Switches off session.upload_progress for new sites and, through a container migration, for every existing WordPress and PHP site on all PHP versions (EasyEngine/site-type-wp#246, EasyEngine/site-type-php#120).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


PHP's 2026-10-21 security advisory for CVE-2026-109618 (GHSA-w8hw-w9fx-j79w) and CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp), announced at https://www.php.net/archive/2026.php#2026-10-21-1, names session upload progress as an attack path: "Session lifecycle RCE was validated against mod_php and FPM". The official mitigation is: "Set session.upload_progress.enabled=0 and restart every worker. Use php.ini, an FPM pool or server configuration that applies before request parsing. Do not rely on ini_set() or FPM .user.ini." PHP also recommends keeping it off after patching if it isn't used.
This PR applies that mitigation to every WordPress site. It is defence in depth, not a substitute for the patched PHP images (8.2.35, 8.3.36, 8.4.27 and 8.5.12). WordPress doesn't use PHP sessions, so nothing changes for WordPress itself. PHP 8.1 and older get no official release with the fix, so for sites still on those versions this setting is the main protection until they move to a supported version.
The setting goes into each site's
custom.ini, which php-fpm loads from its scannedconf.dat startup, before any request is parsed. Running sites then get a graceful php-fpm reload (kill -USR2 1, asee site reloaddoes), which re-executes the master and replaces every worker.New sites:
php.ini.mustacheandphp.ini-56.mustacheset it toOff. PHP-type sites also take theircustom.inifrom this package's template (SITE_WP_TEMPLATE_ROOTin site-type-php'sPHP.php), so this covers new PHP sites too.Existing sites: container migration
20261021120000_site-type-wp_disable_wp_session_upload_progress.phpadds the setting toconfig/php/php/conf.d/custom.iniof every WordPress site, enabled or disabled, on every PHP version:session.upload_progress.enabledglobally (On or Off) is left alone. The check uses PHP's own ini parser in the same mode as php.ini, and only entries before the first section whose name starts withPATHorHOSTcount, since PHP scopes everything after such a header to it (even under later ordinary headers). So a commented-out line, a wrong-case key or a value set only in a scoped section doesn't count, and a scoped override is kept as it is; for a file with a syntax error, only the lines above it count, as in PHP.[PATH=]/[HOST=]section nor a multi-line quoted value can capture it. A missingcustom.iniis recreated with the owner of itsconf.d. A symlinkedcustom.inior a directory in its place is skipped with a warning./opt/easyengine/.backup/session-upload-progress-wp-<timestamp>/<site>/custom.ini. If a later step of the upgrade fails (another container migration or the image migration),down()restores them byte for byte and reloads php-fpm of the running sites.ee site reload(kill -USR2 1) once the image migration is done. Sites whose php container the image migration recreated already read the new file, so they're not reloaded again. Disabled sites pick it up when they're enabled.docker-compose pswhen looking up its php container) is a warning that names the site and the manual fix, so it doesn't block the upgrade.To undo it on a site, remove the line from
custom.ini(or set it toOn), then runee site reload <site>.On macOS,
custom.iniis currently bind-mounted outside theconf.ddirectory PHP scans (a separate, older issue), so the setting has no effect there yet; that needs its own fix.Testing: a scripted matrix over the ini editing and the migration against site directories (empty, whitespace-only, the templates, other settings, no final newline, already Off, explicit On, commented out, wrong case, CRLF, BOM,
[HOST=]/[PATH=]sections with and without a scoped setting, a multi-line quoted value containing a[line, a syntax error, missing file, missingconf.d, symlink, directory, 0444 file owned by www-data, immutable file, disabled site, stopped container, failed container lookup, failure halfway through, unwritable backup dir, second run,down()), with each result also parsed by real PHP, on PHP 7.4 and 8.5. A single-file bind mount into a running php8.4 container picks up the edit and the reload. A live upgrade from 4.13.2 with WordPress sites on PHP 8.4 and 7.4 and PHP sites on 8.1, 5.6 and 8.4 (one disabled, one with an explicitOn, one with extra user settings): FPM reports the setting off on every changed site, the explicitOnstays, sites keep serving 200, multipart and WordPress REST media uploads work, the disabled site gets it onee site enable, a second run changes nothing, and a failed image migration restores everycustom.iniexactly.Needs a core release that pins this tag together with site-type-php's matching change.