Author: NickSdot (NickSdot)
Committer: Derick Rethans (derickr)
Date: 2026-08-10T14:54:33+01:00

Commit: 
https://github.com/php/web-news/commit/5c140154ffd7a8c42f7d5069af8dde151c4d8cda
Raw diff: 
https://github.com/php/web-news/commit/5c140154ffd7a8c42f7d5069af8dde151c4d8cda.diff

Harden attachment download headers

Changed paths:
  M  getpart.php


Diff:

diff --git a/getpart.php b/getpart.php
index c14b616..5652849 100644
--- a/getpart.php
+++ b/getpart.php
@@ -2,6 +2,14 @@
 
 require 'common.php';
 
+function sanitise_header_value($value)
+{
+    // Values must not contain control bytes; stripping them
+    // prevents rejected or injected response headers.
+
+    return trim(preg_replace('/[\x00-\x1F\x7F]/', '', (string) $value));
+}
+
 if (isset($_GET['group'])) {
     $group = preg_replace('@[^A-Za-z0-9.-]@', '', $_GET['group']);
 } else {
@@ -43,14 +51,37 @@
     $contentdisposition = 'attachment';
 
     if (!empty($attachment['filename'])) {
-        $contentdisposition .= '; filename="' . $attachment['filename'] . '"';
+
+        // Use a simple download name; attachment filenames
+        // are not trusted message content.
+
+        $filename = basename(str_replace('\\', '/', 
sanitise_header_value($attachment['filename'])));
+    } else {
+        $filename = '';
+    }
+
+    if ($filename === '') {
+        $filename = 'attachment';
+    }
+
+    $contentdisposition .= '; filename="' . addcslashes($filename, '\\"') . 
'"';
+
+    $mimetype = sanitise_header_value($attachment['mimetype']);
+
+    // Only send a bare type/subtype MIME value; parameters
+    // and malformed values fall back safely.
+
+    if (!preg_match('#^[a-z0-9!#$&^_.+-]+/[a-z0-9!#$&^_.+-]+$#i', $mimetype)) {
+        $mimetype = 'application/octet-stream';
     }
 
-    header('Content-Type: ' . $attachment['mimetype']);
+    header('X-Content-Type-Options: nosniff');
+    header('Content-Security-Policy: sandbox');
+    header('Content-Type: ' . $mimetype);
     header('Content-Disposition: ' . $contentdisposition);
 
     if (isset($attachment['description'])) {
-        header('Content-Description: ' . $attachment['description']);
+        header('Content-Description: ' . 
sanitise_header_value($attachment['description']));
     }
 
     echo $attachment['data'];

Reply via email to