Back to Bugs

ViciBox 12 · Apache/mod_php security advisory

ViciBox 12 PHP security update: verify the served runtime

The official ViciBox advisory identifies critical PHP flaws and requires PHP 8.2.35 or later on ViciBox 12. There may be no visible application symptom.

Source and affected scope

php2shell fixes for ViciBox 11 and 12

  • Official ViciBox 12 advisory for PHP security issues CVE-2026-109618 and CVE-2026-109619. Apache with mod_php is explicitly identified by the vendor.
  • This command path is for ViciBox 12 on openSUSE Leap 15.6. The ViciBox 11 experimental backport uses a different repository and expected version; do not run the V12 commands there.

Before you start

  • A root maintenance shell, current administrative access, and a separately approved package/service maintenance window. Keep the same shell for variables used across the steps.
  • A verified recovery route: a restorable machine snapshot/image and console access, or exact signed prior RPMs, a complete PHP/Apache configuration backup and working SSH access independent of Apache. Record the actual method before any package change.
  • A working private read-only MySQL option file selecting the VICIdial database; use the site’s read-only-database-account guide if one does not exist.
  • A known synthetic user, phone and inactive lab campaign for login checks. Any new call must be separately approved; ordinary package verification does not require an outside call.
  • For the temporary web-runtime probe: the active local HTTPS vhost, its DocumentRoot, and a certificate chain trusted by curl. The probe must be served directly by this Apache host, not relayed to another backend.

Diagnose the reported problem

  1. Step 1Establish OS, installed packages and Apache module

    Run these read-only checks before choosing a remediation branch. Save package release suffixes, not just major/minor PHP numbers.

    Use apache2ctl -S and the DocumentRoot directives to identify the vhost actually used by agents. A separate CLI binary may differ from the Apache module.

    Before you use it
    Run these read-only checks before choosing a remediation branch. Save package release suffixes, not just major/minor PHP numbers.
    Establish OS, installed packages and Apache module
    cat /etc/os-releaserpm -q php8 php8-cli apache2-mod_php8php -vapache2ctl -Mapache2ctl -Sgrep -R -n '^[[:space:]]*DocumentRoot' /etc/apache2
    Not executed · deliberately not run on the demo

    This sample changes a system, contacts an outside service, needs a live call, or would print real data from a shared server, so it was not run on the demo. Run it only where you are authorized, and compare the result with the success and stop guidance.

    Success looks like
    The host is Leap 15.6/ViciBox 12, PHP packages are identified and php_module appears in Apache’s module list if mod_php is in use.
    Stop if
    If OS, SAPI or repository family differs, stop this package recipe and use that platform’s documented fix. An absent package does not establish that the web service is safe.
    Expected observation
    The host is Leap 15.6/ViciBox 12, PHP packages are identified and php_module appears in Apache’s module list if mod_php is in use.
    If this check fails
    If OS, SAPI or repository family differs, stop this package recipe and use that platform’s documented fix. An absent package does not establish that the web service is safe.
  2. Step 2Confirm the PHP version served by the real local vhost

    Run the complete subshell as root. It creates one temporary version-only PHP file and deletes it on exit; it does not expose phpinfo or configuration values.

    Enter the hostname and DocumentRoot identified above. The request connects to 127.0.0.1 while preserving hostname/SNI and normal certificate validation. Confirm this is the actual vhost, not an unrelated default site.

    The script denies non-loopback remote addresses. If a reverse proxy makes external requests appear as loopback, first arrange a private equivalent probe with a real server access restriction; do not deploy this file on that topology unchanged.

    Save the complete JSON privately before and after maintenance. Compare the web extension list with that web baseline, and the CLI extension list with its separate CLI baseline. Do not expose phpinfo or environment/configuration secrets.

    Before you use it
    Run the complete subshell as root. It creates one temporary version-only PHP file and deletes it on exit; it does not expose phpinfo or configuration values.
    Confirm the PHP version served by the real local vhost
    (set -euread -r -p 'Active HTTPS hostname, without scheme or path: ' php_probe_hostcase "$php_probe_host" in ''|*[!A-Za-z0-9.-]*) printf 'Invalid hostname\n'; exit 1;; esacread -r -p 'DocumentRoot of that HTTPS vhost: ' php_probe_rootcase "$php_probe_root" in /*) ;; *) printf 'Use an absolute path\n'; exit 1;; esactest -d "$php_probe_root" || exit 1php_probe_file=$(mktemp "$php_probe_root/vicigeek-runtime-XXXXXXXX.php")trap 'rm -f -- "$php_probe_file"' EXITcat > "$php_probe_file" <<'PHP'<?phpif (!in_array($_SERVER['REMOTE_ADDR'] ?? '', ['127.0.0.1', '::1'], true)) {    http_response_code(404);    exit;}header('Content-Type: application/json');header('Cache-Control: no-store');echo json_encode(['sapi' => PHP_SAPI, 'version' => PHP_VERSION, 'extensions' => get_loaded_extensions()]), "\n";PHPchmod 0644 "$php_probe_file"curl --fail --silent --show-error --noproxy '*' \  --resolve "$php_probe_host:443:127.0.0.1" \  "https://$php_probe_host/$(basename "$php_probe_file")")
    Not executed · deliberately not run on the demo

    This sample changes a system, contacts an outside service, needs a live call, or would print real data from a shared server, so it was not run on the demo. Run it only where you are authorized, and compare the result with the success and stop guidance.

    Success looks like
    JSON identifies the actual served SAPI, PHP version and complete loaded-extension list. For this mod_php branch, expect apache2handler.
    Stop if
    An HTML login page, 401/403, redirect, certificate error or wrong SAPI is not a version result. The trap removes the file; resolve the vhost/access path without bypassing TLS verification.
    Expected observation
    JSON identifies the actual served SAPI, PHP version and complete loaded-extension list. For this mod_php branch, expect apache2handler.
    If this check fails
    An HTML login page, 401/403, redirect, certificate error or wrong SAPI is not a version result. The trap removes the file; resolve the vhost/access path without bypassing TLS verification.
  3. Step 3Prepare private backups and a real recovery point

    Choose and verify a recovery route before changing packages: either a restorable machine snapshot/image with a recorded ID, or the exact signed prior RPMs plus complete configuration backup and working SSH access independent of Apache. Do not claim a VM snapshot exists when it has not been verified.

    The bounded Solarefer proposal uses the signed prior-version RPMs, a private configuration archive and confirmed SSH access. The archive must include /etc/sysconfig/apache2, which controls SUSE Apache module/configuration selection, and the PHP CLI alternative/symlink state.

    Preserve complete CLI and web loaded-extension inventories separately. Compare each SAPI against its own before-state after the update; a four-extension spot check or CLI version alone cannot establish full web-runtime acceptance.

    Before you use it
    Choose and verify a recovery route before changing packages: either a restorable machine snapshot/image with a recorded ID, or the exact signed prior RPMs plus complete configuration backup and working SSH access independent of Apache. Do not claim a VM snapshot exists when it has not been verified.
    Prepare private backups and a real recovery point
    test "$(id -u)" -eq 0 || { printf 'Open an approved root maintenance shell.\n'; exit 1; }umask 077php_repair_dir=$(mktemp -d /root/vicigeek-php-repair.XXXXXXXX)read -r -p 'Verified snapshot ID or signed-RPM/config/SSH recovery reference: ' php_restore_idtest -n "$php_restore_id" || exit 1printf '%s\n' "$php_restore_id" > "$php_repair_dir/recovery-point.txt"rpm -qa --qf '%{NAME} %{VERSION}-%{RELEASE} %{ARCH}\n' | sort > "$php_repair_dir/packages-before.txt"zypper lr -u > "$php_repair_dir/repos-before.txt"zypper locks > "$php_repair_dir/locks-before.txt"tar --acls --xattrs -cpf "$php_repair_dir/config-before.tar" -C / etc/apache2 etc/php8 etc/sysconfig/apache2 etc/zyppprintf 'Private record: %s\n' "$php_repair_dir"command -v php > "$php_repair_dir/php-command-before.txt"readlink -f "$(command -v php)" > "$php_repair_dir/php-resolved-before.txt"php -r 'echo json_encode(get_loaded_extensions()), "\n";' > "$php_repair_dir/cli-extensions-before.json"
    Not executed · deliberately not run on the demo

    This sample changes a system, contacts an outside service, needs a live call, or would print real data from a shared server, so it was not run on the demo. Run it only where you are authorized, and compare the result with the success and stop guidance.

    Success looks like
    A verified recovery route and private record contain exact rollback packages, PHP/Apache configuration including sysconfig, CLI selection and separate before-runtime module inventories.
    Stop if
    If recovery cannot restore the previous package binaries and bootable machine, stop before repository changes.
    Expected observation
    A verified recovery route and private record contain exact rollback packages, PHP/Apache configuration including sysconfig, CLI selection and separate before-runtime module inventories.
    If this check fails
    If recovery cannot restore the previous package binaries and bootable machine, stop before repository changes.
  4. Step 4Read the actual bounded demo transaction separately

    The downloadable manifest records the24 proposed runtime RPMs and24 exact rollback RPMs, their official URLs and verified hashes. This is a Solarefer-specific8.2.30-to 8.2.35 package set; compare your own installed versions before using it.

    The captured command ran in a private plan directory containing target/*.rpm, an empty repos directory and a private cache. It resolves only local RPMs and installed dependencies, without refreshing or changing configured repositories. No package was installed.

    The resolver preview skipped its own file-conflict check for uncached RPMs. An independent rpm --upgrade --test of the already downloaded files returned 0, and all target/rollback signatures passed. Installation, Apache restart and post-change acceptance still require approval.

    Before you use it
    Read the private-directory and staged-RPM context above. The files were downloaded and signature-checked before this exact command.
    Actual bounded Solarefer dry run
    timeout 35 zypper --non-interactive --no-refresh --reposd-dir "$PWD/repos" --cache-dir "$PWD/cache" install --dry-run --allow-vendor-change --no-recommends target/*.rpm
    Evidence · Solarefer PHP maintenance preparation: exact local-RPM dry run; no installation or restart.

    Captured demo response · 2026-11-06T23:25:03.898831+00:00. Any filtering, hidden values or test-only data are identified in the capture label. Select Replay transcript to read the recorded output.

    Command output line: timeout 35 zypper --non-interactive --no-refresh --reposd-dir "$PWD/repos" --cache-dir "$PWD/cache" install --dry-run --allow-vendor-change --no-recommends target/*.rpm
    Loading repository data...
    Reading installed packages...
    Resolving package dependencies...
    The following 24 packages are going to be upgraded:
    apache2-mod_php8 php8 php8-bz2 php8-cli php8-ctype php8-curl php8-dom php8-ftp php8-gd php8-gettext php8-iconv php8-mbstring php8-mysql php8-opcache php8-openssl php8-pdo php8-phar php8-soap php8-sqlite php8-tokenizer php8-xmlreader php8-xmlwriter php8-zip php8-zlib
    The following 24 packages are going to change vendor:
    apache2-mod_php8
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-bz2
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-cli
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-ctype
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-curl
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-dom
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-ftp
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-gd
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-gettext
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-iconv
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-mbstring
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-mysql
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-opcache
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-openssl
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-pdo
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-phar
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-soap
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-sqlite
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-tokenizer
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-xmlreader
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-xmlwriter
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-zip
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    php8-zlib
    SUSE LLC <https://www.suse.com/> -> obs://build.opensuse.org/devel:languages:php:php82
    24 packages to upgrade, 24 to change vendor.
    Package download size: 6.3 MiB
    Package install size change:
    | 24.9 MiB required by packages that will be installed
    56.4 KiB | - 24.8 MiB released by packages that will be removed
    Backend: classic_rpmtrans --dry-run
    Continue? [y/n/v/...? shows all options] (y): y
    Checking for file conflicts: [...done]
    Warning: 24 packages had to be excluded from file conflicts check because they are not yet downloaded.
    Note: Checking for file conflicts requires not installed packages to be downloaded in advance in
    order to access their file lists. See option '--download-in-advance / --dry-run --download-only'
    in the zypper manual page for details.
    Success looks like
    The captured preview exits 0 and resolves the exact 24-package plan.
    Stop if
    A different plan is a new transaction and needs separate review.
    Expected observation
    Exactly24 runtime upgrades and24 vendor changes, with no added or removed packages; this is still a preview, not a fixed runtime.
    If this check fails
    Stop if the package set differs, signature/checksum checks fail or the required recovery RPMs are unavailable.

Correct the confirmed cause

Use this branch only when your diagnostic observations match the affected scope above. The lab result states which outcomes were actually tested.

  1. Step 5Add or confirm the exact official PHP 8.2 repository

    This changes repository configuration and refreshes metadata; it does not yet install packages. Proceed only with authorization to prepare the maintenance transaction.

    Inspect zypper lr -u first. If alias devel_languages_php_php82 already exists with exactly the official URL, skip zypper ar. If that alias points elsewhere, stop and resolve the conflict instead of creating a duplicate or replacing it blindly.

    The vendor example can auto-import GPG keys. Here refresh interactively so the proposed signing key can be checked against the official repository key through an independent trusted channel before accepting it. Do not disable signature checks.

    Before you use it
    This changes repository configuration and refreshes metadata; it does not yet install packages. Proceed only with authorization to prepare the maintenance transaction.
    Add or confirm the exact official PHP 8.2 repository
    zypper lr -uread -r -p 'Type ADD if the alias is absent, or VERIFIED if its URL already matches: ' php_repo_actioncase "$php_repo_action" in  ADD) zypper ar https://download.opensuse.org/repositories/devel:/languages:/php:/php82/openSUSE_Leap_15.6/devel:languages:php:php82.repo || exit 1 ;;  VERIFIED) ;;  *) printf 'Repository preparation stopped.\n'; exit 1 ;;esaczypper mr -f devel_languages_php_php82 || exit 1zypper ref devel_languages_php_php82
    Not executed · deliberately not run on the demo

    This sample changes a system, contacts an outside service, needs a live call, or would print real data from a shared server, so it was not run on the demo. Run it only where you are authorized, and compare the result with the success and stop guidance.

    Success looks like
    The named repository is the official Leap 15.6 PHP 8.2 repository, refresh is enabled and signed metadata refresh succeeds.
    Stop if
    A stale/missing repository, unexpected URL or signing-key mismatch is a stop. Never continue using guessed packages or --no-gpg-checks.
    Expected observation
    The named repository is the official Leap 15.6 PHP 8.2 repository, refresh is enabled and signed metadata refresh succeeds.
    If this check fails
    A stale/missing repository, unexpected URL or signing-key mismatch is a stop. Never continue using guessed packages or --no-gpg-checks.
  2. Step 6Review the package transaction before applying it

    This sample is the documented repository-scoped vendor method and was not the bounded Solarefer transaction. A repository-wide dup can change additional packages, including PEAR. The completed demo transaction instead used exactly 24 runtime RPMs and followed a separately reviewed local-file plan; its preview does not validate a different dup transaction.

    Run the dry run and retain the complete output in the private record. Confirm the PHP CLI, Apache module and required extensions move together to compatible patched packages.

    Review removals, vendor changes, downloads and service-script effects. Stop for a Perl/OpenSSL transition, missing PHP extensions or unrelated removals until the dependency plan is explained.

    Provide the concrete package list, expected Apache restart impact, recovery identifier and verification checklist for maintenance approval. A dry run is not a completed patch.

    Before you use it
    This sample is the documented repository-scoped vendor method and was not the bounded Solarefer transaction. A repository-wide dup can change additional packages, including PEAR. The demo proposal instead stages exactly24 runtime RPMs and uses a separately reviewed local-file plan; its preview does not validate a different dup transaction.
    Review the package transaction before applying it
    zypper dup --dry-run --from devel_languages_php_php82 --allow-vendor-change
    Not executed · deliberately not run on the demo

    This sample changes a system, contacts an outside service, needs a live call, or would print real data from a shared server, so it was not run on the demo. Run it only where you are authorized, and compare the result with the success and stop guidance.

    Success looks like
    A reviewed repository-scoped proposal reaches PHP 8.2.35 or newer with the needed Apache module/extensions and no unexplained removals.
    Stop if
    If the fixed version is unavailable or dependencies are unresolved, stop. Do not run an unrestricted distribution upgrade to force a result.
    Expected observation
    A reviewed repository-scoped proposal reaches PHP 8.2.35 or newer with the needed Apache module/extensions and no unexplained removals.
    If this check fails
    If the fixed version is unavailable or dependencies are unresolved, stop. Do not run an unrestricted distribution upgrade to force a result.
  3. Step 7Finish agent work and verify the maintenance window is clear

    Ask each affected agent to finish/disposition their call and log out. Keep the admin session available for maintenance checks.

    Enter the private existing read-only MySQL option file that selects the VICIdial database. Do not place a password on the command line.

    Both counts below must be zero before restarting this shared web service. A zero call count with a live agent row still requires session cleanup or explicit handling; do not delete live-agent rows to make the gate pass.

    Before you use it
    Ask each affected agent to finish/disposition their call and log out. Keep the admin session available for maintenance checks.
    Finish agent work and verify the maintenance window is clear
    read -r -p 'Absolute path to private read-only MySQL option file: ' php_db_clienttest -f "$php_db_client" || exit 1mysql --defaults-extra-file="$php_db_client" --batch --raw -e \  "SELECT COUNT(*) AS active_call_rows FROM vicidial_auto_calls; SELECT COUNT(*) AS live_agent_rows FROM vicidial_live_agents;"
    Not executed · deliberately not run on the demo

    This sample changes a system, contacts an outside service, needs a live call, or would print real data from a shared server, so it was not run on the demo. Run it only where you are authorized, and compare the result with the success and stop guidance.

    Success looks like
    No active-call rows or live-agent sessions remain, and the approved maintenance window has started.
    Stop if
    If either count is nonzero, wait for controlled logout/completion and recheck. If the counts disagree with the live UI, investigate that mismatch before package/service changes.
    Expected observation
    No active-call rows or live-agent sessions remain, and the approved maintenance window has started.
    If this check fails
    If either count is nonzero, wait for controlled logout/completion and recheck. If the counts disagree with the live UI, investigate that mismatch before package/service changes.
  4. Step 8Apply the exact reviewed transaction and restart Apache

    Package scriptlets can reload systemd and restart Apache during installation or rollback, before any later manual command. Inspect the verified RPM scriptlets, loaded Apache instances, target dependencies and existing /run/httpd.restart.flag* markers before installation; stop if restart scope exceeds the approved Apache instance.

    Obtain explicit maintenance approval and finish the fresh call/session gate before starting the package transaction itself. Run apache2ctl configtest before installation. It validates the current configuration only; repeat it against the new module afterward.

    Review the exact transaction again. Monitor its live process/session to confirmed completion; an observation timeout does not mean the RPM transaction stopped. Never reuse the preview timeout for installation or rollback, or kill/restart a transaction because output paused.

    After installation, verify actual service state and the served runtime even when the package manager exits 0: the RPM post-transaction hook can ignore an Apache restart failure. If the hook has already loaded the new runtime, avoid an unnecessary extra restart. Otherwise restart the approved Apache service only after configtest passes.

    This displayed repository-scoped vendor command is unexecuted. The demo instead completed the separately reviewed bounded 24-RPM local-file installation; its signed target versions and post-install checks are in the execution receipt.

    Before you use it
    Read the package-hook scope above and complete recovery, call/session and config gates before installation. The package transaction itself can restart Apache.
    Apply the exact reviewed transaction and restart Apache
    apache2ctl configtest || exit 1zypper dup --from devel_languages_php_php82 --allow-vendor-change || exit 1apache2ctl configtest || exit 1systemctl is-active apache2systemctl show apache2 -p ActiveState -p SubState -p ExecMainStartTimestampprintf 'Repeat the served-runtime probe now. If Apache is inactive or still serves the old PHP, recheck the approved maintenance gate and run systemctl restart apache2 once, then repeat service and runtime checks.\n'
    Not executed · deliberately not run on the demo

    This sample changes a system, contacts an outside service, needs a live call, or would print real data from a shared server, so it was not run on the demo. Run it only where you are authorized, and compare the result with the success and stop guidance.

    Success looks like
    The reviewed packages install, the new module passes configtest and the actual served runtime reaches the fixed version. If normal RPM hooks already loaded it, no extra restart is needed; otherwise use the explicit approved restart branch and verify it.
    Stop if
    If package installation or configtest fails, stop before additional changes. If Apache cannot start, use the recorded package/config recovery plan through independent SSH or the approved console; do not repeatedly reinstall unrelated packages.
    Expected observation
    The reviewed packages install, the new module passes configtest and the actual served runtime reaches the fixed version. If normal RPM hooks already loaded it, no extra restart is needed; otherwise use the explicit approved restart branch and verify it.
    If this check fails
    If package installation or configtest fails, stop before additional changes. If Apache cannot start, use the recorded package/config recovery plan through independent SSH or the approved console; do not repeatedly reinstall unrelated packages.
  5. Step 9Verify the served runtime and native workflows

    Repeat the package/CLI checks and the temporary served-runtime probe from step 2. A newly installed RPM with an old Apache process is not enough.

    Open the actual VICIdial Administration login and sign in with the authorized test account. Confirm the version footer loads and open Reports, then a narrow report for the synthetic lab fixture. Record success or the exact error; avoid customer rows in screenshots.

    Open the Agent login page and confirm it renders without a new PHP fatal error. This does not establish authenticated agent-session or call acceptance. For a separate full Agent login, use the approved active MANUAL test-campaign preflight in the beginner course, then log out and restore that fixture.

    Compare every previously loaded CLI extension and every previously loaded web extension with its own before list. Check Apache configuration, actual service state and authenticated Admin/report responses independently; a successful package exit code is insufficient.

    Before you use it
    Repeat the package/CLI checks and the temporary served-runtime probe from step 2. A newly installed RPM with an old Apache process is not enough.
    Verify the served runtime and native workflows
    rpm -q php8 php8-cli apache2-mod_php8php -vapache2ctl -Mjournalctl -u apache2 --since '-15 minutes' --no-pager
    Not executed · deliberately not run on the demo

    This sample changes a system, contacts an outside service, needs a live call, or would print real data from a shared server, so it was not run on the demo. Run it only where you are authorized, and compare the result with the success and stop guidance.

    Success looks like
    The served PHP runtime is8.2.35 or newer on the intended8.2 branch; authenticated Admin and the chosen report work, and the Agent login page renders. Authenticated Agent/call acceptance is a separate test.
    Stop if
    A login/report failure after a runtime update is a failed application check even when php -v is correct. Record it, keep the maintenance window open and follow the recovery plan.
    Expected observation
    The served PHP runtime is8.2.35 or newer on the intended8.2 branch; authenticated Admin and the chosen report work, and the Agent login page renders. Authenticated Agent/call acceptance is a separate test.
    If this check fails
    A login/report failure after a runtime update is a failed application check even when php -v is correct. Record it, keep the maintenance window open and follow the recovery plan.
  6. Step 10Inspect the completed demo CLI capture

    This exact command ran after the completed bounded installation. It verifies the CLI version only; use the AFTER Apache screenshot and served-runtime check for web acceptance.

    Download the completed execution receipt to inspect all 24 installed targets, the independent CLI/web extension comparisons and the native application results.

    Before you use it
    Recorded after the completed 24-package maintenance on the pinned demo.
    Actual completed demo CLI version
    php -v | head -n 1
    Evidence · Completed Solarefer PHP transaction log; timestamp is the local log modification time after completion. Exact command/output retained.

    Captured demo response · 2026-11-07T06:04:20.926030+00:00. Any filtering, hidden values or test-only data are identified in the capture label. Select Replay transcript to read the recorded output.

    Command output line: php -v | head -n 1
    PHP 8.2.35 (cli) (built: Oct 21 2026 12:00:00) (NTS)
    Success looks like
    PHP 8.2.35 is present in the CLI; web verification is shown separately.
    Stop if
    Do not use CLI-only output to infer Apache loaded the patched runtime.
    Expected observation
    The completed demo command reports PHP 8.2.35 (cli).
    If this check fails
    A patched CLI with an older served Apache runtime is incomplete. Recheck the loaded Apache process and its actual web response.

Verify the outcome

  • All Apache-bearing servers, including any archive web host, need their own applicability, package and served-runtime checks; one host does not establish cluster coverage.
  • Retain before/after package versions, actual served SAPI/version, restart time and concrete native Admin/report/Agent results. Redact credentials, private URLs and customer data from any shared capture.
  • Review new Apache/PHP errors as well as systemd state. An active service and a 200 response alone do not prove the application works.
  • Verify that the temporary probe was removed and a subsequent request to that generated path returns 404.
  • Do not label the system fully secured or exploit-tested from these checks; they establish the scoped package/runtime and workflow results.

Recover or roll back

  • If only repository preparation was performed, remove only a newly added alias after confirming it did not exist before; retain a pre-existing alias and its prior refresh policy. Use the saved repository configuration as the comparison, not a blanket overwrite.
  • After packages change, restoring php.ini or repositories alone is insufficient. Restore the recorded whole-machine snapshot/image through the approved console procedure, or execute a reviewed reverse package transaction using retained signed versions and then restore compatible configuration.
  • After any rollback, run Apache configtest before starting/restarting it, repeat the served-runtime and native application checks, and record the resulting version. A rollback to a vulnerable PHP build leaves the security issue open and requires constrained access and a new remediation plan.
  • Keep the private transaction and verification records. Do not delete application databases or call history during PHP recovery.

Screenshot evidence

Before the security update: actual web runtime

Open to enlarge
Actual Apache PHP probe reports version 8.2.30 and apache2handler with required modules loaded
Genuine Agent Browser capture before maintenance: the loopback-only Apache response serves PHP 8.2.30. Compare with the matching AFTER capture below.

After the security update: actual web runtime

Open to enlarge
Actual Apache PHP probe after maintenance reports version 8.2.35 and apache2handler with required modules loaded
Genuine Agent Browser capture on November 7 after the 24-package update and normal RPM-triggered Apache restart.
Capture detailsPHP is served as 8.2.35; the complete 39-extension inventory also matches the before set. The temporary probe was removed afterward.

Native Agent login page after maintenance

Open to enlarge
Actual VICIdial Agent login page renders after PHP maintenance with blank Phone Login and Phone Password fields
Actual untouched VICIdial login page after the update.
Capture detailsThe fields stayed blank and the form was not submitted. Authenticated Admin and the synthetic-user report also passed separate read-only checks; this screenshot does not establish Agent-session or call acceptance.

Actions to avoid

Do not treat a CLI version, successful package download or firewall allowlist as proof that the running web runtime is patched.