PHP2Shell: UK Risks for Legacy Moodle PHP & Migration Plan

PHP versions 7.4 to 8.1 lack official PHP2Shell patches. Understand backport coverage and the secure migration path to Moodle 4.5 LTS.

by Cleverson Gouvêa

PHP2Shell: UK Risks for Legacy Moodle PHP & Migration Plan

A legacy Moodle PHP VLE — one that still runs on PHP 7.4, 8.0, or 8.1 — became your organisation's most exposed server in the week of 21/10/2026. PHP2Shell enabled unauthenticated remote code execution, and PHP only released official patches for versions 8.2 to 8.5. In this guide, I outline what minimal backports resolve, the cost of inaction, and the migration plan I would recommend.

TL;DR

  • PHP2Shell comprises two core PHP vulnerabilities: CVE-2026-109618 (out-of-memory corruption) and CVE-2026-109619 (stale global state between requests). CVSS 4.0 score of 9.2, exploitable without authentication.
  • Official patches were released on 21/10/2026 for versions 8.5.12, 8.4.27, 8.3.36, and 8.2.35. For 7.4, 8.0, and 8.1, only minimal source-code backports exist, with no official binaries. For 5.4 to 7.3, no patches at all.
  • php.ini mitigations reduce the attack surface, but PHP itself warns: no complete mitigations exist.
  • A Moodle 3.9, 3.11, 4.0, or 4.1 VLE will not run on PHP 8.2+. The real solution is to upgrade Moodle to 4.5 LTS (security support until 06/10/2027) on PHP 8.3.36.
  • Inaction risks incidents, UK GDPR compliance issues, and reputational damage. Migration involves weeks of planned work.

What is PHP2Shell and why it affects legacy Moodle PHP

PHP2Shell is not a Moodle bug. It's a bug in the underlying PHP interpreter — which is why updating plugins, themes, or Moodle itself won't close the door.

According to the official php.net advisory dated 21/10/2026, there are two vulnerabilities:

  • CVE-2026-109618 (OOM corruption): When memory runs out during a request, PHP is interrupted with only partially initialised internal data. Request cleanup then treats this garbage as valid.
  • CVE-2026-109619 (stale global state): An internal request state persists after its memory has been freed — a use-after-free that leaks from one request to the next.

Tenable's FAQ summarises the worst point: according to PHP, both can be exploited by an unauthenticated remote attacker. No student account, teacher account, or any other credentials are required.

The timeline that matters

Date Fact
17/10/2026 Amazon Threat Intelligence recorded an attempted exploit on the MadPot honeypot network, four days prior to public disclosure.
20/10/2026 Identifiers leaked; PHP published an early advisory and brought forward the release.
21/10/2026 Versions 8.5.12, 8.4.27, 8.3.36, and 8.2.35 were released, along with backports for 7.4, 8.0, and 8.1.
21/10/2026 Palo Alto's Cortex Xpanse counted over 22.6 million potentially vulnerable exposed instances (Unit 42).
23/10/2026 PHP published an informational alert regarding CVE-2026-115560, an unlikely vector linked to session upload progress, with a patch expected in the next regular release.

The detail that should keep VLE administrators awake at night: Unit 42 reports an attack against a European government body where, in under two hours after initial exploitation, the invader obtained password hashes and MFA secrets, and attempted to escalate privileges to domain administrator. A Moodle VLE holds exactly this — passwords for thousands of students, integration tokens, API keys.

Which PHP your Moodle runs (and why it's stuck)

Almost every legacy Moodle PHP VLE I encounter isn't in this state due to oversight. It's stuck because the Moodle version locks the PHP version. The official MoodleDocs compatibility table makes this clear:

Moodle Version Supported PHP Receives official PHP2Shell patch?
3.9 7.2 to 7.4 No — only minimal backport (7.4) or none (7.2/7.3)
3.11 / 4.0 7.3 to 8.0 No — only minimal backport (7.4/8.0)
4.1 LTS 7.4 to 8.1 No — only minimal backport
4.2 / 4.3 8.0 to 8.2 Yes, if running on 8.2.35
4.4 / 4.5 LTS 8.1 to 8.3 Yes, on 8.2.35 or 8.3.36
5.0 / 5.1 8.2 to 8.4 Yes

Pay close attention to the middle column. A legacy Moodle PHP VLE on version 4.1 will not accept PHP 8.2. Changing only the PHP version breaks the VLE; keeping the PHP version leaves the VLE exposed. This is the legacy dead end.

And there's an aggravating factor: Moodle 4.1 LTS went out of security support on 08/12/2025. Those on it had already accumulated unpatched Moodle vulnerabilities even before PHP2Shell.

How to find out in two minutes

  1. In Moodle, go to Site administration → Notifications: the version appears in the footer.
  2. In Site administration → Server → PHP info, check the PHP Version line.
  3. On the server, run php -v and check the PHP-FPM version serving the site. I've encountered servers with PHP 8.3 on the command line but FPM 7.4 serving Moodle.

Minimal backports: what they cover and what they miss

php.net was direct: "PHP 8.1 and older no longer receive updates from the PHP project". To help those unable to upgrade, the security team published minimal source-code backports for 7.4, 8.0, and 8.1 — branches on the php-src GitHub repository, without packages, binaries, or official releases.

For a legacy Moodle PHP VLE in production, this means:

  • You compile PHP. Someone needs to apply the patch, compile it with the same extensions Moodle requires (intl, sodium, zip, gd, soap, mbstring…), and replace the binary in production.
  • Only these two CVEs are covered. Everything else patched after your version's end-of-life remains unaddressed.
  • No guaranteed next time. CVE-2026-115560, from 23/10, will be addressed "in the next regular release" — and out-of-support versions don't have regular releases.

When backports make sense

They make sense as a bridge for days or weeks, while the Moodle migration is being executed. They also make sense via vendor: Tenable reports that Linux distributions and LTS vendors received the patches earlier, so Debian, Red Hat, and similar distributions may have a patched package for your version. Check your distro's security advisory.

When they DO NOT make sense

It makes no sense as a strategy. If the organisation's plan is to "apply the backport and forget", the legacy Moodle PHP VLE will remain vulnerable for the next alert — and the next alert has already been published.

php.ini mitigations for legacy Moodle PHP: they help, but come at a cost

PHP listed mitigations for those unable to update immediately. All reduce risk; none resolve the issue. In the words of the release itself: "There are no complete mitigations, updating is the only safe choice."

memory_limit=-1 against CVE-2026-109618

The recommendation is memory_limit=-1, applied in a way that the application cannot override it — php_admin_value[memory_limit] = -1 in the FPM pool. Alongside this, a low post_max_size: 8M without uploads, 32M with uploads.

For a legacy Moodle PHP VLE on a single server, this has serious side effects:

  • Without a memory ceiling, a large course backup or a heavy report can consume all available RAM. On an all-in-one server (web + MariaDB on the same machine), the database is usually the first to go, killed by the Linux OOM killer.
  • A post_max_size of 32M breaks .mbz file restorations and the uploading of larger videos via the interface. Large restorations will need to be performed on the server.
  • PHP advises against replacing with RLIMIT_AS or RLIMIT_DATA, because these limits can precisely trigger the vulnerable allocation failure.

The solution is to size FPM's pm.max_children by available RAM and, if possible, isolate PHP in a container or cgroup with limits — Tenable cites this as a boundary for availability, not a patch.

session.upload_progress.enabled=0 against CVE-2026-109619

Disabling session upload progress blocks the confirmed paths for CVE-2026-109619 — and, according to the 23/10 alert, also the vector for CVE-2026-115560. This must be set in php.ini or the FPM pool and requires restarting all workers. ini_set() and .user.ini are ineffective.

Moodle's core uploads files via the file picker using AJAX, without relying on this native PHP progress bar. Even so, validate in a staging environment: third-party plugins might depend on it.

The fatal_error_backtraces=0 setting only exists in PHP 8.5 — irrelevant for those on 7.4 to 8.1. And hiding errors with display_errors or @ offers no help at all.

The cost of inaction with a legacy Moodle PHP VLE

No one publishes an incident cost table for VLEs, and I won't invent one. But those maintaining a legacy Moodle PHP VLE need to consider the full cost. We can list what contributes to it, based on legal grounds.

Direct costs of an incident

  • Downtime: Online exams, enrolments, and certificate issuance cease. During assessment weeks, this leads to refunds, re-sits, and mass support requests.
  • Incident Response: Forensics, clean server reinstallation, replacement of all credentials, review of integrations. This is emergency work, billed as such.
  • UK GDPR: The ICO (Information Commissioner's Office) requires relevant incidents to be reported to them and affected data subjects within 72 hours under the UK GDPR (Data Protection Act 2018). Article 83 of the UK GDPR (Data Protection Act 2018) provides for fines of up to 2% of annual global turnover, or up to £8.7 million, whichever is higher, for less serious infringements, and up to 4% of annual global turnover, or up to £17.5 million, whichever is higher, for serious infringements.

Costs that don't appear immediately

  • Reputation: Students who receive a data breach notification remember it at re-enrolment.
  • B2B Contracts: Corporate universities and training clients often have security clauses. An incident leads to renegotiation.
  • Compounding Technical Debt: Each month of inaction increases the leap. Migrating from 3.9 today requires more steps than it did two years ago.

What migration costs

Migrating a legacy Moodle PHP VLE is not cheap, but it is predictable. The effort increases with four variables: version distance, number of third-party plugins, custom theme, and — the biggest culprit — direct alterations to the core code. A clean VLE with few plugins upgrades quickly. A VLE with a hand-edited core requires an audit before any migration date.

The migration plan I would follow

Moodle does not allow arbitrary skipping of steps. The 4.5 upgrade documentation is clear: you can only reach 4.5 from 4.1.2 or higher. Those with a legacy Moodle PHP VLE on 3.9, 3.11, or 4.0 need to upgrade to 4.1 first.

Step 0 — Containment (first 48 hours)

  • Apply patched distro package or compiled backport, if available.
  • Apply the php.ini mitigations with the above precautions and restart all workers.
  • Place the VLE behind a WAF — Cloudflare has published rules for PHP2Shell, which it itself calls a palliative.
  • Look for signs of exploitation in logs from 17/10/2026, the first recorded attempt date.
  • Change secrets in config.php and integrations if there is any indication of compromise.

Step 1 — Inventory (week 1)

List exact version, plugins (with version and 4.5 compatibility), theme, core customisations, integrations, and moodledata size. This is where you discover if the legacy Moodle PHP VLE can be migrated in two weeks or two months.

Step 2 — Staging Environment Testing (weeks 1 to 3)

  1. Clone database and moodledata to an isolated environment.
  2. 3.9 / 3.11 / 4.0 → 4.1.x still on PHP 7.4 to 8.1.
  3. 4.1.x → 4.5 LTS, upgrading PHP to 8.1 midway and then to 8.3.36.
  4. Run environment checks, test exams, grades, certificates, payments, and SSO.

If the VLE uses Google or Microsoft login, review integrations at this point — the OAuth2 in Moodle 5.3 guide shows what changes when you move to the next LTS.

Step 3 — Go-Live (a maintenance window)

Maintenance mode, verified backup, production upgrade following the rehearsed script, smoke test, and reopening. With thorough staging, the go-live can fit into an overnight window.

Why 4.5 and not 5.x

Moodle 4.5 LTS has security support until 06/10/2027 and accepts PHP 8.3. Moodle 5.0 went out of security support on 05/10/2026, and 5.1 is going the same way — I explain the timeline in the post about Moodle 5.1 end of support. For those migrating a legacy Moodle PHP VLE, 4.5 is the stable step; 5.3 LTS comes later, without rush.

Common migration pitfalls

  • Updating only PHP. A legacy Moodle PHP VLE on 4.1 will not run on PHP 8.2. The error appears in the environment check — or, worse, as a white screen.
  • Forgetting FPM. apt upgrade updates the CLI, but the old FPM continues to serve the site.
  • Abandoned plugin. Plugins without a version for 4.5 need to be replaced, rewritten, or removed before go-live, not after.
  • No rollback. Moodle upgrades alter the database; there's no 'undo'. Tested backup of both database and moodledata before starting.
  • Stalled Cron. After the upgrade, accumulated scheduled tasks can overload the server in the first minute.
  • Incorrect server. Many organisations discover during migration that their VPS cannot handle the new Moodle. I compare the two scenarios in VPS for Moodle or Managed Hosting.

How Agathas Web resolves this

I have worked with Moodle for over 15 years, hold Moodle Developer Certification, and operate Linux servers for VLE environments daily. For a legacy Moodle PHP VLE, our Moodle migration and support service works as follows:

  1. Free Diagnosis: We assess your Moodle, PHP, FPM versions, plugins, theme, customisations, and integrations. You receive a clear picture of the actual problem.
  2. Immediate Containment, if required: Patched package or backport, php.ini mitigations adjusted for Moodle (without breaking backup and restore), and log review from 17/10.
  3. Technical Proposal: A document outlining version paths, plugins to replace, infrastructure, timeline, and investment.
  4. Staging Migration and Go-Live: Each step tested in a copy, with a script, verified backup, and agreed maintenance window.
  5. Ongoing Support: Monthly SLA with security updates, monitoring, and verified backups — ensuring the next alert doesn't become an emergency.

You retain ownership of your data, theme, and plugins. We are an independent service company, and our expert team understands Moodle's code deeply. To get started, request a diagnosis on the Agathas Web Moodle services page or contact us via WhatsApp.

Conclusion: PHP2Shell merely brought forward the reckoning

Legacy Moodle PHP VLEs were already a risk before 21/10/2026: out-of-support Moodle versions, unpatched PHP, and outdated plugins. PHP2Shell transformed this risk into an unauthenticated exploitation window, with 22.6 million instances exposed according to Unit 42.

The secure path has three steps: immediate containment, migration to Moodle 4.5 LTS on PHP 8.3.36 in the coming weeks, and ongoing environment support. If you want to know where your VLE stands and what it will take to secure it, request a diagnosis at /servicos/moodle.