3

Recently I noticed a recurring pattern in some of the spams I get. The return-path and from headers always have the same structure.

Let me explain with an example:

Return-path: <[email protected]>
From: <[email protected]>
To: <[email protected]>

Basically, I'd like to check if the Return-path user part equals the From user part with the addition of the To ("@" changed to "=") and a dash in front of the To.

I wanted to use some Postfix header_checks and reject the USER=DOMAIN.COM@ pattern but most of the legit newsletters I receive contain that too in their return-path (except there's a much more complex string before, which never matches the From field).

Has anybody created such a rule before and cares to share?

Thanks!

4
  • You need combine two header rules (Return-path and From) with meta rule feature from spamassassin. See wiki.apache.org/spamassassin/WritingRules
    – masegaloeh
    Jul 2, 2015 at 22:07
  • OK but how do you make a reference to the From header in the Return-path rule? In fact, I wouldn't even need to combine 2 rules, I just need one that tells "If Return-path equals From + my email address (with @ turned to =) is injected before the @, then bingo.
    – Capsule
    Jul 5, 2015 at 13:50
  • I have samples of spam from the same sender in my traps. The spam was caught trivially by Spamhaus SBL-CSS (a DNSBL), Spamhaus DBL (a URI DNSBL), and Razor (a hash sharing system). I recommend looking at your config and making sure you've got those installed, as they're all very good at nailing large quantities of spam. SBL and DBL should even be enabled by default. See DNS Blocklists and Installing Razor.
    – Adam Katz
    Jul 7, 2015 at 0:59
  • Yeah, I already have those enabled but it seems like I get some early spams with URLs not yet in RBLs. If I run spamassassin on them again let's say one day after, they score well with RBLs
    – Capsule
    Jul 7, 2015 at 2:08

1 Answer 1

4

SpamAssassin does not let you write code or assign variables ... in its rules. To do what you want, you'd be best suited writing a custom plugin (which would give you full access to perl).

That said, you can technically do what you're asking for within the SpamAssassin rule writing syntax by using header type ALL (which examines all headers at once, kind of like rawbody rules):

header RPATH_EMBEDS_TO_ADDR  ALL =~ /\bReturn-Path:[^\r\n]{0,99}-([\w.])=([\w.-]{1,99}\.[a-z]{2,8})\@(?:[^\r\n]{0,99}[\r\n]{1,9}){1,30}To:[^\r\n]{0,99}<\1@\2>/ism

The above rule is expensive, and would be even more expensive if you were to allow for dashes in the username since it would have to iterate over all possible lengths of ([\w.-]) for the username. This is expensive not just because it requires lots of backtracking, but also because it requires examining very long strings. Also, it is possible that the Return-Path header is after the To header, meaning that you'd need a second rule for a second regex to handle that case.

You'd be far better off writing a custom SpamAssassin plugin for this technique.

However, I think you'll quickly find that all this does is target certain types of bulk mail, many of which are legitimate; the Return-Path header is used as a bounce address and many mailing lists encode the recipient into it in order to measure their deliverability and clean up their lists.

If you really want this sort of thing, I suspect it doesn't actually matter if the exact To address is the one present in the Return-Path header. Here is a dramatically faster rule that should have nearly the same efficacy:

header RPATH_EMBEDS_ADDR  Return-Path =~ /-[\w.]{1,99}=[\w.-]{1,99}\.[a-z]{2,8}\@/i

Another big note is that whenever a message is redirected (e.g. an email forwarding service), the Return-Path header is rewritten. This may limit the spam detection utility of that rule.

6
  • Thanks Adam, actually I can implement such a rule with a simple postfix header_checks but what make these spams different from a legitimate bulk email system is the From is also embedded in the Return-path, which would never be the case with an ham mail from, let's say, a newsletter. I guess writing an even more complex rule to check the From header too would even be more expensive... But I'll still adapt your first rule and test it against the From header.
    – Capsule
    Jul 7, 2015 at 0:46
  • Um, I tried that: header RPATH_FAKE ALL =~ /\bReturn-Path: <([^\r\n]{0,99})-([\w.]+)=([\w.-]{1,99}\.[a-z]{2,8})\@([^>]+)>/ism and it works but this one never matches, despite the fact I tested in a regexp tester on my test mail: header RPATH_EMBEDS_FROM_ADDR ALL =~ /\bReturn-Path: <([^\r\n]{0,99})-([\w.]+)=([\w.-]{1,99}\.[a-z]{2,8})\@([^>]+)>(?:[^\r\n]{0,99}[\r\n]{1,9}){1,30}From:[^\r\n]{0,99}<\1@\4/ism. Is the "From" accessible in the headers or is it considered as part of the body since it's not in the SMTP enveloppe?
    – Capsule
    Jul 7, 2015 at 2:43
  • From headers are headers, but you're not guaranteed for them to be before the Return-Path header. Try writing a second rule that expects the opposite order. It's also possible that they're more than 30 lines removed (I used 30 to be conservative on system resources, as this is an expensive rule).
    – Adam Katz
    Jul 7, 2015 at 16:37
  • 1
    No, SA parses in the given order. There must be a bug in the regex. Try to simplify it and then work out the issue.
    – Adam Katz
    Jul 8, 2015 at 2:29
  • 2
    Yep, I simplified it to Return-Path: <([^\r\n]{0,99})-([\w.]+)=([\w.-]{1,99}\.[a-z]{2,8})\@([^>]+)>.+From:[^<]+<\1@\4> and it works like a charm now, thanks again for your help!
    – Capsule
    Jul 8, 2015 at 3:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .