[PHP-WEBMASTER] [web-news] master: Harden attachment download headers

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

Commit: Harden attachment download headers · php/web-news@5c14015 · GitHub
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'];