feat: surface most severe SPF result and hide "via" badge on spoofed mail

This commit is contained in:
Linus Rath
2026-06-01 17:46:57 +02:00
parent 4659b81538
commit 3035fb046f
6 changed files with 173 additions and 14 deletions
+61
View File
@@ -7,6 +7,7 @@ import {
getSecurityStatus,
parseSpamLLM,
extractListHeaders,
isAuthenticationSpoofed,
} from '../email-headers';
describe('parseAuthenticationResults', () => {
@@ -52,6 +53,66 @@ describe('parseAuthenticationResults', () => {
const result = parseAuthenticationResults('spf=softfail smtp.mailfrom=example.com');
expect(result.spf?.result).toBe('softfail');
});
it('surfaces the most severe result when multiple SPF identities exist', () => {
// HELO temperror, MAIL FROM fail — the harder fail must be the headline.
const header =
'mx.example.com; spf=temperror (mx: dns timeout) smtp.helo=mail.spoof.com; spf=fail (mx: not authorized) smtp.mailfrom=victim.com';
const result = parseAuthenticationResults(header);
expect(result.spf?.result).toBe('fail');
expect(result.spf?.domain).toBe('victim.com');
});
it('exposes all SPF results when more than one identity is evaluated', () => {
const header =
'spf=temperror smtp.helo=mail.spoof.com; spf=fail smtp.mailfrom=victim.com';
const result = parseAuthenticationResults(header);
expect(result.spf?.all).toEqual([
{ result: 'temperror', identity: 'helo', domain: 'mail.spoof.com' },
{ result: 'fail', identity: 'mailfrom', domain: 'victim.com' },
]);
});
it('does not set `all` for a single SPF result', () => {
const result = parseAuthenticationResults('spf=pass smtp.mailfrom=example.com');
expect(result.spf?.all).toBeUndefined();
});
it('prefers the MAIL FROM identity when severities tie', () => {
const header = 'spf=pass smtp.helo=mail.example.com; spf=pass smtp.mailfrom=example.com';
const result = parseAuthenticationResults(header);
expect(result.spf?.domain).toBe('example.com');
});
});
describe('isAuthenticationSpoofed', () => {
it('returns false when no auth results are present', () => {
expect(isAuthenticationSpoofed(undefined)).toBe(false);
expect(isAuthenticationSpoofed({})).toBe(false);
});
it('flags a DMARC fail as spoofed', () => {
expect(isAuthenticationSpoofed({ dmarc: { result: 'fail' } })).toBe(true);
});
it('flags a hard SPF fail without a passing DKIM as spoofed', () => {
expect(isAuthenticationSpoofed({ spf: { result: 'fail' } })).toBe(true);
expect(
isAuthenticationSpoofed({ spf: { result: 'fail' }, dkim: { result: 'fail' } })
).toBe(true);
});
it('does not flag an SPF fail rescued by a passing DKIM', () => {
expect(
isAuthenticationSpoofed({ spf: { result: 'fail' }, dkim: { result: 'pass' } })
).toBe(false);
});
it('does not flag passing or ambiguous results', () => {
expect(isAuthenticationSpoofed({ spf: { result: 'pass' }, dmarc: { result: 'pass' } })).toBe(false);
expect(isAuthenticationSpoofed({ spf: { result: 'softfail' } })).toBe(false);
expect(isAuthenticationSpoofed({ spf: { result: 'temperror' } })).toBe(false);
});
});
describe('parseSpamScore', () => {