NixOS: Quick fix for PHP CVE-2026-109618 and CVE-2026-109619

21 Okt. 2026

PHP disclosed two CVSS 9.2 unauthenticated RCE vulnerabilities on 21 October 2026, with exploitation expected within minutes. Patched releases like 8.3.36, 8.4.27 were available immediately, but nixpkgs takes days to catch up: PR, review, Hydra rebuild of PHP and its reverse dependencies, channel advance. Our flake pins a nixpkgs commit, so waiting also means bumping the pin and rebuilding everything else.

An overlay swaps only the PHP source.

{ lib, ... }:
let
  patched = {
    php83 = { version = "8.3.36"; hash = "sha256-RvS0XjaI7SsYGQFae1MsFbUcwFW907E/0A3f7r7tzV8="; };
    php84 = { version = "8.4.27"; hash = "sha256-slMKh3xyL0sIyeF0owywi6wrfhkD7m6eMV8KqfX4LCQ="; };
  };

  mkPhpOverride = name: attrs: _final: prev: {
    ${name} = prev.${name}.overrideAttrs (_: {
      inherit (attrs) version;
      src = mkPatchedSrc prev attrs;
    });
  };
in
{
  nixpkgs.overlays = lib.mkAfter (map (name: mkPhpOverride name patched.${name}) (builtins.attrNames patched));
}

overrideAttrs on the buildEnv wrapper propagates to the unwrapped derivation and rebuilds every enabled extension, so one override covers FPM pools, CLI, Composer and phpXXPackages. lib.mkAfter keeps it last so it wins over other overrides.

The sandbox problem

The build failed on three new tests in ext/filter:

FAIL filter_input() doesn't reach hard limit [tests/oom_filter_input.phpt]
FAIL filter_input_array() doesn't reach hard limit [tests/oom_filter_input_array.phpt]
FAIL filter.default=encoded doesn't reach hard limit while parsing POST data [tests/oom_filter_default_encoded.phpt]

They spawn php-cgi with memory_limit=12M and assert on the fatal-error output, which doesn't reproduce in the Nix build sandbox.

doCheck = false on the extension isn't reachable: extensions live in a packageOverrides scope the buildEnv wrapper doesn't expose, and overriding the extensions function directly causes infinite recursion. So we patched the source instead:

mkPatchedSrc = prev: { version, hash }:
  let
    src = prev.fetchurl {
      url = "https://www.php.net/distributions/php-${version}.tar.bz2";
      inherit hash;
    };
  in
  prev.runCommand "php-${version}-src" { } ''
    mkdir -p "$out"
    tar -xf ${src} -C "$out" --strip-components=1
    rm -f "$out"/ext/filter/tests/oom_filter_input.phpt \
          "$out"/ext/filter/tests/oom_filter_input_array.phpt \
          "$out"/ext/filter/tests/oom_filter_default_encoded.phpt
  '';

Interpreter and extensions share the same src, so removing three files once covers all of them. The interpreter still builds from the patched upstream source.

Takeaway

An overlay is the right tool when a fix is minutes old and the package set is days behind. A few lines, reversible, gone once nixpkgs catches up. The only friction was the test suite — a sandbox limitation, not a problem with the patch.

Neuen Kommentar hinzufügen

Der Inhalt dieses Feldes wird nicht öffentlich zugänglich angezeigt.

Restricted HTML

  • Erlaubte HTML-Tags: <a href hreflang target> <em> <strong> <cite> <blockquote cite> <pre> <ul type> <ol start type> <li> <dl> <dt> <dd> <h4 id> <h5 id> <h6 id>
  • Zeilenumbrüche und Absätze werden automatisch erzeugt.
  • Website- und E-Mail-Adressen werden automatisch in Links umgewandelt.

Angebot innerhalb von 24 Stunden

Ob ein großes kommerzielles System, oder eine kleine Business Seite, wir schicken ein Angebot ab innerhalb von 24 Stunden nachdem Sie diese Taste drücken: Angebot anfordern