`
* server-side (file_get_contents for local paths, curl with TLS
* verification disabled for remote URLs) and attached the bytes to the
* outbound mail. A low-privilege user with categories.create/edit +
* assets.checkout could set eula_text to `` or a
* raw `` tag, check the asset out to themselves, and receive the
* file contents (or any URL's response body, including cloud metadata) as
* a MIME attachment.
*
* The fix sanitizes at the model boundary: `SnipeModel::getEula` now
* pipes through `Helper::parseEscapedMarkedown` (strip_tags + Parsedown
* safe mode) and additionally strips `
` from the Parsedown output,
* killing both attack vectors before eula content reaches any mail
* template. `BlockImagesMarkdownExtension` on the mail Markdown parser
* from GHSA-f3vq-g24v-xc2g remains defense in depth.
*
* These tests exercise the model-layer sanitizer directly and the
* end-to-end mailable render so both surfaces are pinned.
*/
class EulaMailAutoEmbedInjectionTest extends TestCase
{
private function assetWithEula(string $eulaText): Asset
{
$category = Category::factory()->assetLaptopCategory()->create([
'eula_text' => $eulaText,
'use_default_eula' => 0,
]);
$model = AssetModel::factory()->create(['category_id' => $category->id]);
return Asset::factory()->create(['model_id' => $model->id]);
}
public function test_get_eula_strips_markdown_syntax_image_pointing_at_local_file()
{
$asset = $this->assetWithEula('');
$rendered = $asset->getEula();
$this->assertStringNotContainsString('
assertStringNotContainsString('/var/www/html/.env', (string) $rendered);
}
public function test_get_eula_strips_raw_html_img_pointing_at_local_file()
{
$asset = $this->assetWithEula('
');
$rendered = $asset->getEula();
$this->assertStringNotContainsString('
assertStringNotContainsString('/var/www/html/.env', (string) $rendered);
}
public function test_get_eula_strips_markdown_syntax_image_pointing_at_ssrf_target()
{
$asset = $this->assetWithEula('');
$rendered = $asset->getEula();
$this->assertStringNotContainsString('
assertStringNotContainsString('169.254.169.254', (string) $rendered);
}
public function test_get_eula_strips_raw_html_img_pointing_at_loopback_ssrf_target()
{
$asset = $this->assetWithEula('
');
$rendered = $asset->getEula();
$this->assertStringNotContainsString('
assertStringNotContainsString('127.0.0.1', (string) $rendered);
}
public function test_get_eula_preserves_legitimate_markdown_formatting()
{
$asset = $this->assetWithEula("**Terms** apply.\n\n- item one\n- item two");
$rendered = (string) $asset->getEula();
$this->assertStringContainsString('Terms', $rendered);
$this->assertStringContainsString('