home *** CD-ROM | disk | FTP | other *** search
/ ftp.f-secure.com / 2014.06.ftp.f-secure.com.tar / ftp.f-secure.com / support / hotfix / fsis / IS-SpamControl.fsfix / iufssc / rules / 20_head_tests.cf < prev    next >
Text File  |  2006-11-29  |  33KB  |  685 lines

  1. # SpamAssassin rules file: header tests
  2. #
  3. # Please don't modify this file as your changes will be overwritten with
  4. # the next update. Use @@LOCAL_RULES_DIR@@/local.cf instead.
  5. # See 'perldoc Mail::SpamAssassin::Conf' for details.
  6. #
  7. # <@LICENSE>
  8. # Copyright 2004 Apache Software Foundation
  9. # Licensed under the Apache License, Version 2.0 (the "License");
  10. # you may not use this file except in compliance with the License.
  11. # You may obtain a copy of the License at
  12. #     http://www.apache.org/licenses/LICENSE-2.0
  13. # Unless required by applicable law or agreed to in writing, software
  14. # distributed under the License is distributed on an "AS IS" BASIS,
  15. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. # See the License for the specific language governing permissions and
  17. # limitations under the License.
  18. # </@LICENSE>
  19. #
  20. ###########################################################################
  21.  
  22. #require_version @@VERSION@@
  23.  
  24. header HEAD_LONG        eval:check_msg_parse_flags('truncated_header')
  25. describe HEAD_LONG        Message headers are very long
  26.  
  27. # partial messages; currently-theoretical attack
  28. # unsurprisingly this hits 0/0 right now.
  29. header FRAGMENTED_MESSAGE    Content-Type =~ /\bmessage\/partial/i
  30. describe FRAGMENTED_MESSAGE    Partial message
  31.  
  32. header MISSING_HB_SEP        eval:check_msg_parse_flags('missing_head_body_separator')
  33. describe MISSING_HB_SEP        Missing blank line between message header and body
  34.  
  35. header UNPARSEABLE_RELAY        eval:check_relays_unparseable()
  36. tflags UNPARSEABLE_RELAY        userconf
  37. describe UNPARSEABLE_RELAY      Informational: message has unparseable relay lines
  38.  
  39. ###########################################################################
  40.  
  41. header NO_REAL_NAME        From =~ /^["\s]*\<?\S+\@\S+\>?\s*$/
  42. describe NO_REAL_NAME        From: does not include a real name
  43.  
  44. header FROM_BLANK_NAME        From =~ /(?:\s|^)"" <\S+>/i
  45. describe FROM_BLANK_NAME    From: contains empty name
  46.  
  47. ###########################################################################
  48. # numeric address rules, these are written to avoid overlap with each other
  49.  
  50. header FROM_ENDS_IN_NUMS    From:addr =~ /\D\d{8,}\@/i
  51. describe FROM_ENDS_IN_NUMS    From: ends in many numbers
  52.  
  53. header FROM_STARTS_WITH_NUMS    From:addr =~ /^\d{6,}\S+\@/i
  54. describe FROM_STARTS_WITH_NUMS    From: starts with many numbers
  55.  
  56. # note: anchored for speed
  57. header FROM_HAS_MIXED_NUMS    From:addr =~ /^[a-z]+\d+[a-z]+\d+[a-z]+\w*\@/i
  58. describe FROM_HAS_MIXED_NUMS    From: contains numbers mixed in with letters
  59.  
  60. header FROM_HAS_ULINE_NUMS    From =~ /_\S?(?:[a-z]+\w*?\d+|\d+\w*?[a-z]+)\w*\@/i
  61. describe FROM_HAS_ULINE_NUMS    From: contains an underline and numbers/letters
  62.  
  63. # don't match US/Canada phone numbers: 10 digits optionally preceded by a "1"
  64. header FROM_ALL_NUMS        From:addr =~ /^(?:\d{1,9}|[02-9]\d{10}|\d{12,})@/
  65. describe FROM_ALL_NUMS        From numeric address (except US/Canada phones)
  66.  
  67. # faked addresses tend to come from big public sites, but avoid overlap
  68. header __ADDR_NUMS_AT_BIGSITE    ALL =~ /^(?:To|From|Cc|Reply-To):\s{0,20}<?\S{0,20}\d{5,}\S{0,20}\@(?:bigfoot|email|excite|hotmail|juno|msn|yahoo)\.(?:com|net|org)/mi
  69. meta ADDR_NUMS_AT_BIGSITE    __ADDR_NUMS_AT_BIGSITE && !FROM_ENDS_IN_NUMS && !FROM_STARTS_WITH_NUMS && !FROM_HAS_MIXED_NUMS && !FROM_ALL_NUMS
  70. describe ADDR_NUMS_AT_BIGSITE    Has an address with lots of numbers at a big ISP
  71.  
  72. ###########################################################################
  73.  
  74. header FROM_OFFERS        From:addr =~ /\@\S*offers(?![eo]n\b)/i
  75. describe FROM_OFFERS        From address is "at something-offers"
  76.  
  77. header FROM_NO_USER        From =~ /(?:^\@|<\@| \@[^\)<]*$|<>)/ [if-unset: unset@unset.unset]
  78. describe FROM_NO_USER        From: has no local-part before @ sign
  79.  
  80. header TO_NO_USER        To =~ /(?:^\@|<\@| \@[^\)<]*$|<>)/ [if-unset: unset@unset.unset]
  81. describe TO_NO_USER        To: has no local-part before @ sign
  82.  
  83. header TO_EMPTY            To =~ /^\s*$/ [if-unset: UNSET]
  84. describe TO_EMPTY        To: is empty
  85.  
  86. header REPLY_TO_EMPTY        Reply-To =~ /^\s*$/ [if-unset: UNSET]
  87. describe REPLY_TO_EMPTY        Reply-To: is empty
  88.  
  89. header TO_ADDRESS_EQ_REAL    To =~ /^\s*"([^"@]+\@[^"@]+)"\s+<\1>\s*$/i
  90. describe TO_ADDRESS_EQ_REAL    To: repeats address as real name
  91.  
  92. # NOTE: this is what 100% valid undisclosed-recipients mails look like.
  93. # If this gets a high score, that's a bug!
  94. header UNDISC_RECIPS        To =~ /^undisclosed-recipients?:\s*;$/
  95. describe UNDISC_RECIPS        Valid-looking To "undisclosed-recipients"
  96.  
  97. # also 100% valid
  98. header FAKED_UNDISC_RECIPS    To =~ /undisclosed[_ ]*recipient(?:s[^:]|[^s])/i
  99. describe FAKED_UNDISC_RECIPS    Faked To "Undisclosed-Recipients"
  100.  
  101. header PLING_QUERY        Subject =~ /\?.*!|!.*\?/
  102. describe PLING_QUERY        Subject has exclamation mark and question mark
  103.  
  104. header SUBJ_HAS_UNIQ_ID        eval:check_for_unique_subject_id()
  105. describe SUBJ_HAS_UNIQ_ID    Subject contains a unique ID
  106.  
  107. header SUBJ_HAS_SPACES        Subject =~ /(?:\s{6}|\t\s|\s\t)\S/
  108. describe SUBJ_HAS_SPACES    Subject contains lots of white space
  109.  
  110. header SUBJ_ALL_CAPS        eval:subject_is_all_caps()
  111. describe SUBJ_ALL_CAPS        Subject is all capitals
  112.  
  113. header MSGID_SPAM_99X9XX99    MESSAGEID =~ /^<\d\d\d\d\d\d[a-z]\d[a-z][a-z]\d\d\$[a-z][a-z][a-z]\d\d\d\d\d\$\d\d\d\d\d\d\d\d\@/
  114. describe MSGID_SPAM_99X9XX99    Spam tool Message-Id: (99x9xx99 variant)
  115.  
  116. header MSGID_SPAM_ALPHA_NUM    MESSAGEID =~ /<[A-Z]{7}-000[0-9]{10}\@[a-z]*>/
  117. describe MSGID_SPAM_ALPHA_NUM    Spam tool Message-Id: (alpha-numeric variant)
  118.  
  119. header MSGID_SPAM_CAPS        Message-ID =~ /^\s*<?[A-Z]+\@(?!(?:mailcity|whowhere)\.com)/
  120. describe MSGID_SPAM_CAPS    Spam tool Message-Id: (caps variant)
  121.  
  122. header MSGID_SPAM_LETTERS    Message-Id =~ /<[a-z]{5,}\@(\S+\.)+\S+>/
  123. describe MSGID_SPAM_LETTERS    Spam tool Message-Id: (letters variant)
  124.  
  125. header MSGID_SPAM_ZEROES    MESSAGEID =~ /<0000[0-9a-f]{8}\$0000[0-9a-f]{4}\$0000[0-9a-f]{4}\@/
  126. describe MSGID_SPAM_ZEROES    Spam tool Message-Id: (12-zeroes variant)
  127.  
  128. header MSGID_NO_HOST            MESSAGEID =~ /\@>(?:$|\s)/m
  129. describe MSGID_NO_HOST         Message-Id has no hostname
  130.  
  131. header MSGID_OUTLOOK_INVALID    eval:check_outlook_message_id()
  132. describe MSGID_OUTLOOK_INVALID    Message-Id is fake (in Outlook Express format)
  133.  
  134. # catches a few spams missed by MSGID_OUTLOOK_INVALID
  135. header __HAS_OUTLOOK_IN_MAILER    X-Mailer =~ /\bMSCRM\b|Microsoft (?:CDO|Outlook|Office Outlook)\b/
  136. meta MSGID_DOLLARS        (__OUTLOOK_DOLLARS_MSGID && !__HAS_OUTLOOK_IN_MAILER && !__UNUSABLE_MSGID)
  137. describe MSGID_DOLLARS        Message-Id has pattern used in spam
  138.  
  139. # negative lookahead exempts this MUA from circa 1997-2000 
  140. # X-Mailer: Microsoft Outlook Express 4.71.1712.3
  141. # Message-ID: <01bd45da$2649cdc0$LocalHost@andrew>
  142. header __MSGID_DOLLARS_OK    MESSAGEID =~ /<[0-9a-f]{4,}\$[0-9a-f]{4,}\$[0-9a-f]{4,}\@\S+>/m
  143. header __MSGID_DOLLARS_MAYBE    MESSAGEID =~ /<\w{4,}\$\w{4,}\$(?!localhost)\w{4,}\@\S+>/mi
  144. meta MSGID_DOLLARS_RANDOM    __MSGID_DOLLARS_MAYBE && !__MSGID_DOLLARS_OK
  145.  
  146. # bit of a ratware rule, but catches a bit more than just the one ratware
  147. header __MSGID_RANDY        Message-ID =~ /<[a-z\d][a-z\d\$-]{10,29}[a-z\d]\@[a-z\d][a-z\d.]{3,12}[a-z\d]>/
  148. # heuristic to eliminate most good Message-ID formats
  149. header __MSGID_OK_HEX        Message-ID =~ /\b[a-f\d]{8}\b/
  150. header __MSGID_OK_DIGITS    Message-ID =~ /\d{10}/
  151. header __MSGID_OK_HOST        Message-ID =~ /\@(?:\D{2,}|(?:\d{1,3}\.){3}\d{1,3})>/
  152. meta MSGID_RANDY    (__MSGID_RANDY && !(__MSGID_OK_HEX || __MSGID_OK_DIGITS || __MSGID_OK_HOST))
  153. describe MSGID_RANDY        Message-Id has pattern used in spam
  154.  
  155. # bug 3395
  156. header MSGID_YAHOO_CAPS        Message-ID =~ /<[A-Z]+\@yahoo.com>/
  157. describe MSGID_YAHOO_CAPS    Message-ID has ALLCAPS@yahoo.com
  158.  
  159. ###########################################################################
  160.  
  161. header   __AT_AOL_MSGID        MESSAGEID =~ /\@aol\.com\b/i
  162. header   __FROM_AOL_COM        From =~ /\@aol\.com\b/i
  163. meta     FORGED_MSGID_AOL    (__AT_AOL_MSGID && !__FROM_AOL_COM)
  164. describe FORGED_MSGID_AOL    Message-ID is forged, (aol.com)
  165.  
  166. header   __AT_EXCITE_MSGID    MESSAGEID =~ /\@excite\.com\b/i
  167. header   __MY_RCVD_EXCITE    Received =~ /\.excite\.com\b/i
  168. meta     FORGED_MSGID_EXCITE    (__AT_EXCITE_MSGID && !__MY_RCVD_EXCITE)
  169. describe FORGED_MSGID_EXCITE    Message-ID is forged, (excite.com)
  170.  
  171. header   __AT_HOTMAIL_MSGID    MESSAGEID =~ /\@hotmail\.com\b/i
  172. header   __FROM_HOTMAIL_COM    From =~ /\@hotmail\.com\b/i
  173. meta     FORGED_MSGID_HOTMAIL    (__AT_HOTMAIL_MSGID && (!__FROM_HOTMAIL_COM && !__FROM_MSN_COM && !__FROM_YAHOO_COM))
  174. describe FORGED_MSGID_HOTMAIL    Message-ID is forged, (hotmail.com)
  175.  
  176. header   __AT_MSN_MSGID        MESSAGEID =~ /\@msn\.com\b/i
  177. header   __FROM_MSN_COM        From =~ /\@msn\.com\b/i
  178. meta     FORGED_MSGID_MSN    (__AT_MSN_MSGID && (!__FROM_MSN_COM && !__FROM_HOTMAIL_COM && !__FROM_YAHOO_COM))
  179. describe FORGED_MSGID_MSN    Message-ID is forged, (msn.com)
  180.  
  181. header   __AT_YAHOO_MSGID    MESSAGEID =~ /\@yahoo\.com\b/i
  182. header   __FROM_YAHOO_COM    From =~ /\@yahoo\.com\b/i
  183. meta     FORGED_MSGID_YAHOO    (__AT_YAHOO_MSGID && !__FROM_YAHOO_COM)
  184. describe FORGED_MSGID_YAHOO    Message-ID is forged, (yahoo.com)
  185.  
  186. ###########################################################################
  187.  
  188. header __MSGID_BEFORE_RECEIVED    ALL =~ /\nMessage-Id:.*\nReceived:/si
  189. header __MSGID_BEFORE_OKAY    Message-Id =~ /\@[a-z0-9.-]+\.(?:yahoo|wanadoo)(?:\.[a-z]{2,3}){1,2}>/
  190. meta MSGID_FROM_MTA_HEADER    (__MSGID_BEFORE_RECEIVED && !__MSGID_BEFORE_OKAY)
  191. describe MSGID_FROM_MTA_HEADER    Message-Id was added by a relay
  192.  
  193. header MSGID_FROM_MTA_ID    eval:message_id_from_mta()
  194. describe MSGID_FROM_MTA_ID    Message-Id for external message added locally
  195.  
  196. header MSGID_FROM_MTA_HOTMAIL    Message-Id =~ /<MC\d{1,2}-F{1,2}\w{21,22}\@\S*hotmail\.com>/
  197. describe MSGID_FROM_MTA_HOTMAIL    Message-Id was added by a hotmail.com relay
  198.  
  199. header MSGID_LONG        MESSAGEID =~ /<.{160,}>|<.{140,}\@|\@.{55,}>/m
  200. describe MSGID_LONG        Message-ID is unusually long
  201.  
  202. header MSGID_SHORT        MESSAGEID =~ /^.{1,15}$|<.{0,4}\@/m
  203. describe MSGID_SHORT        Message-ID is unusually short
  204.  
  205. header MSGID_MULTIPLE_AT    MESSAGEID =~ /<[^>]*\@[^>]*\@/
  206. describe MSGID_MULTIPLE_AT    Message-ID contains multiple '@' characters
  207.  
  208. ###########################################################################
  209.  
  210. header DATE_SPAMWARE_Y2K    Date =~ /^[A-Z][a-z]{2}, \d\d [A-Z][a-z]{2} [0-6]\d \d\d:\d\d:\d\d [A-Z]{3}$/
  211. describe DATE_SPAMWARE_Y2K    Date header uses unusual Y2K formatting
  212.  
  213. header INVALID_DATE        Date !~ /^\s*(?:(?i:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s+)?[0-3\s]?[0-9]\s+(?i:Jan|Feb|Ma[ry]|Apr|Ju[nl]|Aug|Sep|Oct|Nov|Dec)\s+(?:[12][901])?[0-9]{2}\s+[0-2]?[0-9](?:\:[0-5][0-9]){1,2}\s+(?:[AP]M\s+)?(?:[+-][0-9]{4}|UT|[A-Z]{2,3}T)(?:\s+\(.*\))?\s*$/ [if-unset: Wed, 31 Jul 2002 16:41:57 +0200]
  214. describe INVALID_DATE        Invalid Date: header (not RFC 2822)
  215.  
  216. # allow +1300, NZ timezone
  217. header INVALID_DATE_TZ_ABSURD    Date =~ /[-+](?:1[4-9]\d\d|[2-9]\d\d\d)$/
  218. describe INVALID_DATE_TZ_ABSURD    Invalid Date: header (timezone does not exist)
  219.  
  220. header INVALID_TZ_CST        ALL =~ /[+-]\d\d[30]0(?<!-0600|-0500|\+0800|\+0930|\+1030)\s+(?:\bCST\b|\(CST\))/
  221. describe INVALID_TZ_CST        Invalid date in header (wrong CST timezone)
  222.  
  223. header INVALID_TZ_EST        ALL =~ /[+-]\d\d[30]0(?<!-0500|-0300|\+1000|\+1100)\s+(?:\bEST\b|\(EST\))/
  224. describe INVALID_TZ_EST        Invalid date in header (wrong EST timezone)
  225.  
  226. header INVALID_TZ_GMT        ALL =~ /[+-]\d\d[30]0(?<![+-]0000)\s+(?:\b(?:GMT|UTC)\b(?![\w+-])|\((?:GMT|UTC)\))/
  227. describe INVALID_TZ_GMT        Invalid date in header (wrong GMT/UTC timezone)
  228.  
  229. header DATE_IN_PAST_03_06    eval:check_for_shifted_date('-6', '-3')
  230. describe DATE_IN_PAST_03_06    Date: is 3 to 6 hours before Received: date
  231.  
  232. header DATE_IN_PAST_06_12    eval:check_for_shifted_date('-12', '-6')
  233. describe DATE_IN_PAST_06_12    Date: is 6 to 12 hours before Received: date
  234.  
  235. header DATE_IN_PAST_12_24    eval:check_for_shifted_date('-24', '-12')
  236. describe DATE_IN_PAST_12_24    Date: is 12 to 24 hours before Received: date
  237.  
  238. header DATE_IN_PAST_24_48    eval:check_for_shifted_date('-48', '-24')
  239. describe DATE_IN_PAST_24_48    Date: is 24 to 48 hours before Received: date
  240.  
  241. header DATE_IN_PAST_48_96    eval:check_for_shifted_date('-96', '-48')
  242. describe DATE_IN_PAST_48_96    Date: is 48 to 96 hours before Received: date
  243.  
  244. header DATE_IN_PAST_96_XX    eval:check_for_shifted_date('undef', '-96')
  245. describe DATE_IN_PAST_96_XX    Date: is 96 hours or more before Received: date
  246.  
  247. header DATE_IN_FUTURE_03_06    eval:check_for_shifted_date('3', '6')
  248. describe DATE_IN_FUTURE_03_06    Date: is 3 to 6 hours after Received: date
  249.  
  250. header DATE_IN_FUTURE_06_12    eval:check_for_shifted_date('6', '12')
  251. describe DATE_IN_FUTURE_06_12    Date: is 6 to 12 hours after Received: date
  252.  
  253. header DATE_IN_FUTURE_12_24    eval:check_for_shifted_date('12', '24')
  254. describe DATE_IN_FUTURE_12_24    Date: is 12 to 24 hours after Received: date
  255.  
  256. header DATE_IN_FUTURE_24_48    eval:check_for_shifted_date('24', '48')
  257. describe DATE_IN_FUTURE_24_48    Date: is 24 to 48 hours after Received: date
  258.  
  259. header DATE_IN_FUTURE_48_96    eval:check_for_shifted_date('48', '96')
  260. describe DATE_IN_FUTURE_48_96    Date: is 48 to 96 hours after Received: date
  261.  
  262. header DATE_IN_FUTURE_96_XX    eval:check_for_shifted_date('96', 'undef')
  263. describe DATE_IN_FUTURE_96_XX    Date: is 96 hours or more after Received: date
  264.  
  265. header UNRESOLVED_TEMPLATE    eval:check_unresolved_template()
  266. describe UNRESOLVED_TEMPLATE    Headers contain an unresolved template
  267.  
  268. ###########################################################################
  269. # illegal characters that should be MIME encoded
  270. # might want to exempt users using languages that don't use Latin
  271. # alphabets, but do it in the eval
  272.  
  273. header SUBJ_ILLEGAL_CHARS    eval:check_illegal_chars('Subject','0.00','2')
  274. describe SUBJ_ILLEGAL_CHARS    Subject: has too many raw illegal characters
  275.  
  276. header FROM_ILLEGAL_CHARS    eval:check_illegal_chars('From','0.20','2')
  277. describe FROM_ILLEGAL_CHARS    From: has too many raw illegal characters
  278.  
  279. header HEAD_ILLEGAL_CHARS    eval:check_illegal_chars('ALL','0.010','2')
  280. describe HEAD_ILLEGAL_CHARS    Headers have too many raw illegal characters
  281.  
  282. ###########################################################################
  283. # MIME encoding with spam characteristics
  284.  
  285. header __SUBJECT_NEEDS_MIME    Subject =~ /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff]/
  286. header __SUBJECT_ENCODED_QP    Subject:raw =~ /=\?\S+\?Q\?/i
  287. header __SUBJECT_ENCODED_B64    Subject:raw =~ /=\?\S+\?B\?/i
  288.  
  289. meta SUBJECT_EXCESS_QP        __SUBJECT_ENCODED_QP && !__SUBJECT_NEEDS_MIME
  290. describe SUBJECT_EXCESS_QP    Subject: quoted-printable encoded unnecessarily
  291.  
  292. meta SUBJECT_EXCESS_BASE64    __SUBJECT_ENCODED_B64 && !__SUBJECT_NEEDS_MIME
  293. describe SUBJECT_EXCESS_BASE64    Subject: base64 encoded encoded unnecessarily
  294.  
  295. header __FROM_NEEDS_MIME    From =~ /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff]/
  296. header __FROM_ENCODED_QP    From:raw =~ /=\?\S+\?Q\?/i
  297. header __FROM_ENCODED_B64    From:raw =~ /=\?\S+\?B\?/i
  298.  
  299. meta FROM_EXCESS_QP        __FROM_ENCODED_QP && !__FROM_NEEDS_MIME
  300. describe FROM_EXCESS_QP        From: quoted-printable encoded unnecessarily
  301.  
  302. meta FROM_EXCESS_BASE64        __FROM_ENCODED_B64 && !__FROM_NEEDS_MIME
  303. describe FROM_EXCESS_BASE64    From: base64 encoded unnecessarily
  304.  
  305. header SUBJECT_ENCODED_TWICE    Subject:raw =~ /=\?\S+\?[BQ]\?.*=\?\S+\?[BQ]\?/i
  306. describe SUBJECT_ENCODED_TWICE    Subject: MIME encoded twice
  307.  
  308. ###########################################################################
  309. # ADV tags in various languages
  310.  
  311. header ENGLISH_UCE_SUBJECT    Subject =~ /^[^0-9a-z]*adv(?:ert)?\b/i
  312. describe ENGLISH_UCE_SUBJECT    Subject contains an English UCE tag
  313.  
  314. # alan premselaar <alien@12inch.com>, see SpamAssassin-talk list 2003-03
  315. # quinlan: 2003-03-23 here are more generic Japanese iso-2022-jp codes
  316. # ("not yet acceptance" or "email") + "announcement"
  317. # FWIW, according to Peter Evans, this should be sufficient to catch the
  318. # UCE tag and a common attempt at evasion (using the "sue" instead of
  319. # "mi" Chinese character).
  320. header JAPANESE_UCE_SUBJECT    Subject =~ /\e\$B.*(?:L\$>5Bz|EE;R%a!<%k)9-9p/
  321. describe JAPANESE_UCE_SUBJECT    Subject contains a Japanese UCE tag
  322.  
  323. # quinlan: "advertisement" in Russian KOI8-R
  324. # (no longer common, but worth noting in future)
  325. #header RUSSIAN_UCE_SUBJECT    Subject =~ /\xf0\xe5\xea\xeb\xe0\xec\xf3/
  326. #describe RUSSIAN_UCE_SUBJECT    Subject contains a Russian UCE tag
  327.  
  328. # Korean UCE Subject: lines are usually 8-bit, but are occasionally encoded
  329. # with quoted-printable or base64.
  330. #
  331. # \xbc\xba\xc0\xce means "adult"
  332. # \xb1\xa4\xb0\xed means "advertisement"
  333. # \xc1\xa4\xba\xb8 means "information"
  334. # \xc8\xab\xba\xb8 means "publicity"
  335. #
  336. # Each two byte sequence is one Korean letter; the spaces and periods are
  337. # sometimes used to obscure the words.  \xb1\xa4\xb0\xed is the most common
  338. # tag and is sometimes very obscured so we look harder.
  339. #
  340. header KOREAN_UCE_SUBJECT    Subject =~ /[({[<][. ]*(?:\xbc\xba[. ]*\xc0\xce[. ]*)?(?:\xb1\xa4(?:[. ]*|[\x00-\x7f]{0,3})\xb0\xed|\xc1\xa4[. ]*\xba\xb8|\xc8\xab[. ]*\xba\xb8)[. ]*[)}\]>]/
  341. describe KOREAN_UCE_SUBJECT    Subject: contains Korean unsolicited email tag
  342.  
  343. ###########################################################################
  344.  
  345. header FROM_AND_TO_SAME        eval:check_for_from_to_same()
  346. describe FROM_AND_TO_SAME    From and To are the same, but not exactly
  347.  
  348. header FORGED_RCVD_HELO        eval:check_for_forged_received_helo()
  349. describe FORGED_RCVD_HELO    Received: contains a forged HELO
  350.  
  351. header RCVD_HELO_IP_MISMATCH    eval:helo_ip_mismatch()
  352. describe RCVD_HELO_IP_MISMATCH    Received: HELO and IP do not match, but should
  353.  
  354. header RCVD_NUMERIC_HELO    eval:check_for_numeric_helo()
  355. describe RCVD_NUMERIC_HELO    Received: contains an IP address used for HELO
  356.  
  357. header RCVD_ILLEGAL_IP        eval:check_for_illegal_ip()
  358. describe RCVD_ILLEGAL_IP    Received: contains illegal IP address
  359.  
  360. # no legit mailer claims that their mailserver has no name
  361. # overlaps with RCVD_DOUBLE_IP*, but let's see how it is scored
  362. header RCVD_BY_IP    Received =~ /\bby\s+\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?<!127\.0\.0\.1)\b/
  363. describe RCVD_BY_IP    Received by mail server with no name
  364.  
  365. # two reliable signatures
  366. header __DOUBLE_IP_SPAM_1    Received =~ /from \[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\] by \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} with/
  367. header __DOUBLE_IP_SPAM_2    Received =~ /from\s+\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\s+by\s+\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3};/
  368. # loose match
  369. header __DOUBLE_IP_LOOSE    Received =~ /(?:\b(?:from|by)\b.{1,4}\b\d{1,3}[._-]\d{1,3}[._-]\d{1,3}[._-]\d{1,3}(?<!127\.0\.0\.1)\b.{0,4}){2}/i
  370. # spam signature
  371. meta RCVD_DOUBLE_IP_SPAM    (__DOUBLE_IP_SPAM_1 || __DOUBLE_IP_SPAM_2)
  372. describe RCVD_DOUBLE_IP_SPAM    Bulk email fingerprint (double IP) found
  373. # other matches
  374. meta RCVD_DOUBLE_IP_LOOSE    (__DOUBLE_IP_LOOSE && !RCVD_DOUBLE_IP_SPAM)
  375. describe RCVD_DOUBLE_IP_LOOSE   Received: by and from look like IP addresses
  376.  
  377. header FORGED_AOL_RCVD            eval:check_for_fake_aol_relay_in_rcvd()
  378. describe FORGED_AOL_RCVD    Received forged, contains fake AOL relays
  379.  
  380. header FORGED_TELESP_RCVD    Received =~ /\.(?!br).. \(\d+-\d+-\d+-\d+\.dsl\.telesp\.net\.br /
  381. describe FORGED_TELESP_RCVD    Contains forged hostname for a DSL IP in Brazil
  382.  
  383. # a forged Hotmail message; host HELO'd as hotmail.com, but it wasn't
  384. header FORGED_HOTMAIL_RCVD    eval:check_for_forged_hotmail_received_headers()
  385. describe FORGED_HOTMAIL_RCVD    Forged hotmail.com 'Received:' header found
  386.  
  387. # this, by comparison is more common: from was @hotmail.com, but it wasn't
  388. header FORGED_HOTMAIL_RCVD2    eval:check_for_no_hotmail_received_headers()
  389. describe FORGED_HOTMAIL_RCVD2 hotmail.com 'From' address, but no 'Received:'
  390.  
  391. header FORGED_EUDORAMAIL_RCVD    eval:check_for_forged_eudoramail_received_headers()
  392. describe FORGED_EUDORAMAIL_RCVD    Forged eudoramail.com 'Received:' header found
  393.  
  394. header FORGED_YAHOO_RCVD    eval:check_for_forged_yahoo_received_headers()
  395. describe FORGED_YAHOO_RCVD    'From' yahoo.com does not match 'Received' headers
  396.  
  397. header FORGED_JUNO_RCVD        eval:check_for_forged_juno_received_headers()
  398. describe FORGED_JUNO_RCVD    'From' juno.com does not match 'Received' headers
  399.  
  400. header FORGED_GW05_RCVD        eval:check_for_forged_gw05_received_headers()
  401. describe FORGED_GW05_RCVD    Forged 'by gw05' 'Received:' header found
  402.  
  403. # not used directly right now due to FPs; but CONFIRMED_FORGED turns it
  404. # into a 1.0 S/O rule anyway, so that's not a problem ;)
  405. # 2.626   3.6340   1.5251    0.704   0.34    1.44  FORGED_RCVD_TRAIL
  406. # 0.956   3.3890   0.0000    1.000   0.98    4.30  CONFIRMED_FORGED
  407. header __FORGED_RCVD_TRAIL    eval:check_for_forged_received_trail()
  408.  
  409. # forgery meta-rules: more reliable than their inputs
  410. meta CONFIRMED_FORGED        (__FORGED_RCVD_TRAIL && (FORGED_AOL_RCVD || FORGED_HOTMAIL_RCVD || FORGED_EUDORAMAIL_RCVD || FORGED_YAHOO_RCVD || FORGED_JUNO_RCVD || FORGED_GW05_RCVD))
  411. describe CONFIRMED_FORGED    Received headers are forged
  412.  
  413. meta MULTI_FORGED        ((FORGED_AOL_RCVD + FORGED_HOTMAIL_RCVD + FORGED_EUDORAMAIL_RCVD + FORGED_YAHOO_RCVD + FORGED_JUNO_RCVD + FORGED_GW05_RCVD) > 1)
  414. describe MULTI_FORGED        Received headers indicate multiple forgeries
  415.  
  416. header NONEXISTENT_CHARSET    Content-Type =~ /charset=.?DEFAULT/
  417. describe NONEXISTENT_CHARSET    Character set doesn't exist
  418.  
  419. header CHARSET_FARAWAY_HEADER    eval:check_for_faraway_charset_in_headers()
  420. describe CHARSET_FARAWAY_HEADER    A foreign language charset used in headers
  421. tflags CHARSET_FARAWAY_HEADER    userconf
  422.  
  423. header X_PRIORITY_HIGH        X-Priority =~ /^1/
  424. describe X_PRIORITY_HIGH    Sent with 'X-Priority' set to high
  425.  
  426. header X_MSMAIL_PRIORITY_HIGH    X-Msmail-Priority =~ /^High/
  427. describe X_MSMAIL_PRIORITY_HIGH    Sent with 'X-Msmail-Priority' set to high
  428.  
  429. # this variant is local, using the Received hdr itself...
  430. header ROUND_THE_WORLD_LOCAL    eval:check_for_round_the_world_received_helo()
  431. describe ROUND_THE_WORLD_LOCAL    Received: says mail sent around the world (HELO)
  432.  
  433. header MISSING_DATE             Date =~ /^UNSET$/ [if-unset: UNSET]
  434. describe MISSING_DATE           Missing Date: header
  435.  
  436. # this is a quite common false positive, as it's legal to remove a To but leave
  437. # a CC. so don't score it high.
  438. header MISSING_HEADERS        eval:check_for_missing_to_header()
  439. describe MISSING_HEADERS    Missing To: header
  440.  
  441. header __HAS_SUBJECT        exists:Subject
  442. meta MISSING_SUBJECT        !__HAS_SUBJECT
  443. describe MISSING_SUBJECT    Missing Subject: header
  444.  
  445. header SUSPICIOUS_RECIPS    eval:similar_recipients('0.65','undef')
  446. describe SUSPICIOUS_RECIPS    Similar addresses in recipient list
  447.  
  448. header SORTED_RECIPS        eval:sorted_recipients()
  449. describe SORTED_RECIPS        Recipient list is sorted by address
  450.  
  451. header GAPPY_SUBJECT        Subject =~ /\b(?:[a-z]([-_. =~\/:,*!\@\#\$\%\^&+;\"\'<>\\])\1{0,2}){4}/i
  452. describe GAPPY_SUBJECT        Subject: contains G.a.p.p.y-T.e.x.t
  453.  
  454. ### header existence tests (description is added automatically)
  455.  
  456. # X-Fix example: NTMail fixed non RFC822 compliant EMail message
  457. #
  458. # X-PMFLAGS is all caps
  459. #
  460. # Headers that seem to only be used by a single spamming software and
  461. # are found together in the same message:
  462. # 1. X-MailingID and X-ServerHost
  463. # 2. X-Stormpost-To and X-List-Unsubscribe
  464. #
  465. # not spammish: X-EM-Registration, X-EM-Version, X-Antiabuse, X-List-Host,
  466. # X-Message-Id
  467. # bad FP rate: Comment, Date-warning
  468.  
  469. header PREVENT_NONDELIVERY    exists:Prevent-NonDelivery-Report
  470. describe PREVENT_NONDELIVERY    Message has Prevent-NonDelivery-Report header
  471.  
  472. header X_IP            exists:X-IP
  473. describe X_IP            Message has X-IP header
  474.  
  475. header X_LIBRARY        exists:X-Library
  476. describe X_LIBRARY        Message has X-Library header
  477.  
  478. # this rule is case-sensitive
  479. header X_MESSAGE_FLAG_ODD    ALL =~ /^X-Message-flag:/m
  480. describe X_MESSAGE_FLAG_ODD    Message has X-Message-flag header (odd case)
  481.  
  482. header   __HAS_MIMEOLE          exists:X-MimeOLE
  483. header   __HAS_MSMAIL_PRI       exists:X-MSMail-Priority
  484. header   __HAS_SQUIRRELMAIL_IN_MAILER    X-Mailer =~ /SquirrelMail\b/
  485. meta     MISSING_MIMEOLE    (__HAS_MSMAIL_PRI && !__HAS_MIMEOLE && !__HAS_SQUIRRELMAIL_IN_MAILER)
  486. describe MISSING_MIMEOLE    Message has X-MSMail-Priority, but no X-MimeOLE
  487.  
  488. header __HAS_X_MAILER        exists:X-Mailer
  489.  
  490. header __IS_EXCH        X-MimeOLE =~ /Produced By Microsoft Exchange V/
  491.  
  492. header __HAS_X_PRIORITY     exists:X-Priority
  493. header __USER_AGENT             exists:User-Agent
  494. header __X_NEWSREADER        exists:X-Newsreader
  495. meta PRIORITY_NO_NAME        ((__HAS_X_PRIORITY && __HAS_MSMAIL_PRI) && !__HAS_X_MAILER && !__IS_EXCH && !__USER_AGENT && !__X_NEWSREADER)
  496. describe PRIORITY_NO_NAME    Message has priority, but no user agent name
  497.  
  498. header SUBJ_AS_SEEN        Subject =~ /\bAs Seen/i
  499. describe SUBJ_AS_SEEN        Subject contains "As Seen"
  500.  
  501. header SUBJ_DOLLARS             Subject =~ /^\$[0-9.,]+\b/
  502. describe SUBJ_DOLLARS           Subject starts with dollar amount
  503.  
  504. header SUBJ_FOR_ONLY         Subject =~ /For Only/i
  505. describe SUBJ_FOR_ONLY         Subject contains "For Only"
  506.  
  507. header SUBJ_FREE_CAP        Subject =~ /FREE|F.R.E.E\b/
  508. describe SUBJ_FREE_CAP        Subject contains "FREE" in CAPS
  509.  
  510. header SUB_FREE_OFFER           Subject =~ /^fre{2,}\b/i
  511. describe SUB_FREE_OFFER         Subject starts with "Free"
  512.  
  513. header SUBJ_GUARANTEED          Subject =~ /^guaranteed|(?-i:GUARANTEE)/i
  514. describe SUBJ_GUARANTEED        Subject GUARANTEED
  515.  
  516. header SUB_HELLO                Subject =~ /^hello\b/i
  517. describe SUB_HELLO              Subject starts with "Hello"
  518.  
  519. header SUBJ_LIFE_INSURANCE    Subject =~ /life\s+insurance/i
  520. describe SUBJ_LIFE_INSURANCE    Subject includes "life insurance"
  521.  
  522. header SUBJ_YOUR_DEBT        Subject =~ /Your (?:Bills|Debt|Credit)/i
  523. describe SUBJ_YOUR_DEBT        Subject contains "Your Bills" or similar
  524.  
  525. header SUBJ_YOUR_FAMILY        Subject =~ /Your Family/i
  526. describe SUBJ_YOUR_FAMILY    Subject contains "Your Family"
  527.  
  528. header SUBJ_YOUR_OWN        Subject =~ /Your Own/i
  529. describe SUBJ_YOUR_OWN        Subject contains "Your Own"
  530.  
  531. # the real services never HELO as 'foo.com', instead 'mail.foo.com' or
  532. # something like that.  Note: be careful when expanding this... legit dotcom
  533. # HELOers include: hotmail.com, drizzle.com, lockergnome.com.
  534. header RCVD_FAKE_HELO_DOTCOM    Received =~ /^from (?:msn|yahoo|yourwebsite|lycos|excite|cs|aol|localhost|koreanmail|allexecs|mydomain|juno|eudoramail|compuserve|desertmail|excite|caramail)\.com \(/m
  535. describe RCVD_FAKE_HELO_DOTCOM  Received contains a faked HELO hostname
  536.  
  537. header ADDRESS_IN_SUBJECT    eval:check_for_to_in_subject('address')
  538. describe ADDRESS_IN_SUBJECT    To: address appears in Subject
  539.  
  540. header LOCALPART_IN_SUBJECT    eval:check_for_to_in_subject('user')
  541. describe LOCALPART_IN_SUBJECT    Local part of To: address appears in Subject
  542.  
  543. header SUBJECT_DIET        Subject =~ /\bLose .*(?:pounds|lbs|weight)/i
  544. describe SUBJECT_DIET        Subject talks about losing pounds
  545.  
  546. header EXTRA_MPART_TYPE         Content-Type =~ /(?:\s*multipart\/)?.* type=/i
  547. describe EXTRA_MPART_TYPE       Header has extraneous Content-type:...type= entry
  548.  
  549. header TO_RECIP_MARKER          To =~ /\#recipient\#/
  550. describe TO_RECIP_MARKER        To header contains 'recipient' marker
  551.  
  552. # MIME boundary tests; spam tools use distinctive patterns.
  553. header MIME_BOUND_DD_DIGITS    Content-Type =~ /boundary=\"--\d+\"/
  554. describe MIME_BOUND_DD_DIGITS    Spam tool pattern in MIME boundary
  555. header MIME_BOUND_DIGITS_7    Content-Type =~ /boundary=\d{9}\.\d{13}/
  556. describe MIME_BOUND_DIGITS_7    Spam tool pattern in MIME boundary
  557. header MIME_BOUND_DIGITS_15    Content-Type =~ /boundary=\"\d{15,}\"/
  558. describe MIME_BOUND_DIGITS_15    Spam tool pattern in MIME boundary
  559. header MIME_BOUND_MANY_HEX    Content-Type =~ /boundary="[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}"/
  560. describe MIME_BOUND_MANY_HEX    Spam tool pattern in MIME boundary
  561. header __NEXTPART_ALL        Content-Type =~ /NextPart/
  562. header __NEXTPART_NORMAL    Content-Type =~ /="(?:----_?=_)?NextPart_[\dA-F]{3}(_[\dA-F]{3,8})?_[\dA-F]{8}\.[\dA-F]{8}"/
  563. meta MIME_BOUND_NEXTPART    (__NEXTPART_ALL && !__NEXTPART_NORMAL)
  564. describe MIME_BOUND_NEXTPART    Spam tool pattern in MIME boundary
  565. header MIME_BOUND_RKFINDY       Content-Type =~ /boundary=\"=_NextPart_2rfkindysadvnqw3nerasdf\"/
  566. describe MIME_BOUND_RKFINDY     Spam tool pattern in MIME boundary (rfkindy)
  567.  
  568. # note: the first alternation is anchored for speed
  569. header TO_MALFORMED             To !~ /(?:^|[^\S"])(?:(?:\"[^\"]+\"|\S+)\@\S+\.\S+|^\s*.+:\s*;|^\s*\"[^\"]+\":\s*;|^\s*\([^\)]*\)\s*$|<\S+(?:\!\S+){1,}>|^\s*$)/ [if-unset: unset@unset.unset]
  570. describe TO_MALFORMED           To: has a malformed address
  571.  
  572. header ADDR_FREE              From =~ /\b(?-i:F)ree(?-i:[ A-Z]).*</i
  573. describe ADDR_FREE            From Address contains FREE
  574.  
  575. # common spam-dropping: To: C:\VICTIMS.txt@yourmx.org
  576. header TO_TXT            To =~ /\.txt[\'\"]?\@/i
  577. describe TO_TXT            Sent to a text file
  578.  
  579. header CHINA_HEADER             ALL =~ /\@china\.com/i
  580. describe CHINA_HEADER           Involves 'china.com'
  581.  
  582. header __CD                     exists:Content-Disposition
  583. header __CT                     exists:Content-Type
  584. header __CTE                    exists:Content-Transfer-Encoding
  585. header __MIME_VERSION           exists:MIME-Version
  586. header __CT_TEXT_PLAIN          Content-Type =~ /^text\/plain\b/i
  587. meta MIME_HEADER_CTYPE_ONLY     (!__CD && !__CTE && __CT && !__MIME_VERSION && !__CT_TEXT_PLAIN)
  588. describe MIME_HEADER_CTYPE_ONLY 'Content-Type' found without required MIME headers
  589.  
  590. header WITH_LC_SMTP        Received =~ /\swith\ssmtp;\s/
  591. describe WITH_LC_SMTP        Received line contains spam-sign (lowercase smtp)
  592.  
  593. header FROM_NO_LOWER        From:addr !~ /[a-z]/ [if-unset: x@example.com]
  594. describe FROM_NO_LOWER        From address has no lower-case characters
  595.  
  596. header SUBJ_BUY                 Subject =~ /^buy/i
  597. describe SUBJ_BUY               Subject line starts with Buy or Buying
  598.  
  599. # seems to be ratware
  600. header RCVD_AM_PM        Received =~ /; [A-Z][a-z][a-z], \d{1,2} \d{4} \d{1,2}:\d\d:\d\d [AP]M [+-]\d{4}/
  601. describe RCVD_AM_PM        Received headers forged (AM/PM)
  602.  
  603. header HEADER_COUNT_CTYPE    eval:check_header_count_range('Content-Type','2','999')
  604. describe HEADER_COUNT_CTYPE    Multiple Content-Type headers found
  605.  
  606. header __USER_AGENT_MSN             X-Mailer =~ /^MSN Explorer /
  607.  
  608. header NO_RDNS_DOTCOM_HELO    eval:check_for_no_rdns_dotcom_helo()
  609. describe NO_RDNS_DOTCOM_HELO    Host HELO'd as a big ISP, but had no rDNS
  610.  
  611. header X_ORIG_IP_NOT_IPV4    X-Originating-IP !~ /\[?(?:\d{1,3}\.){3}\d{1,3}\]?/ [if-unset: 0.0.0.0]
  612. describe X_ORIG_IP_NOT_IPV4    X-Originating-IP doesn't look like IPv4 address
  613.  
  614. # match the format of a legit X-Auth-Warning header, and hit on fake ones
  615. # normal: "e4e.oac.uci.edu: foo owned process doing -bs"
  616. # fake: "bzgrdag, upaeqehv"
  617. header X_AUTH_WARN_FAKED    X-Authentication-Warning !~ /(?:set sender to \S{2,80} using -f|owned process doing -bs|claimed to be|didn.t use HELO protocol)/ [if-unset: host.example.com: foo owned process doing -bs]
  618. describe X_AUTH_WARN_FAKED    X-Authentication-Warning header looks faked
  619.  
  620. # host no longer exists according to administrator
  621. header FAKE_OUTBLAZE_RCVD    Received =~ /\.mr\.outblaze\.com/
  622. describe FAKE_OUTBLAZE_RCVD    Received header contains faked 'mr.outblaze.com'
  623.  
  624. # domains never longer used for email, confirmed by administrator
  625. header FROM_NONSENDING_DOMAIN    From:addr =~ /\@(?:altavista\.com|eudora\.com)$/i
  626. describe FROM_NONSENDING_DOMAIN    Message is from domain that never sends email
  627.  
  628. header SUBJ_2_NUM_PARENS        Subject =~ /^\(\d+\).*\(\d+\)\s*$/
  629. describe SUBJ_2_NUM_PARENS      Subject contains common spam sign (2 numbers)
  630.  
  631. # thanks to David Ritz for passing this on; ready for post-3.0.0
  632. header UNCLOSED_BRACKET        ALL =~ /\[\d+\r?\n/s
  633. describe UNCLOSED_BRACKET    Headers contain an unclosed bracket
  634.  
  635. # some header rules
  636. header ORG_MIME_TOOLS        Organization =~ /MIME-tools/
  637. describe ORG_MIME_TOOLS        Organization is MIME-tools
  638.  
  639. header X_MIME_AUTOCONVERTED    X-MIME-Autoconverted =~ /Yes/
  640. describe X_MIME_AUTOCONVERTED    Message has X-MIME-Autoconverted "Yes" header
  641.  
  642. header __HOTMAIL_RCVD        Received =~/\bhotmail\.com\b/
  643. header __HOTMAIL_SMTPSVC    Received =~ /\bwith Microsoft SMTPSVC;/
  644. header __HOTMAIL_OIP        X-Originating-IP =~ /\[(\d{1,3}\.){3}\d{1,3}\]/
  645. header __RECEIVED_DAV        Received =~ /\bwith DAV;/
  646. meta DAV_NON_HOTMAIL        __RECEIVED_DAV && !(__HOTMAIL_RCVD && __HOTMAIL_SMTPSVC && __HOTMAIL_OIP)
  647. describe DAV_NON_HOTMAIL    Message sent using DAV, but not via Hotmail
  648.  
  649. header FROM_DOMAIN_NOVOWEL    From =~ /\@\S*[bcdfghjklmnpqrstvwxz]{7}/i
  650. describe FROM_DOMAIN_NOVOWEL    From: domain has series of non-vowel letters
  651.  
  652. header FROM_LOCAL_NOVOWEL    From =~ /[bcdfghjklmnpqrstvwxz]{7}\S*\@/i
  653. describe FROM_LOCAL_NOVOWEL    From: localpart has series of non-vowel letters
  654.  
  655. header SUBJECT_NOVOWEL        Subject =~ /[bcdfghjklmnpqrstvwxz]{8}/i
  656. describe SUBJECT_NOVOWEL    Subject: has long non-vowel letter sequence
  657.  
  658. header FROM_LOCAL_HEX        From =~ /[0-9a-f]{11}\S*\@/i
  659. describe FROM_LOCAL_HEX        From: localpart has long hexadecimal sequence
  660.  
  661. header FROM_LOCAL_DIGITS    From =~ /\d{11}\S*\@/i
  662. describe FROM_LOCAL_DIGITS    From: localpart has long digit sequence
  663.  
  664. header X_MAILER_SPAM        X-Mailer !~ m{[A-Z0-9./]} [if-unset: Foo 1.0]
  665. describe X_MAILER_SPAM        X-Mailer: header is bulk email fingerprint
  666.  
  667. header __TOCC_EXISTS        exists:ToCc
  668. meta TO_CC_NONE            !__TOCC_EXISTS
  669. describe TO_CC_NONE        No To: or Cc: header
  670.  
  671. header X_PRIORITY_CC        ALL =~ /\nX-Priority:[^\n]{0,80}\nCc:/si
  672. describe X_PRIORITY_CC        Cc: after X-Priority: (bulk email fingerprint)
  673.  
  674. header    SUBJ_CONSONANTS       Subject =~ /\b[bcghjklmnpqrstvwxz]{6,20}\b/
  675. describe  SUBJ_CONSONANTS       Subject contains consecutive consonants in "word"
  676.  
  677. # catch non-RFC2047 compliant messages
  678. # Apple Mail has a bug where headers will have whitespace around the encoded
  679. # text, so try to ignore that
  680. header BAD_ENC_HEADER        ALL =~ /=\?[^?\s]+\?[^?\s]\?\s*[^?]+\s(?!\?=)/
  681. describe BAD_ENC_HEADER        Message has bad MIME encoding in the header
  682.