diff --git a/.env.example b/.env.example
index 4b158bf0..89e85750 100644
--- a/.env.example
+++ b/.env.example
@@ -17,3 +17,7 @@ DB_PASSWORD=
SESSION_DOMAIN=null
SANCTUM_STATEFUL_DOMAIN=
TRUSTED_PROXIES="*"
+
+# Dompdf: keep false so untrusted HTML in PDF notes cannot trigger outbound requests (SSRF).
+# Set true only if you fully trust all PDF HTML and need remote images/CSS.
+DOMPDF_ENABLE_REMOTE=false
diff --git a/app/Models/Estimate.php b/app/Models/Estimate.php
index 353996fc..cafacfc1 100644
--- a/app/Models/Estimate.php
+++ b/app/Models/Estimate.php
@@ -8,6 +8,7 @@ use App\Facades\PDF;
use App\Mail\SendEstimateMail;
use App\Services\SerialNumberFormatter;
use App\Space\PdfTemplateUtils;
+use App\Support\PdfHtmlSanitizer;
use App\Traits\GeneratesPdfTrait;
use App\Traits\HasCustomFieldsTrait;
use Carbon\Carbon;
@@ -475,7 +476,7 @@ class Estimate extends Model implements HasMedia
public function getNotes()
{
- return $this->getFormattedString($this->notes);
+ return PdfHtmlSanitizer::sanitize($this->getFormattedString($this->notes));
}
public function getEmailAttachmentSetting()
diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php
index 3f88a2c7..f77c6e05 100644
--- a/app/Models/Invoice.php
+++ b/app/Models/Invoice.php
@@ -8,6 +8,7 @@ use App\Facades\PDF;
use App\Mail\SendInvoiceMail;
use App\Services\SerialNumberFormatter;
use App\Space\PdfTemplateUtils;
+use App\Support\PdfHtmlSanitizer;
use App\Traits\GeneratesPdfTrait;
use App\Traits\HasCustomFieldsTrait;
use Carbon\Carbon;
@@ -644,7 +645,7 @@ class Invoice extends Model implements HasMedia
public function getNotes()
{
- return $this->getFormattedString($this->notes);
+ return PdfHtmlSanitizer::sanitize($this->getFormattedString($this->notes));
}
public function getEmailString($body)
diff --git a/app/Models/Payment.php b/app/Models/Payment.php
index b52a1e58..e3b3193f 100644
--- a/app/Models/Payment.php
+++ b/app/Models/Payment.php
@@ -6,6 +6,7 @@ use App\Facades\Hashids;
use App\Jobs\GeneratePaymentPdfJob;
use App\Mail\SendPaymentMail;
use App\Services\SerialNumberFormatter;
+use App\Support\PdfHtmlSanitizer;
use App\Traits\GeneratesPdfTrait;
use App\Traits\HasCustomFieldsTrait;
use Barryvdh\DomPDF\Facade\Pdf as PDF;
@@ -433,7 +434,7 @@ class Payment extends Model implements HasMedia
public function getNotes()
{
- return $this->getFormattedString($this->notes);
+ return PdfHtmlSanitizer::sanitize($this->getFormattedString($this->notes));
}
public function getEmailBody($body)
diff --git a/app/Support/PdfHtmlSanitizer.php b/app/Support/PdfHtmlSanitizer.php
new file mode 100644
index 00000000..95d16558
--- /dev/null
+++ b/app/Support/PdfHtmlSanitizer.php
@@ -0,0 +1,86 @@
+
x';
+ $html = strip_tags($html, $allowedTags);
+
+ $previous = libxml_use_internal_errors(true);
+
+ $doc = new DOMDocument;
+ $wrapped = '
";
+
+ expect(PdfHtmlSanitizer::sanitize($html))->not->toContain('
Bold and italic';
+
+ expect(PdfHtmlSanitizer::sanitize($html))->toContain('')->toContain('');
+});
+
+it('strips style and link attributes that may carry URLs', function () {
+ $html = '