Skip to content
← /srv/projects

WordPress Dependency Pipeline

Year
2026
Role
Sole developer
Status
live

A live WordPress compromise I worked alone on call, turned into a pipeline that keeps the site current on its own — auto-merging what is safe, escalating what is not, and cutting update noise by around 80%.

  • WordPress
  • Bedrock
  • Composer
  • GitHub Actions
  • Dependabot
  • Slack

Problem

A WordPress instance was exposed to wp2shell: two chained flaws, patched upstream in July 2026, that allowed malicious code to be injected without a login and without any user interaction. A successful exploit does not just deface a site — it hands over broad privileges and whatever the installation can reach, including database credentials, tokens and API keys.

I was the only person on call that day, so the response was mine end to end.

It was not theoretical. Alongside patching, the log sweep turned up unauthorised administrator accounts — someone had already acted on the exposure. So the work was an incident response rather than a precautionary update: remove the accounts, rotate every administrator credential, and go back through the logs looking for anything else that had been done while they had access.

Patching took an afternoon. The uncomfortable part took longer to admit: the site would drift out of date again, nobody would notice until the next advisory, and the next one might land on a day when nobody was available at all.

WordPress dependency updates fail in a particular way. Turn automation on naively and you get a wall of pull requests nobody reads, so they get ignored, so you are back where you started with extra noise. Leave it manual and it depends on somebody remembering.

Approach

The site is Bedrock — a Composer-managed WordPress — so its dependencies are tractable rather than a folder full of plugins. That made a real pipeline possible using Dependabot and GitHub Actions.

Grouping, because noise is the failure mode. Semantic package grouping and rule-based limits consolidate minor and patch updates for plugins and core into far fewer pull requests. That cut PR volume and automated build minutes by roughly 80% — a number that matters less as a saving than as the reason anybody still looks at the ones that remain.

Auto-merge with guardrails. Custom GitHub Actions workflows validate, squash and merge safe patch and minor updates without a human. Anything that could break is not eligible, so the automation is trusted to be boring.

Escalation, not silence. A custom Slack app receives major version alerts, so breaking core and plugin releases go to a person for manual review before they reach production. The pipeline is explicitly not allowed to decide the risky cases.

Outcome

The site keeps itself current for the routine majority of updates, and asks for a human on the ones that warrant it.