From 0c07c10009a2439c8ee56c8faefd1319dc6e388d Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Mon, 18 Nov 2024 15:51:51 -0500 Subject: [PATCH] [5.x] Add upload path traversal tests (#11139) --- tests/Feature/Assets/StoreAssetTest.php | 59 ++++++++++++++++++------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/tests/Feature/Assets/StoreAssetTest.php b/tests/Feature/Assets/StoreAssetTest.php index 4f49180ac8..c417a6d077 100644 --- a/tests/Feature/Assets/StoreAssetTest.php +++ b/tests/Feature/Assets/StoreAssetTest.php @@ -5,6 +5,7 @@ use Illuminate\Http\UploadedFile; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Storage; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use Statamic\Assets\AssetContainer; use Statamic\Facades; @@ -37,22 +38,35 @@ public function setUp(): void } #[Test] - public function it_uploads_an_asset() + #[DataProvider('uploadProvider')] + public function it_uploads_an_asset($filename, $expected) { - Storage::disk('test')->assertMissing('path/to/test.jpg'); + Storage::disk('test')->assertMissing($expected); $this ->actingAs($this->userWithPermission()) - ->submit() - ->assertOk() + ->submit([ + 'file' => UploadedFile::fake()->image($filename), + ]) ->assertJson([ 'data' => [ - 'id' => 'test_container::path/to/test.jpg', - 'path' => 'path/to/test.jpg', + 'id' => 'test_container::'.$expected, + 'path' => $expected, ], ]); - Storage::disk('test')->assertExists('path/to/test.jpg'); + Storage::disk('test')->assertExists($expected); + } + + public static function uploadProvider() + { + return [ + 'test.jpg' => ['test.jpg', 'path/to/test.jpg'], + + // path traversal naughtiness + '../test.jpg urlencoded' => ['%2e%2e%2ftest.jpg', 'path/to/..-test.jpg'], + 'foo/../test.jpg urlencoded' => ['foo%2f%2e%2e%2ftest.jpg', 'path/to/foo-..-test.jpg'], + ]; } #[Test] @@ -187,24 +201,39 @@ public function it_can_upload_with_different_filename() } #[Test] - public function it_can_upload_to_relative_path() + #[DataProvider('relativePathProvider')] + public function it_can_upload_to_relative_path($filename, $expected) { - Storage::disk('test')->assertMissing('path/to/test.jpg'); - Storage::disk('test')->assertMissing('path/to/sub/folder/test.jpg'); + Storage::disk('test')->assertMissing('path/to/'.$filename); + Storage::disk('test')->assertMissing($expected); $this ->actingAs($this->userWithPermission()) - ->submit(['relativePath' => 'sub/folder']) + ->submit([ + 'relativePath' => 'sub/folder', + 'file' => UploadedFile::fake()->image($filename), + ]) ->assertOk() ->assertJson([ 'data' => [ - 'id' => 'test_container::path/to/sub/folder/test.jpg', - 'path' => 'path/to/sub/folder/test.jpg', + 'id' => 'test_container::'.$expected, + 'path' => $expected, ], ]); - Storage::disk('test')->assertMissing('path/to/test.jpg'); - Storage::disk('test')->assertExists('path/to/sub/folder/test.jpg'); + Storage::disk('test')->assertMissing('path/to/'.$filename); + Storage::disk('test')->assertExists($expected); + } + + public static function relativePathProvider() + { + return [ + 'test.jpg' => ['test.jpg', 'path/to/sub/folder/test.jpg'], + + // path traversal naughtiness + '../test.jpg urlencoded' => ['%2e%2e%2ftest.jpg', 'path/to/sub/folder/..-test.jpg'], + 'foo/../test.jpg urlencoded' => ['foo%2f%2e%2e%2ftest.jpg', 'path/to/sub/folder/foo-..-test.jpg'], + ]; } #[Test]