create(); $asset = Asset::factory()->create(['name' => $assetName, 'company_id' => $company->id]); return CheckoutAcceptance::factory()->pending()->for($asset, 'checkoutable')->create(); } public function test_data_rows_with_formula_prefix_are_escaped_by_default() { $this->seedPendingAcceptanceWithAssetNamed('=HYPERLINK("http://attacker.test","click")'); $body = $this->actingAs(User::factory()->superuser()->create()) ->post(route('reports/export/unaccepted_assets')) ->assertOk() ->getContent(); $this->assertStringNotContainsString('=HYPERLINK("http://attacker.test","click")', $body); $this->assertStringContainsString('`=HYPERLINK', $body); } public function test_data_rows_with_plus_and_at_prefixes_are_escaped() { $this->seedPendingAcceptanceWithAssetNamed('+cmd|/c calc'); $this->seedPendingAcceptanceWithAssetNamed('@SUM(A1:A9)'); $body = $this->actingAs(User::factory()->superuser()->create()) ->post(route('reports/export/unaccepted_assets')) ->assertOk() ->getContent(); $this->assertStringContainsString('`+cmd|', $body); $this->assertStringContainsString('`@SUM(', $body); } public function test_data_rows_are_not_escaped_when_setting_disabled() { // Matches how the sibling exports in ReportsController behave when // operators intentionally disable escaping. config(['app.escape_formulas' => false]); $this->seedPendingAcceptanceWithAssetNamed('=SUM(A1:A9)'); $body = $this->actingAs(User::factory()->superuser()->create()) ->post(route('reports/export/unaccepted_assets')) ->assertOk() ->getContent(); $this->assertStringContainsString('=SUM(A1:A9)', $body); $this->assertStringNotContainsString('`=SUM(A1:A9)', $body); } }