Skip to content

fix: PHP2Shell workaround, upgrade PHP in DDEV web images on workspace start - #222

Merged
rfay merged 1 commit into
mainfrom
20261021_rfay_php2shell
Oct 21, 2026
Merged

rfay merged 1 commit into
mainfrom
20261021_rfay_php2shell

Conversation

@rfay

@rfay rfay commented Oct 21, 2026

Copy link
Copy Markdown
Member

The Issue

PHP2Shell (CVE-2026-109618 / CVE-2026-109619) lets a single unauthenticated request run code on any PHP that serves web requests. Fixed PHP is 8.5.12, 8.4.27, 8.3.36 and 8.2.35, released 2026-10-21.

DDEV's guidance (blog post) says local-only projects are not exposed. Coder workspaces can serve sites publicly, though: drupal_site_public in drupal-core/drupal-contrib, and public project sharing in freeform. That is the exposed "casual hosting" case.

The coder-ddev image itself has no PHP (/usr/local/bin/php wraps ddev php). The vulnerable PHP is in the ddev-webserver image pulled inside each workspace. No DDEV release includes the fix yet; v1.25.5 is expected 2026-10-22.

How This PR Solves The Issue

This applies the blog's interim workaround for amd64, which is what the coder hosts run. On every workspace start, each template writes .ddev/web-build/Dockerfile.php2shell:

RUN (apt-get update || true) && apt-get install -y --only-upgrade 'php*'
  • drupal-core / drupal-contrib: the file is written next to config.coder.yaml, so the ddev start in startup rebuilds the web image with fixed PHP.
  • freeform: the file is written into every project listed by ddev list -j. It takes effect on each project's next ddev start or ddev restart.
  • Dockerfile.php2shell is appended to ~/.gitignore_global on every start, and added to the image's copy, so it doesn't show as untracked in core and contrib clones.

Rollout

  1. Merge this PR and run make push-all-templates. Existing workspaces then show "update available". They pick up the fix only after the owner updates the workspace, because a stop/start alone re-runs the old template version.
  2. Tell owners of publicly shared workspaces to update.
  3. When DDEV v1.25.5 ships: bump VERSION to v0.6, so pull_triggers actually repulls the image, rebuild the image, and remove these steps. Comments in the code mark what to delete.

Manual Testing Instructions

  1. Push the templates to staging and create or update a drupal-core workspace.
  2. In the project, run ddev php -v. It should show 8.3.36 or 8.4.27 (depending on the project's PHP version).
  3. Run git status in the core checkout. .ddev/web-build/Dockerfile.php2shell should not be listed.
  4. In a freeform workspace with an existing project, restart the workspace, then run ddev restart and ddev php -v in the project.

Automated Testing Overview

make validate and make test-templates pass (13, 13 and 18 tests). This change is shell inside startup_script, so the terraform tests don't exercise it. I dry-ran the freeform ddev list -j | jq loop locally against sample output: it skips projects without a .ddev directory and does nothing when the list is empty.

Release/Deployment Notes

Temporary. A project's first start after updating takes a bit longer because of the apt-get update and PHP upgrade in the web build; later starts use Docker's cache.

🤖 Generated with Claude Code

…e start

PHP2Shell (CVE-2026-109618/CVE-2026-109619) allows unauthenticated RCE
against any PHP serving web requests. Workspaces can share their sites
publicly (drupal_site_public, freeform public sharing), so they are exposed.
The coder-ddev image itself has no PHP; the vulnerable PHP is in the
ddev-webserver image pulled inside each workspace, and no fixed DDEV
release exists until v1.25.5.

Following https://ddev.com/blog/php2shell-what-ddev-users-need-to-know/,
each template now writes .ddev/web-build/Dockerfile.php2shell on every
start, which runs `apt-get install --only-upgrade 'php*'` when the web
image is built:

- drupal-core / drupal-contrib: written next to config.coder.yaml, so the
  startup `ddev start` rebuilds with fixed PHP.
- freeform: written into every project in `ddev list`; takes effect on
  each project's next `ddev start`/`ddev restart`.

Dockerfile.php2shell is added to ~/.gitignore_global (and the image's
copy) so it does not appear as untracked in core/contrib clones.

Remove these steps after upgrading the image to DDEV v1.25.5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-21 20:51 UTC

@rfay
rfay merged commit cd5e899 into main Oct 21, 2026
18 checks passed
@rfay
rfay deleted the 20261021_rfay_php2shell branch October 21, 2026 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant