Skip to content

Commit 8057743

Browse files
committed
test(smtp): add custom header security coverage ⬜
- Add acceptance test for safe custom headers - Add rejection tests for invalid names and CRLF header injection - Add rejection tests for reserved header overrides including mixed-case names
1 parent 37da453 commit 8057743

1 file changed

Lines changed: 117 additions & 0 deletions

File tree

tests/smtp/Message.test.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@ const smtpMessage = new SMTP.SmtpMessage({
77
secure: false
88
})
99

10+
Deno.test('SmtpMessage accepts safe custom headers', () => {
11+
const formattedMessage = smtpMessage.formatMessage({
12+
from: 'sender@example.com',
13+
to: 'receiver@example.com',
14+
subject: 'Header',
15+
text: 'body',
16+
headers: {
17+
'X-Security-Test': 'safe-value',
18+
'X-Trace_Id': 'trace-123'
19+
}
20+
})
21+
assertMatch(formattedMessage, /X-Security-Test: safe-value/)
22+
assertMatch(formattedMessage, /X-Trace_Id: trace-123/)
23+
})
24+
1025
Deno.test('SmtpMessage formats multipart html and text', () => {
1126
const formattedMessage = smtpMessage.formatMessage({
1227
from: 'sender@example.com',
@@ -32,6 +47,108 @@ Deno.test('SmtpMessage formats plain text message', () => {
3247
assertMatch(formattedMessage, /hello/)
3348
})
3449

50+
Deno.test('SmtpMessage rejects custom header names with invalid characters', () => {
51+
assertThrows(
52+
() =>
53+
smtpMessage.formatMessage({
54+
from: 'sender@example.com',
55+
to: 'receiver@example.com',
56+
subject: 'Header',
57+
text: 'body',
58+
headers: {
59+
'Bad Header': 'value'
60+
}
61+
}),
62+
Error,
63+
'contains invalid characters'
64+
)
65+
})
66+
67+
Deno.test('SmtpMessage rejects custom header names with line breaks', () => {
68+
assertThrows(
69+
() =>
70+
smtpMessage.formatMessage({
71+
from: 'sender@example.com',
72+
to: 'receiver@example.com',
73+
subject: 'Header',
74+
text: 'body',
75+
headers: {
76+
'X-Test\r\nBcc': 'value'
77+
}
78+
}),
79+
Error,
80+
'contains invalid characters'
81+
)
82+
})
83+
84+
Deno.test('SmtpMessage rejects custom header values with line breaks', () => {
85+
assertThrows(
86+
() =>
87+
smtpMessage.formatMessage({
88+
from: 'sender@example.com',
89+
to: 'receiver@example.com',
90+
subject: 'Header',
91+
text: 'body',
92+
headers: {
93+
'X-Test': 'ok\r\nBcc: victim@example.com'
94+
}
95+
}),
96+
Error,
97+
'value contains line break characters'
98+
)
99+
})
100+
101+
Deno.test('SmtpMessage rejects empty custom header names', () => {
102+
assertThrows(
103+
() =>
104+
smtpMessage.formatMessage({
105+
from: 'sender@example.com',
106+
to: 'receiver@example.com',
107+
subject: 'Header',
108+
text: 'body',
109+
headers: {
110+
' ': 'value'
111+
}
112+
}),
113+
Error,
114+
'name cannot be empty'
115+
)
116+
})
117+
118+
Deno.test('SmtpMessage rejects reserved custom header names', () => {
119+
assertThrows(
120+
() =>
121+
smtpMessage.formatMessage({
122+
from: 'sender@example.com',
123+
to: 'receiver@example.com',
124+
subject: 'Header',
125+
text: 'body',
126+
headers: {
127+
Subject: 'Injected subject'
128+
}
129+
}),
130+
Error,
131+
'reserved and cannot be overridden'
132+
)
133+
})
134+
135+
Deno.test('SmtpMessage rejects reserved headers case-insensitively', () => {
136+
assertThrows(
137+
() =>
138+
smtpMessage.formatMessage({
139+
from: 'sender@example.com',
140+
to: 'receiver@example.com',
141+
subject: 'Header',
142+
text: 'body',
143+
headers: {
144+
'mImE-vErSiOn': '2.0'
145+
}
146+
}),
147+
Error,
148+
'reserved and cannot be overridden'
149+
)
150+
})
151+
35152
Deno.test('SmtpMessage throws when embedded cid is invalid', () => {
36153
assertThrows(
37154
() =>

0 commit comments

Comments
 (0)