Author: Shivam Mathur (shivammathur)
Date: 2026-10-02T20:00:38+05:30

Commit: 
https://github.com/php/web-downloads/commit/a915aed4ac6cc641fb37a2cb48e2444a1ca2aa53
Raw diff: 
https://github.com/php/web-downloads/commit/a915aed4ac6cc641fb37a2cb48e2444a1ca2aa53.diff

Reject trailing newlines in Winlibs deletion requests

Changed paths:
  M  src/Actions/DeleteWinlibsBuild.php
  M  src/Http/Controllers/WinlibsDeleteController.php
  M  tests/Console/Command/WinlibsCommandDeleteTest.php
  M  tests/Http/Controllers/WinlibsDeleteControllerTest.php


Diff:

diff --git a/src/Actions/DeleteWinlibsBuild.php 
b/src/Actions/DeleteWinlibsBuild.php
index a117899..81b62e3 100644
--- a/src/Actions/DeleteWinlibsBuild.php
+++ b/src/Actions/DeleteWinlibsBuild.php
@@ -44,7 +44,7 @@ public function handle(): void
                 $filename = $data['filename'] ?? null;
                 if (!in_array($type, ['php', 'pecl'], true)
                     || !is_string($filename)
-                    || preg_match('/^[A-Za-z0-9][A-Za-z0-9._-]*\.zip$/', 
$filename) !== 1) {
+                    || preg_match('/\A[A-Za-z0-9][A-Za-z0-9._-]*\.zip\z/', 
$filename) !== 1) {
                     throw new Exception("Invalid Winlibs deletion task: 
$taskFile");
                 }
 
diff --git a/src/Http/Controllers/WinlibsDeleteController.php 
b/src/Http/Controllers/WinlibsDeleteController.php
index 269bf33..c72d84a 100644
--- a/src/Http/Controllers/WinlibsDeleteController.php
+++ b/src/Http/Controllers/WinlibsDeleteController.php
@@ -11,8 +11,8 @@ class WinlibsDeleteController extends BaseController
     protected function validate(array $data): bool
     {
         $validator = new Validator([
-            'type' => 'required|string|regex:/^(php|pecl)$/',
-            'filename' => 
'required|string|regex:/^[A-Za-z0-9][A-Za-z0-9._-]*\.zip$/',
+            'type' => 'required|string|regex:/\A(php|pecl)\z/',
+            'filename' => 
'required|string|regex:/\A[A-Za-z0-9][A-Za-z0-9._-]*\.zip\z/',
         ]);
 
         $validator->validate($data);
diff --git a/tests/Console/Command/WinlibsCommandDeleteTest.php 
b/tests/Console/Command/WinlibsCommandDeleteTest.php
index b31bd62..0fcdb6a 100644
--- a/tests/Console/Command/WinlibsCommandDeleteTest.php
+++ b/tests/Console/Command/WinlibsCommandDeleteTest.php
@@ -5,6 +5,7 @@
 
 use App\Console\Command\WinlibsCommand;
 use App\Helpers\Helpers;
+use PHPUnit\Framework\Attributes\DataProvider;
 use PHPUnit\Framework\TestCase;
 
 class WinlibsCommandDeleteTest extends TestCase
@@ -136,9 +137,10 @@ public function 
testMissingBuildAndIndexEntriesAreIdempotent(): void
         $this->assertSame([], $this->queuedTasks());
     }
 
-    public function testInvalidTaskFailsAndRemainsQueued(): void
+    #[DataProvider('invalidTasks')]
+    public function testInvalidTaskFailsAndRemainsQueued(string $type, string 
$filename): void
     {
-        $task = $this->queue('php', '../outside.zip');
+        $task = $this->queue($type, $filename);
         ob_start();
         $result = $this->runCommand();
         $output = (string) ob_get_clean();
@@ -147,6 +149,17 @@ public function testInvalidTaskFailsAndRemainsQueued(): 
void
         $this->assertFileExists($task);
     }
 
+    public static function invalidTasks(): array
+    {
+        return [
+            'path traversal' => ['php', '../outside.zip'],
+            'php type with trailing newline' => ["php\n", 
'zlib-1.3.2-vs18-x64.zip'],
+            'pecl type with trailing newline' => ["pecl\n", 
'zlib-1.3.2-vs18-x64.zip'],
+            'php filename with trailing newline' => ['php', 
"zlib-1.3.2-vs18-x64.zip\n"],
+            'pecl filename with trailing newline' => ['pecl', 
"zlib-1.3.2-vs18-x64.zip\n"],
+        ];
+    }
+
     public function testIndexFailureRetainsTaskAndZipForRetry(): void
     {
         $directory = $this->baseDirectory . '/pecl/deps';
diff --git a/tests/Http/Controllers/WinlibsDeleteControllerTest.php 
b/tests/Http/Controllers/WinlibsDeleteControllerTest.php
index 8c9a9f5..011960a 100644
--- a/tests/Http/Controllers/WinlibsDeleteControllerTest.php
+++ b/tests/Http/Controllers/WinlibsDeleteControllerTest.php
@@ -63,7 +63,11 @@ public static function invalidPayloads(): array
         return [
             'missing type' => [['filename' => 'zlib-1.3.2-vs18-x64.zip']],
             'bad type' => [['type' => 'other', 'filename' => 
'zlib-1.3.2-vs18-x64.zip']],
+            'php type with trailing newline' => [['type' => "php\n", 
'filename' => 'zlib-1.3.2-vs18-x64.zip']],
+            'pecl type with trailing newline' => [['type' => "pecl\n", 
'filename' => 'zlib-1.3.2-vs18-x64.zip']],
             'missing filename' => [['type' => 'php']],
+            'php filename with trailing newline' => [['type' => 'php', 
'filename' => "zlib-1.3.2-vs18-x64.zip\n"]],
+            'pecl filename with trailing newline' => [['type' => 'pecl', 
'filename' => "zlib-1.3.2-vs18-x64.zip\n"]],
             'path traversal' => [['type' => 'php', 'filename' => 
'../zlib.zip']],
             'nested path' => [['type' => 'php', 'filename' => 
'vs18/x64/zlib.zip']],
             'non zip' => [['type' => 'pecl', 'filename' => 'packages.txt']],

Reply via email to