Parcel Desk: CVE assessment and change plan

Generated: 2026-10-22T04:21:27.004223+00:00

Outcome

Upgrade Parcel Desk from PHP 8.4.26 to 8.4.27 within its existing release branch.

Planning report only. No runtime change or post-change verification was performed. Applicability is based on observed upstream version and configuration evidence; exploitation was not demonstrated.

Evidence

CVE findings

CVE Assessment Fixed version
CVE-2026-109618 Affected version observed 8.4.27
CVE-2026-109619 Affected version observed 8.4.27

Session lifecycle coverage

Prerequisites

1. Confirm the target and current evidence

Run these commands on the Docker host for Parcel Desk. Confirm the container, Compose service, and web PHP version match this plan. Stop if the image, application files, configuration, or advisory evidence has changed.

docker inspect --format 'image={{.Config.Image}} container={{.Name}} started={{.State.StartedAt}}' parceldesk-web
docker compose -f /home/iktdts/apps/website/parceldesk/compose.yaml config --quiet
target_ip=$(docker inspect --format '{{(index .NetworkSettings.Networks "parceldesk_private").IPAddress}}' parceldesk-web)
curl --fail --silent --show-error "http://$target_ip/health.php"

Expected result: parceldesk-web, service web, image php:8.4.26-apache; HTTP health reports PHP 8.4.26 and apache2handler.

2. Confirm application behavior and recovery readiness

Run the normal application checks listed below before the change. Obtain application-owner approval for a restart and record the maintenance window. Confirm a current application/data backup or snapshot and a tested restore procedure; a Compose-file copy alone is not a data backup.

Expected result: Application page, form calculation and session behavior pass; recovery owner and maintenance window are recorded.

3. Save the deployment configuration and obtain the fixed image

Save the current Compose file and pull the proposed image before touching the running service. Record its digest and review the upstream sources linked in this report.

backup_file=/home/iktdts/apps/website/parceldesk/compose.yaml.before-$(date -u +%Y%m%dT%H%M%SZ)
cp -- /home/iktdts/apps/website/parceldesk/compose.yaml "$backup_file"
printf 'Saved deployment configuration to %s\n' "$backup_file"
docker pull php:8.4.27-apache
docker image inspect --format '{{json .RepoDigests}}' php:8.4.27-apache

Expected result: A timestamped Compose backup exists; the fixed image is available locally and its digest is recorded.

4. Edit only the PHP image reference

Replace php:8.4.26-apache with php:8.4.27-apache in /home/iktdts/apps/website/parceldesk/compose.yaml. The guarded edit below stops if the expected old image line is not found exactly once. Review the resulting diff before proceeding.

python3 - <<'PYTHON'
from pathlib import Path
path = Path('/home/iktdts/apps/website/parceldesk/compose.yaml')
text = path.read_text()
old = 'image: php:8.4.26-apache'
new = 'image: php:8.4.27-apache'
if text.count(old) != 1:
    raise SystemExit('Expected image line was not found exactly once; stop and reassess')
path.write_text(text.replace(old, new))
PYTHON
docker compose -f /home/iktdts/apps/website/parceldesk/compose.yaml config --quiet
diff -u "$backup_file" /home/iktdts/apps/website/parceldesk/compose.yaml

Expected result: The only intended change is the image reference for service web. A diff exit status of 1 means differences were found; validation must succeed.

5. Recreate the web service during the approved window

This command stops and replaces the configured web container. Brief unavailability and loss of in-memory sessions are possible. No application source-file edit is planned.

docker compose -f /home/iktdts/apps/website/parceldesk/compose.yaml up -d --no-deps web
docker compose -f /home/iktdts/apps/website/parceldesk/compose.yaml ps web
docker logs --tail 50 parceldesk-web

Expected result: The web service is running with image php:8.4.27-apache, with no startup errors.

6. Verify manually before declaring the change complete

This is a future operator step, not a check executed by this planning workflow. Re-read the web runtime, repeat all normal requests, compare application fingerprints, and record the new container identity. Review fresh upstream evidence if execution happens later.

target_ip=$(docker inspect --format '{{(index .NetworkSettings.Networks "parceldesk_private").IPAddress}}' parceldesk-web)
curl --fail --silent --show-error "http://$target_ip/health.php"
docker inspect --format 'id={{.Id}} image={{.Config.Image}} started={{.State.StartedAt}}' parceldesk-web
docker exec parceldesk-web sha256sum /var/www/html/index.php /var/www/html/health.php /var/www/html/shipments/upload.php /var/www/html/shipments/progress.php

Expected result: The HTTP endpoint reports PHP 8.4.27 and apache2handler; application checks pass; fingerprints match the baseline; the old container has been replaced.

Application acceptance checks

Run these checks before and after the planned change. Use the same cookie file for the request sequence.

target_ip=$(docker inspect --format '{{(index .NetworkSettings.Networks "parceldesk_private").IPAddress}}' parceldesk-web)
curl --fail --silent --show-error "http://$target_ip/health.php"
check_cookies=$(mktemp)
chmod 600 "$check_cookies"

Page

Baseline: passed

curl --fail --silent --show-error -b "$check_cookies" -c "$check_cookies" "http://$target_ip/"

Page contains 'Parcel Desk.'.

Quote

Baseline: passed

curl --fail --silent --show-error -b "$check_cookies" -c "$check_cookies" -X POST --data-urlencode quantity=3 "http://$target_ip/?format=json"

Response values: quantity=3, total=36

Session

Baseline: passed

curl --fail --silent --show-error -b "$check_cookies" -c "$check_cookies" "http://$target_ip/?format=json"

visits increases by one compared with quote.

Manifest_page

Baseline: passed

curl --fail --silent --show-error -b "$check_cookies" -c "$check_cookies" "http://$target_ip/shipments/upload.php"

Page contains 'Upload shipment manifest'.

Manifest_upload

Baseline: passed

manifest_file=$(mktemp)
printf %s 'parcel_id,destination
P001,Denver
' >"$manifest_file"
curl --fail --silent --show-error -b "$check_cookies" -c "$check_cookies" -X POST --form-string PHP_SESSION_UPLOAD_PROGRESS=shipment_manifest -F manifest=@"$manifest_file"';filename=manifest.csv;type=text/csv' "http://$target_ip/shipments/upload.php"
rm -f -- "$manifest_file"

Response values: received=True, upload_progress_enabled=True, upload_count=1

Manifest_session

Baseline: passed

curl --fail --silent --show-error -b "$check_cookies" -c "$check_cookies" "http://$target_ip/shipments/progress.php"

Response values: upload_count=1

rm -f -- "$check_cookies"

Baseline application fingerprints

d3069529be0356b148ffb326872e6a4f074dfffa5c12e05f12fa113ce6bf075e  /var/www/html/index.php
79b2d70ff88b6a0a921f29cf0759e074a092cba0e3f4228a8b0a237305bfc5d3  /var/www/html/health.php
794a0b9f6cfe2409a37d7663dcbca67b3b42c79ced65a4341f7a631b8c65e5cf  /var/www/html/shipments/upload.php
8418f946ca0849644c126ceff912c961cc35c02e4ea0a15b42a6728f3ad699d5  /var/www/html/shipments/progress.php

Recovery guidance

Completion criteria

Upstream evidence