Skip to content

Fix whitelist truncated to 0 bytes when match data contains non-UTF-8 characters#141

Merged
marcocesarato merged 3 commits into
masterfrom
copilot/fix-whitelist-file-permission-issue
May 6, 2026
Merged

Fix whitelist truncated to 0 bytes when match data contains non-UTF-8 characters#141
marcocesarato merged 3 commits into
masterfrom
copilot/fix-whitelist-file-permission-issue

Conversation

Copilot AI commented May 5, 2026

Copy link
Copy Markdown
Contributor

When scanned malware contains binary (non-UTF-8) payloads, the matched bytes end up in the whitelist entry's match field. json_encode() returns false on invalid UTF-8, and passing false to file_put_contents() writes an empty string — silently truncating the whitelist to 0 bytes on every subsequent whitelist attempt.

Changes

  • src/Actions.phpaddToWhitelist()
    • Encode with JSON_INVALID_UTF8_SUBSTITUTE so invalid UTF-8 bytes are replaced with \uFFFD rather than causing json_encode() to fail
    • Guard against false return from json_encode() — bail out early without touching the file if encoding still fails
    • Moved Scanner::setWhitelist() to after successful encoding so in-memory and on-disk state remain consistent
// Before — json_encode() failure silently zeroed the file
return file_put_contents(Scanner::getPathWhitelist(), json_encode($whitelist));

// After — encoding is checked before any write
$encoded = json_encode($whitelist, JSON_INVALID_UTF8_SUBSTITUTE);
if ($encoded === false) {
    return false;
}
Scanner::setWhitelist($whitelist);
return file_put_contents(Scanner::getPathWhitelist(), $encoded);
  • tests/Unit/ActionsTest.php — new unit tests covering: valid write, entry preservation across calls, non-UTF-8 input not truncating an existing whitelist file, and successful substitution of invalid UTF-8 bytes.

  • composer.json / composer.lock — tightened phpunit/phpunit constraint to ^8.5.52|^9.6.33 and updated the lock file to 9.6.34 to address CVE-2026-24765 (Unsafe Deserialization in PHPT Code Coverage Handling).

Copilot AI linked an issue May 5, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Fix failed adding file to whitelist due to permissions error Fix whitelist truncated to 0 bytes when match data contains non-UTF-8 characters May 5, 2026
Copilot AI requested a review from marcocesarato May 5, 2026 21:13
@marcocesarato

Copy link
Copy Markdown
Owner

@copilot /usr/bin/docker run --name ghcriosymfonyclisymfonycliv5_cb406c --label 85db94 --workdir /github/workspace --rm -e "COMPOSER_PROCESS_TIMEOUT" -e "COMPOSER_NO_INTERACTION" -e "COMPOSER_NO_AUDIT" -e "INPUT_LOCK" -e "INPUT_FORMAT" -e "INPUT_DISABLE-EXIT-CODE" -e "HOME" -e "GITHUB_JOB" -e "GITHUB_REF" -e "GITHUB_SHA" -e "GITHUB_REPOSITORY" -e "GITHUB_REPOSITORY_OWNER" -e "GITHUB_REPOSITORY_OWNER_ID" -e "GITHUB_RUN_ID" -e "GITHUB_RUN_NUMBER" -e "GITHUB_RETENTION_DAYS" -e "GITHUB_RUN_ATTEMPT" -e "GITHUB_ACTOR_ID" -e "GITHUB_ACTOR" -e "GITHUB_WORKFLOW" -e "GITHUB_HEAD_REF" -e "GITHUB_BASE_REF" -e "GITHUB_EVENT_NAME" -e "GITHUB_SERVER_URL" -e "GITHUB_API_URL" -e "GITHUB_GRAPHQL_URL" -e "GITHUB_REF_NAME" -e "GITHUB_REF_PROTECTED" -e "GITHUB_REF_TYPE" -e "GITHUB_WORKFLOW_REF" -e "GITHUB_WORKFLOW_SHA" -e "GITHUB_REPOSITORY_ID" -e "GITHUB_TRIGGERING_ACTOR" -e "GITHUB_WORKSPACE" -e "GITHUB_ACTION" -e "GITHUB_EVENT_PATH" -e "GITHUB_ACTION_REPOSITORY" -e "GITHUB_ACTION_REF" -e "GITHUB_PATH" -e "GITHUB_ENV" -e "GITHUB_STEP_SUMMARY" -e "GITHUB_STATE" -e "GITHUB_OUTPUT" -e "RUNNER_OS" -e "RUNNER_ARCH" -e "RUNNER_NAME" -e "RUNNER_ENVIRONMENT" -e "RUNNER_TOOL_CACHE" -e "RUNNER_TEMP" -e "RUNNER_WORKSPACE" -e "ACTIONS_RUNTIME_URL" -e "ACTIONS_RUNTIME_TOKEN" -e "ACTIONS_CACHE_URL" -e "ACTIONS_RESULTS_URL" -e "ACTIONS_ORCHESTRATION_ID" -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work/_temp":"/github/runner_temp" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/_temp/_runner_file_commands":"/github/file_commands" -v "/home/runner/work/PHP-Antimalware-Scanner/PHP-Antimalware-Scanner":"/github/workspace" ghcr.io/symfony-cli/symfony-cli:v5 "security:check" "--format" "ansi" "--dir" "./composer.lock" "--disable-exit-code=0"
Symfony Security Check Report

1 package has known vulnerabilities.

phpunit/phpunit (9.6.29)

  • CVE-2026-24765: Unsafe Deserialization in PHPT Code Coverage Handling

Note that this checker can only detect vulnerabilities that are referenced in the security advisories database.
Execute this command regularly to check the newly discovered vulnerabilities.

Copilot AI commented May 6, 2026

Copy link
Copy Markdown
Contributor Author

@copilot /usr/bin/docker run --name ghcriosymfonyclisymfonycliv5_cb406c --label 85db94 --workdir /github/workspace --rm -e "COMPOSER_PROCESS_TIMEOUT" -e "COMPOSER_NO_INTERACTION" -e "COMPOSER_NO_AUDIT...

Updated phpunit/phpunit to 9.6.34 (patched version for CVE-2026-24765) by tightening the constraint to ^8.5.52|^9.6.33 in composer.json and updating the lock file. All 47 tests still pass. Commit: afa0ebf

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/BrainMaestro/composer-git-hooks/zipball/ffed8803690ac12214082120eee3441b00aa390e
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a8d15584bafb0f0d9d938827840060fd4a3ebc99
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/marcocesarato/php-conventional-changelog/zipball/2a153727bab28c85d54184975292a468fac269f7
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/lofx3X /usr/bin/composer update phpunit/phpunit --with-all-dependencies --no-interaction (http block)
  • https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/comparator/zipball/e4df00b9b3571187db2831ae9aada2c6efbd715d
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b36f02317466907a230d3aa1d34467041271ef4a
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/console/zipball/c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/lofx3X /usr/bin/composer update phpunit/phpunit --with-all-dependencies --no-interaction (http block)
  • https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/e0fe3d79b516eb75126ac6fa4cbf19b79b08c99f
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/event-dispatcher/zipball/72982eb416f61003e9bb6e91f8b3213600dcf9e9
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/filesystem/zipball/57c8294ed37d4a055b77057827c67f9558c95c54
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/finder/zipball/63741784cd7b9967975eec610b256eed3ede022b
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/options-resolver/zipball/74e5b6f0db3e8589e6cfd5efb317a1fc2bb52fb6
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/lofx3X /usr/bin/composer update phpunit/phpunit --with-all-dependencies --no-interaction (http block)
  • https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/lofx3X /usr/bin/composer update phpunit/phpunit --with-all-dependencies --no-interaction (http block)
  • https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/lofx3X /usr/bin/composer update phpunit/phpunit --with-all-dependencies --no-interaction (http block)
  • https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/lofx3X /usr/bin/composer update phpunit/phpunit --with-all-dependencies --no-interaction (http block)
  • https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/lofx3X /usr/bin/composer update phpunit/phpunit --with-all-dependencies --no-interaction (http block)
  • https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/process/zipball/5d1662fb32ebc94f17ddb8d635454a776066733d
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/stopwatch/zipball/fb2c199cf302eb207f8c23e7ee174c1c31a5c004
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/symfony/string/zipball/136ca7d72f72b599f2631aca474a4f8e26719799
    • Triggering command: /usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/lofx3X /usr/bin/composer update phpunit/phpunit --with-all-dependencies --no-interaction (http block)
  • https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678
    • Triggering command: REDACTED, pid is -1 (http block)
  • https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c
    • Triggering command: REDACTED, pid is -1 (http block)

If you need me to access, download, or install something from one of these locations, you can either:

@marcocesarato marcocesarato marked this pull request as ready for review May 6, 2026 07:37
Copilot AI review requested due to automatic review settings May 6, 2026 07:37
@marcocesarato marcocesarato merged commit ca84354 into master May 6, 2026
8 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens whitelist persistence in AMWScan\Actions::addToWhitelist() so invalid UTF-8 bytes in matched malware payloads no longer cause json_encode() failure and silent truncation of scanner-whitelist.json, and adds tests + dependency updates to cover/regress this behavior.

Changes:

  • Encode whitelist JSON with JSON_INVALID_UTF8_SUBSTITUTE and bail out if encoding still fails, to avoid writing empty content.
  • Add unit tests for whitelist writing/preservation and invalid UTF-8 handling.
  • Tighten PHPUnit version constraints and update composer.lock to newer dev dependency versions.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/Actions.php Updates whitelist serialization to tolerate invalid UTF-8 and avoid truncating the file on encode failure.
tests/Unit/ActionsTest.php Adds unit tests covering whitelist writes, preservation across calls, and invalid UTF-8 scenarios.
composer.json Narrows PHPUnit constraints to specific patched versions.
composer.lock Updates locked dev dependencies to match the new constraints.

Comment thread src/Actions.php
Scanner::setWhitelist($whitelist);

return file_put_contents(Scanner::getPathWhitelist(), json_encode($whitelist));
return file_put_contents(Scanner::getPathWhitelist(), $encoded);
Comment thread src/Actions.php
Comment on lines 152 to +167
foreach ($patternFound as $key => $pattern) {
$exploit = $pattern['key'];
$lineNumber = $pattern['line'];
$match = $pattern['match'];
$fileName = str_replace(Scanner::getPathScan(), '', $file);
$key = md5($exploit . $fileName . $lineNumber);
$whitelist[$key] = [
'file' => $fileName,
'exploit' => $exploit,
'line' => $lineNumber,
'match' => $match,
];
}

$encoded = json_encode($whitelist, JSON_INVALID_UTF8_SUBSTITUTE);
if ($encoded === false) {

protected function setUp(): void
{
$this->whitelistFile = tempnam(sys_get_temp_dir(), 'whitelist_') . '.json';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failed adding file to whitelist

3 participants