Legacy Moodle PHP After PHP2Shell: Risks, Costs, and Your Migration Plan

PHP 7.4 to 8.1 lacks an official PHP2Shell patch. Learn what backports cover and the safe migration path to Moodle 4.5 LTS.

by Cleverson Gouvêa

Legacy Moodle PHP After PHP2Shell: Risks, Costs, and Your Migration Plan

A legacy Moodle PHP — an LMS still running on PHP 7.4, 8.0, or 8.1 — became your institution's most exposed server in the week of October 21, 2026. PHP2Shell enabled unauthenticated remote code execution, and PHP only released official patches for versions 8.2 through 8.5. In this guide, I'll show you what minimal backports address, the cost of inaction, and the migration plan I would follow.

TL;DR

  • PHP2Shell consists of two core PHP vulnerabilities: CVE-2026-109618 (out-of-memory corruption) and CVE-2026-109619 (stale global state between requests). Rated 9.2 on CVSS 4.0, exploitable without authentication.
  • Official patches were released on 10/21/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. From 5.4 to 7.3, no patches are available.
  • php.ini mitigations reduce the attack surface, but PHP itself warns: no complete mitigations exist.
  • Moodle 3.9, 3.11, 4.0, or 4.1 does not run on PHP 8.2+. The real solution is to upgrade Moodle to 4.5 LTS (security support until 10/06/2027) on PHP 8.3.36.
  • Inaction costs incidents, privacy law penalties (e.g., CCPA), and reputation damage. Migration costs 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 vulnerability.

According to the official php.net advisory from October 21, 2026, there are two vulnerabilities:

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

The Tenable FAQ summarizes the worst aspect: according to PHP, both can be exploited by a remote attacker without authentication. No student, teacher, or any other account is needed.

The Timeline That Matters

Date Event
10/17/2026 Amazon Threat Intelligence records attempted exploitation on the MadPot honeypot network, four days before disclosure
10/20/2026 Identifiers leak; PHP publishes pre-advisory and accelerates release
10/21/2026 8.5.12, 8.4.27, 8.3.36, and 8.2.35 are released, along with backports for 7.4, 8.0, and 8.1
10/21/2026 Palo Alto's Cortex Xpanse counts over 22.6 million potentially vulnerable exposed instances (Unit 42)
10/23/2026 PHP publishes an informational alert about CVE-2026-115560, an unlikely vector related to session upload progress, with a fix planned for the next regular release

The detail that should keep LMS administrators awake: Unit 42 reports an attack against a European government agency where, in less than two hours after initial exploitation, the attacker obtained password hashes and MFA secrets, and attempted to escalate to domain administrator. A Moodle instance stores 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 instance I encounter isn't stuck 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 nothing (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 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

Read the middle column carefully. A legacy Moodle PHP on version 4.1 does not support PHP 8.2. Changing only PHP breaks the LMS; keeping PHP leaves the LMS vulnerable. This is the legacy trap.

And there's an aggravating factor: Moodle 4.1 LTS reached end-of-security-life on 12/08/2025. Anyone on it was already accumulating 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. Under 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 and 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 assist 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, without packages, binaries, or releases.

For a production legacy Moodle PHP, this means:

  • You compile PHP. Someone needs to apply the patch, compile with the same extensions Moodle requires (intl, sodium, zip, gd, soap, mbstring…), and replace the production binary.
  • Only covers these two CVEs. Everything else patched after your version's end-of-life remains unaddressed.
  • No guaranteed next time. CVE-2026-115560, from 10/23, 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 Moodle migration is underway. They also make sense via vendors: Tenable notes that Linux distributions and LTS vendors received the patches earlier, so Debian, Red Hat, and similar might have a patched package for your version. Check your distro's security advisory.

When They DON'T Make Sense

They don't make sense as a strategy. If your institution's plan is to "apply the backport and forget it," your legacy Moodle PHP 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 fully resolve it. 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 so the application cannot override it — php_admin_value[memory_limit] = -1 in the FPM pool. Additionally, a low post_max_size: 8M without uploads, 32M with uploads.

On a single-server legacy Moodle PHP, this has serious side effects:

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

The solution is to size pm.max_children for FPM 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 fix.

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 10/23 alert, also the vector for CVE-2026-115560. This must be done in php.ini or the FPM pool and requires restarting all workers. ini_set() and .user.ini are not sufficient.

Moodle's core uploads files via the file picker using AJAX, without relying on this native PHP progress bar. Nevertheless, validate in a staging environment: a third-party plugin 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 @ does not help at all.

The Cost of Inaction with a Legacy Moodle PHP

No one publishes an incident cost table for an LMS, and I won't invent one. But anyone maintaining a legacy Moodle PHP needs to look at the full cost. We can list, with a legal basis, what goes into it.

Direct Costs of an Incident

  • Downtime: Online exams, enrollments, and certificate issuance halt. During assessment week, this turns into refunds, re-examinations, and mass support requests.
  • Incident Response: Forensics, clean server reinstallation, credential resets, integration review. This is emergency work, billed as such.
  • Privacy Law Penalties: US state privacy laws (e.g., CCPA) and federal regulations often require notifying affected individuals and regulators of significant incidents within a few business days. For instance, the California Consumer Privacy Act (CCPA) can levy fines up to $7,500 per violation. Other state and federal regulations also impose significant penalties for data breaches.

Hidden Costs

  • Reputation: A student who receives a data breach notification remembers it at re-enrollment.
  • 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 gap. Moving from 3.9 today requires more steps than it did two years ago.

What Migration Costs

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

The Migration Plan I Would Follow

Moodle doesn't allow skipping versions at will. The Moodle 4.5 upgrade documentation is clear: you can only reach 4.5 from 4.1.2 or higher. Anyone with a legacy Moodle PHP on 3.9, 3.11, or 4.0 needs to go through 4.1 first.

Phase 0 — Containment (First 48 Hours)

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

Phase 1 — Inventory (Week 1)

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

Phase 2 — Staging Environment Validation (Weeks 1-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 your LMS uses Google or Microsoft login, review the integrations at this point — the OAuth2 in Moodle 5.3 guide shows what changes when you move to the next LTS.

Phase 3 — Go-Live (A Maintenance Window)

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

Why 4.5 and Not 5.x

4.5 LTS has security support until 10/06/2027 and accepts PHP 8.3. 5.0 already reached end-of-security-life on 10/05/2026, and 5.1 is headed the same way — I explain the calendar in the post about Moodle 5.1 end-of-life. For those taking a legacy Moodle PHP offline, 4.5 is the stable step; 5.3 LTS comes later, without rush.

Common Migration Pitfalls

  • Updating only PHP. A legacy Moodle PHP on 4.1 won't run on PHP 8.2. The error appears during environment checks — or, worse, as a blank screen.
  • Forgetting FPM. apt upgrade updates the CLI, but the old FPM continues serving the site.
  • Abandoned Plugin. A plugin without a 4.5 version needs to be replaced, rewritten, or removed before go-live, not after.
  • No Rollback. Moodle upgrades alter the database; there's no "undo." A tested backup of both the database and moodledata is essential before starting.
  • Stalled Cron. After the upgrade, accumulated scheduled tasks can overload the server in the first minute.
  • Wrong Server. Many institutions 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 Solves This

I've worked with Moodle for over 15 years, hold Moodle Developer Certification, and manage Linux servers for LMS environments daily. For a legacy Moodle PHP, our Moodle migration and support service works like this:

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

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

Conclusion: PHP2Shell Only Accelerated the Inevitable

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

The secure path has three steps: contain now, migrate to Moodle 4.5 LTS on PHP 8.3.36 in the coming weeks, and maintain the environment with ongoing support. If you want to know where your LMS stands and how far you are from a secure state, request a diagnosis at /servicos/moodle.