Hi everyone,

I have noticed that some recent versions of Delta Chat started to
spoof more than just the subject header when sending OpenPGP-encrypted
messages. From what I saw, they mask at least the following three headers:

1. Date -- the outer header contains a fictitious date while the protected
header contains the real date.

2. To -- the outer header is set to `"hidden-recipients": ;` while the
protected header contains the full display name and email address of
the recipient.

3. From -- the outer header contains only the email address while the
protected header contains both the email address and the display name
of the sender.

To my eyes, these ways of masking protected headers look like they should
be valid. I have not yet gotten around to looking any deeper into how
protected headers are implemented in notmuch. However, I attach a patch
with additional tests for the three cases described above as a form of
executable bug report.

I would not be surprised if future versions of Delta Chat started to
spoof even more unprotected headers, like References, In-Reply-To,
or even Message-ID. If anyone fixes the issues described above, they
might want to check if they can make the implementation generic enough
to cover such cases as well.


Best

Frank
>From 422f184a93f677242c01837ee4666ba6605b70b4 Mon Sep 17 00:00:00 2001
From: Frank Seifferth <[email protected]>
Date: Thu, 18 Dec 2025 17:41:07 +0100
Subject: [PATCH] Add more test cases for protected headers

Some versions of Delta Chat recently started to send spoofed headers
that are overridden by the protected headers of OpenPGP-encrypted
messages. Currently, notmuch uses the spoofed headers rather than the
real ones, with the subject being the sole exception. This commit adds
test cases for the following three headers: Date, To, and From. The
example messages were modelled after what Delta Chat produces, which
(in my opinion) look like it should be valid.
---
 test/T356-protected-headers.sh                | 70 ++++++++++++++++++-
 .../protected-headers/spoofed-date.eml        | 28 ++++++++
 .../protected-headers/spoofed-recipient.eml   | 28 ++++++++
 .../protected-headers/spoofed-sender.eml      | 29 ++++++++
 4 files changed, 154 insertions(+), 1 deletion(-)
 create mode 100644 test/corpora/protected-headers/spoofed-date.eml
 create mode 100644 test/corpora/protected-headers/spoofed-recipient.eml
 create mode 100644 test/corpora/protected-headers/spoofed-sender.eml

diff --git a/test/T356-protected-headers.sh b/test/T356-protected-headers.sh
index 9f640331..712c099d 100755
--- a/test/T356-protected-headers.sh
+++ b/test/T356-protected-headers.sh
@@ -24,6 +24,36 @@ test_json_nodes <<<"$output" \
                 'crypto:[0][0][0]["crypto"]={"decrypted": {"status": "full", 
"header-mask": {"Subject": "Subject Unavailable"}}}' \
                 'subject:[0][0][0]["headers"]["Subject"]="This is a protected 
header"'
 
+test_begin_subtest "verify spoofed date is shown without decryption"
+output=$(notmuch show --format=json id:[email protected])
+test_json_nodes <<<"$output" \
+                'subject:[0][0][0]["headers"]["Date"]="Sat, 01 Jan 2000 
12:00:00 +0000"'
+
+test_begin_subtest "verify real date is shown with decryption"
+output=$(notmuch show --decrypt=true --format=json 
id:[email protected])
+test_json_nodes <<<"$output" \
+                'subject:[0][0][0]["headers"]["Date"]="Wed, 16 Dec 2015 
17:19:18 +0100"'
+
+test_begin_subtest "verify spoofed recipient is shown without decryption"
+output=$(notmuch show --format=json 
id:[email protected])
+test_json_nodes <<<"$output" \
+                'subject:[0][0][0]["headers"]["To"]="undisclosed-recipients: 
;"'
+
+test_begin_subtest "verify real recipient is shown with decryption"
+output=$(notmuch show --decrypt=true --format=json 
id:[email protected])
+test_json_nodes <<<"$output" \
+                'subject:[0][0][0]["headers"]["To"]="Notmuch Test Suite 
<[email protected]>"'
+
+test_begin_subtest "verify spoofed sender is shown without decryption"
+output=$(notmuch show --format=json 
id:[email protected])
+test_json_nodes <<<"$output" \
+                
'subject:[0][0][0]["headers"]["From"]="[email protected]"'
+
+test_begin_subtest "verify real sender is shown with decryption"
+output=$(notmuch show --decrypt=true --format=json 
id:[email protected])
+test_json_nodes <<<"$output" \
+                'subject:[0][0][0]["headers"]["From"]="Notmuch Test Suite 
<[email protected]>"'
+
 test_begin_subtest "when no external header is present, show masked subject as 
null"
 output=$(notmuch show --decrypt=true --format=json 
id:[email protected])
 test_json_nodes <<<"$output" \
@@ -87,7 +117,7 @@ test_begin_subtest "protected subject is not indexed by 
default"
 output=$(notmuch search --output=messages 'subject:"This is a protected 
header"')
 test_expect_equal "$output" ''
 
-test_begin_subtest "reindex message with protected header"
+test_begin_subtest "reindex message with protected subject"
 test_expect_success 'notmuch reindex --decrypt=true 
id:[email protected]'
 
 test_begin_subtest "protected subject is indexed when cleartext is indexed"
@@ -105,6 +135,41 @@ test_json_nodes <<<"$output" \
                 'subject:["original"]["headers"]["Subject"]="This is a 
protected header"' \
                 'reply-subject:["reply-headers"]["Subject"]="Re: Subject 
Unavailable"'
 
+test_begin_subtest "spoofed date is used when cleartext is not indexed"
+output=$(notmuch search --output=messages 
'id:[email protected] and date:2000-01-01')
+test_expect_equal "$output" 'id:[email protected]'
+
+test_begin_subtest "real date is masked when cleartext is not indexed"
+output=$(notmuch search --output=messages 
'id:[email protected] and date:2015-12-16')
+test_expect_equal "$output" ''
+
+test_begin_subtest "real recipient is masked when cleartext is not indexed"
+output=$(notmuch search --output=messages 
'id:[email protected] and to:"Notmuch Test Suite"')
+test_expect_equal "$output" ''
+
+test_begin_subtest "real sender is masked when cleartext is not indexed"
+output=$(notmuch search --output=messages 
'id:[email protected] and from:"Notmuch Test Suite"')
+test_expect_equal "$output" ''
+
+test_begin_subtest "reindex messages with spoofed headers"
+test_expect_success 'notmuch reindex --decrypt=true 
id:[email protected] or 
id:[email protected] or 
id:[email protected]'
+
+test_begin_subtest "spoofed date is ignored when cleartext is indexed"
+output=$(notmuch search --output=messages 
'id:[email protected] and date:2000-01-01')
+test_expect_equal "$output" ''
+
+test_begin_subtest "real date is used when cleartext is indexed"
+output=$(notmuch search --output=messages 
'id:[email protected] and date:2015-12-16')
+test_expect_equal "$output" 'id:[email protected]'
+
+test_begin_subtest "real recipient is used when cleartext is indexed"
+output=$(notmuch search --output=messages 
'id:[email protected] and to:"Notmuch Test Suite"')
+test_expect_equal "$output" 'id:[email protected]'
+
+test_begin_subtest "real sender is used when cleartext is indexed"
+output=$(notmuch search --output=messages 
'id:[email protected] and from:"Notmuch Test Suite"')
+test_expect_equal "$output" 'id:[email protected]'
+
 test_begin_subtest "verify correct protected header when submessage exists"
 output=$(notmuch show --decrypt=true --format=json 
id:encrypted-message-with-forwarded-attachm...@crypto.notmuchmail.org)
 test_json_nodes <<<"$output" \
@@ -134,6 +199,9 @@ test_expect_equal "$output" 
'id:[email protected]
 id:[email protected]
 id:[email protected]
 id:[email protected]
+id:[email protected]
+id:[email protected]
+id:[email protected]
 id:[email protected]'
 
 test_begin_subtest "when rendering protected headers, avoid rendering 
legacy-display part"
diff --git a/test/corpora/protected-headers/spoofed-date.eml 
b/test/corpora/protected-headers/spoofed-date.eml
new file mode 100644
index 00000000..b3e5bb5a
--- /dev/null
+++ b/test/corpora/protected-headers/spoofed-date.eml
@@ -0,0 +1,28 @@
+From: [email protected]
+To: [email protected]
+Subject: Subject Unavailable
+Date: Sat, 01 Jan 2000 12:00:00 +0000
+Message-ID: <[email protected]>
+MIME-Version: 1.0
+Content-Type: multipart/encrypted; boundary="=-=-=";
+       protocol="application/pgp-encrypted"
+
+--=-=-=
+Content-Type: application/pgp-encrypted
+
+Version: 1
+
+--=-=-=
+Content-Type: application/octet-stream
+
+-----BEGIN PGP MESSAGE-----
+
+hF4DHXHP849rSK8SAQdALxucRFN71JbLt2GfNFt2/YrBvrshI8tGn7IzlxdE+1sw
++Pu7X4CisgRLrNP5NrkCeXd3qtdBL1oCp7Q8CE1MzagVZb3tGE9tdGjHqOHSUIcg
+0rsBt1bR4Vdunh5kgzfYVV3JqdtgQlZXF/AUrkB8LatxZ6nA9V0t/DC63dh6gUsJ
+EnbjAZq9z/k5Tjgi52+gXarl62cJQp7YSFLU2GgHCOjUMLugNPpr9J3YRtN9u7Np
+fLenbcQynXRWY0MNp+vRzWoVPi2g4A4J+L+LRKmChX/Ni6gqEU1ksXnhkX9+dZXs
+J4T6ixs1IyJxfyQCmA1bbi9exkORLdE7ZyxgYC3kSWUzivjwz68PdHUqitE+
+=XRi1
+-----END PGP MESSAGE-----
+--=-=-=--
diff --git a/test/corpora/protected-headers/spoofed-recipient.eml 
b/test/corpora/protected-headers/spoofed-recipient.eml
new file mode 100644
index 00000000..f9d47c57
--- /dev/null
+++ b/test/corpora/protected-headers/spoofed-recipient.eml
@@ -0,0 +1,28 @@
+From: [email protected]
+To: undisclosed-recipients: ;
+Subject: Subject Unavailable
+Date: Sat, 01 Jan 2000 12:00:00 +0000
+Message-ID: <[email protected]>
+MIME-Version: 1.0
+Content-Type: multipart/encrypted; boundary="=-=-=";
+       protocol="application/pgp-encrypted"
+
+--=-=-=
+Content-Type: application/pgp-encrypted
+
+Version: 1
+
+--=-=-=
+Content-Type: application/octet-stream
+
+-----BEGIN PGP MESSAGE-----
+
+hF4DHXHP849rSK8SAQdA15+QCv0bg+6LKzXtfj4pPyrOwkzIhCPgLd3aeMnv3WMw
+KcOKlfdgmEtI92AZFCpDErTceKpcTzVz2m9vaR3ZLIntf4Db8P/KPVTLeJla9Wy0
+0r4BEuH4GwCq/rM889/funOJBIm/amlNEAbOicBR9QJzqAkvQ1i9SsrAuA/MFA7S
+/sH3RrNT0x00UHh6i2Ho5B+GgJFBpYyijZb6dGXcMt8jMrhM/D3hQvu2VLL72h6z
+cHjqEIxYrgCXcmMKGzXFpv0WLYXVbe/BU6tcTUqzcQtRXQAImv3WQXmTx0ZXHxe0
+y4DkxxrdLMS4ogKp6iPCtqIjGV6wrBRVlcFGTh+1gmhYiAviKixx03XfRCw7YZTj
+=vcs2
+-----END PGP MESSAGE-----
+--=-=-=--
diff --git a/test/corpora/protected-headers/spoofed-sender.eml 
b/test/corpora/protected-headers/spoofed-sender.eml
new file mode 100644
index 00000000..ed1d2595
--- /dev/null
+++ b/test/corpora/protected-headers/spoofed-sender.eml
@@ -0,0 +1,29 @@
+From: [email protected]
+To: undisclosed-recipients: ;
+Subject: Subject Unavailable
+Date: Sat, 01 Jan 2000 12:00:00 +0000
+Message-ID: <[email protected]>
+MIME-Version: 1.0
+Content-Type: multipart/encrypted; boundary="=-=-=";
+       protocol="application/pgp-encrypted"
+
+--=-=-=
+Content-Type: application/pgp-encrypted
+
+Version: 1
+
+--=-=-=
+Content-Type: application/octet-stream
+
+-----BEGIN PGP MESSAGE-----
+
+hF4DHXHP849rSK8SAQdA21XV8GyULURScZxf9wBJs5j+5z3OvXJYTKVVURbUVVAw
+sJL+xsbZY24IkCDqX6YEY/iCZgnwJMXWkgtkiapQnLhGj9NOiBa3++iuzZVJ9/26
+0sAJAZCrLPqeCBtB3WveXXrY974CFYE6q1hp27bye5hY0mNDxudEEUpfMA0t6dFV
+BhzYCkdIbZSwYglr8JM4vaHKpeMT3RgiANm9IxG4vKieLS8rFzJ54Q6EPIpROLkd
+WDpoCtfXTHj9vvr+Vx2eLdURCsdcA4Kjj4Xdujz04p5yq3UcCx/5Ml2vwKZJTVzO
+41mTVzkx52Y4iDgOupjdvAy0UIkowj/gXzhcVOL/0VRG4MMelQ3raiuNiOP19es+
+id0ZmRgEoEB0TsrY
+=DZBa
+-----END PGP MESSAGE-----
+--=-=-=--
-- 
2.39.5

_______________________________________________
notmuch mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to