Skip to content

Rebuild base-php from the PHP 7.4 backport for CVE-2026-109618/109619 - #1856

Merged
hahn-kev merged 1 commit into
developfrom
php-cve-2026-109618-109619
Oct 22, 2026
Merged

hahn-kev merged 1 commit into
developfrom
php-cve-2026-109618-109619

Conversation

@hahn-kev

Copy link
Copy Markdown
Collaborator

Both CVEs are unauthenticated RCE in PHP, highest risk on Apache mod_php, which is what Language Forge runs. PHP 7.4 is EOL so there is no fixed release and the official php:7.4-apache image will not be rebuilt. The PHP security team published a minimal source backport branch (PHP-7.4-CVE-2026-109618-109619); this recompiles PHP from that branch, pinned to commit 712e60f9, in place on top of the official image using the same configure flags, so the apache module, ini layout and extension tooling are unchanged.

Also needed to make the image buildable at all today:

  • Debian 11 moved to archive.debian.org, so apt sources are rewritten.
  • The mongodb extension is pinned to 1.19.0 (the version in the published image); unpinned it resolves to 1.20, whose ReadPreference deprecation floods the test log and OOMs PHPUnit's JUnit writer.

Defence in depth: session.upload_progress.enabled=Off, a confirmed CVE-2026-109619 path that Language Forge does not use.

docs/RELEASE.md explains that the base PHP image must be published via the manual workflow before merging changes to docker/base-php.

Fixes #issue

Description

A summary of the change including motivation and context.

Screenshots

Demonstrate any UI / behavioral changes with screenshots or animations.

Checklist

  • I have labeled my PR with: bug, feature, engineering, security fix or testing
  • I have performed a self-review of my own code
  • I have reviewed the title & description of this PR which I will use as the squashed PR commit message
  • I have commented my code, particularly in hard-to-understand areas
  • I have added tests that prove my fix is effective or that my feature works
  • I have enabled auto-merge (optional)

Testing

Testers, use the following instructions against our staging environment. Post your findings as a comment and include any meaningful screenshots, etc.

Describe how to verify your changes and provide any necessary test data.

  • Test A

Both CVEs are unauthenticated RCE in PHP, highest risk on Apache mod_php,
which is what Language Forge runs. PHP 7.4 is EOL so there is no fixed
release and the official php:7.4-apache image will not be rebuilt. The PHP
security team published a minimal source backport branch
(PHP-7.4-CVE-2026-109618-109619); this recompiles PHP from that branch,
pinned to commit 712e60f9, in place on top of the official image using the
same configure flags, so the apache module, ini layout and extension
tooling are unchanged.

Also needed to make the image buildable at all today:
- Debian 11 moved to archive.debian.org, so apt sources are rewritten.
- The mongodb extension is pinned to 1.19.0 (the version in the published
  image); unpinned it resolves to 1.20, whose ReadPreference deprecation
  floods the test log and OOMs PHPUnit's JUnit writer.

Defence in depth: session.upload_progress.enabled=Off, a confirmed
CVE-2026-109619 path that Language Forge does not use.

docs/RELEASE.md explains that the base PHP image must be published via
the manual workflow before merging changes to docker/base-php.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Unit Test Results

362 tests   362 ✅  9s ⏱️
 37 suites    0 💤
  1 files      0 ❌

Results for commit ae18dd7.

@rmunn rmunn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this should work. Let's merge it and let the proof of the pudding be in the eating.

\
# remove build dependencies again, same approach as the official image
apt-mark auto '.*' > /dev/null; \
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible for this to fail if the $savedAptMark variable is extremely long. In theory, to be safe, it should be piped through xargs, which would split the command into two (or more) commands if the argument length is too long. But it would take thousands of manually-installed packages to exceed the default 2 MB limit for command line length, so that's not a serious concern here.

This can stand as-is.

Comment on lines +89 to +97
find /usr/local -type f -executable -exec ldd '{}' ';' \
| awk '/=>/ { print $(NF-1) }' \
| sort -u \
| xargs -r dpkg-query --search \
| cut -d: -f1 \
| sort -u \
| xargs -r apt-mark manual \
; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is attempting to trim the volume down to the minimally-required set of packages. Normally I would say this is worth doing, but it's possible that this might end up removing some Debian packages that we assume are there. I would actually remove this find command and the apt-get purge (and then the savedAptMark and apt-mark auto business can go away too), and just remove the packages that were explicitly installed by the script, such as git and the various *-dev packages. If the purpose is to reduce the available attack surface, then only removing git might actually make more sense.

However, that can also wait for later. For now, this should work, so let's let this also stand as-is. If it turns out that this ends up removing something that LfMerge relied on, we can switch to just uninstalling git and nothing else.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that LfMerge runs in its own container, so removing things from the app container shouldn't affect it. So I should have said "something that Language Forge code relied on". Which we'll find out when we try to test this.

@rmunn rmunn added the security fix A fix that improves security, mostly dependency upgrades via dependabot label Oct 22, 2026
@hahn-kev
hahn-kev merged commit bb056ec into develop Oct 22, 2026
36 of 50 checks passed
@hahn-kev
hahn-kev deleted the php-cve-2026-109618-109619 branch October 22, 2026 03:38
hahn-kev added a commit that referenced this pull request Oct 22, 2026
fixes CI which is currently broken



---

<details>
<summary>AI summary</summary>

## Summary

The deploy job ran `kubectl set image` on a self-hosted runner labelled
`languageforge` that no longer exists. Every staging deploy since May
has queued on it until GitHub cancelled the job after 24 hours. This
replaces it with the LexBox pattern: commit new image tags to the fleet
repo and let Rancher Fleet roll the cluster.

```diff
 integrate-and-deploy.yml
   inputs: image-tag-app, image-tag-proxy, image-tag-next-app
+          k8s-environment (staging | production), deploy-domain
-  secrets: kube-context
+  secrets: fleet-repo-ssh-key
   integrate
+    outputs.TAG_LFMERGE            # so deploy can pin lfmerge too
   deploy
-    runs-on: [self-hosted, languageforge]
-    kubectl set image deployment/{app,next-proxy,next-app,lfmerge}
+    runs-on: ubuntu-latest, concurrency per environment, GitHub environment + url
+    checkout ${{ vars.FLEET_REPO }}@main with FLEET_REPO_SSH_KEY   -> fleet/
+    yq: set newTag for the 4 images in fleet/languageforge/<env>/kustomize/kustomization.yaml
+    add-and-commit + push: "[Language Forge] Update <env> images to <tag>"
 staging.yml      + k8s-environment: staging,    deploy-domain: staging.languageforge.org
 production.yml   + k8s-environment: production, deploy-domain: languageforge.org
 docs/RELEASE.md    describes the fleet flow and manual deploy (edit the kustomization, push main)
```

Unlike LexBox, the fleet repo already holds the full Language Forge
manifests under `languageforge/<env>/kustomize/`, so nothing is copied
from this repo; only the four `newTag` values change. The
`docker/deployment` folder here is now unused by CI.

Actions are SHA-pinned to the same versions LexBox uses.
`docker/login-action` moved from v2 to v3 because actionlint rejects v2
as too old to run.

## Evidence

- **Before:** staging run 39717933967 (merge of #1856): integrate and
all e2e shards green, `deploy` queued forever. Run 25669681222 from May:
`deploy` cancelled after exactly 24 h.
**After:** `actionlint -shellcheck= -pyflakes= .github/workflows/*.yml`
exits 0. The yq expression was run against a copy of the real staging
kustomization and updated all four `newTag` values with the rest of the
file byte-identical.

Not tested: an actual workflow run. It cannot run until the repository
variable and secret below exist.

## Merge Danger

**Door:** two-way

Revert the workflow; nothing in the cluster changes until a deploy runs.

**Blast Radius:** deploys only

Needs, before the first run on `develop`:

- Repository variable `FLEET_REPO` = `sillsdev/languagedepot-deploy`
(same as LexBox).
- Repository secret `FLEET_REPO_SSH_KEY` = a deploy key with write
access on that repo (LexBox's can be reused or a new one added).
- Environments `staging` and `production` are created automatically on
first use; add required reviewers on `production` if you want an
approval gate like LexBox.

`staging.yml` calls the reusable workflow `@develop`, so the new deploy
job is live for staging as soon as this merges to `develop`. Production
picks it up once `master` has it.

</details>

## Test plan

- [x] Add `FLEET_REPO` variable and `FLEET_REPO_SSH_KEY` secret
- [ ] Merge to `develop`; confirm the `deploy` job pushes a commit to
`languagedepot-deploy` and Fleet updates `staging.languageforge.org`
- [ ] Check `staging.languageforge.org` serves PHP 7.4.34-dev (`php -v`
in the app pod)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

security fix A fix that improves security, mostly dependency upgrades via dependabot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants