haraka-plugin-karma 2.4.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
4
4
 
5
5
  ### Unreleased
6
6
 
7
+ ### [2.4.1] - 2026-05-13
8
+
9
+ - fix: after trapping a denysoft, return denysoft later (vs deny)
10
+ - config: update spammy TLDs
11
+ - fix(config): spamassassin hits -> score
12
+
7
13
  ### [2.4.0] - 2026-05-06
8
14
 
9
15
  - extend spammy_tlds to support multi-label suffixes
@@ -172,3 +178,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
172
178
  [2.2.0]: https://github.com/haraka/haraka-plugin-karma/releases/tag/v2.2.0
173
179
  [2.3.0]: https://github.com/haraka/haraka-plugin-karma/releases/tag/v2.3.0
174
180
  [2.4.0]: https://github.com/haraka/haraka-plugin-karma/releases/tag/v2.4.0
181
+ [2.4.1]: https://github.com/haraka/haraka-plugin-karma/releases/tag/v2.4.1
package/config/karma.ini CHANGED
@@ -56,8 +56,8 @@ hooks=unrecognized_command,data,data_post,queue,queue_outbound
56
56
  [deny_excludes]
57
57
  ; karma captures and scores deny requests from other plugins, permitting finer
58
58
  ; control over connection handling. For plugins that should be able to reject
59
- ; the connection, add their name to the plugin list:
60
- plugins=send_email, tls, access, helo.checks, headers, rspamd, spamassassin, clamd, attachment, limit
59
+ ; the connection, add their name to the plugins list:
60
+ plugins=access, attachment, clamd, headers, helo.checks, limit, rspamd, spamassassin, send_email, tls
61
61
 
62
62
  ; hooks whose DENY rejections should be not be captured.
63
63
  hooks=rcpt, queue, queue_outbound
@@ -79,41 +79,79 @@ hooks=rcpt, queue, queue_outbound
79
79
  ; award negative karma to spammy TLDs or second-level domains
80
80
  ; multi-label suffixes are supported, e.g.: sa.com=-3
81
81
  ; caution, awarding karma > msg_negative_limit may blacklist that TLD
82
+ archi=-5
83
+ baby=-5
82
84
  bid=-3
83
85
  biz=-2
84
86
  bet=-4
87
+ best=-4
85
88
  bio=-4
89
+ bond=-4
90
+ boston=-5
86
91
  buzz=-3
92
+ cam=-3
93
+ city=-5
94
+ cc=-3
95
+ co=-3
87
96
  club=-3
97
+ coach=-5
98
+ codes=-5
99
+ coffee=-5
88
100
  company=-4
101
+ coupons=-5
89
102
  directory=-4
103
+ dog=-4
104
+ energy=-4
90
105
  eu=-4
106
+ financial=-5
91
107
  fun=-5
92
- guru=-4
108
+ fund=-5
109
+ futbol=-5
110
+ gay=-5
111
+ global=-4
112
+ guide=-4
113
+ guru=-5
93
114
  gury=-3
115
+ help=-4
94
116
  icu=-6
95
- info=-4
117
+ industries=-4
118
+ info=-5
96
119
  link=-3
97
- me=-1
120
+ live=-5
121
+ love=-6
122
+ makeup=-5
123
+ me=-2
124
+ mobi=-6
98
125
  monster=-5
99
126
  mom=-5
100
127
  na=-6
101
128
  ninja=-3
102
- one=-4
129
+ one=-5
130
+ onl=-5
103
131
  pics=-5
132
+ pro=-5
104
133
  pw=-2
134
+ rest=-5
105
135
  rocks=-3
136
+ rodeo=-5
106
137
  ru=-2
107
- sbs=-4
138
+ sbs=-5
108
139
  science=-6
140
+ shop=-6
141
+ site=-8
142
+ skin=-4
143
+ store=-5
109
144
  stream=-3
110
145
  studio=-5
146
+ support=-5
147
+ tax=-5
111
148
  top=-5
112
149
  trade=-3
113
150
  us=-4
151
+ vin=-5
114
152
  work=-4
115
153
  xyz=-6
116
-
154
+ zone=-5
117
155
 
118
156
  [tls]
119
157
  ; awards based on whether the sender opportunistically encrypted
@@ -202,7 +240,7 @@ early_talker = -3
202
240
  008 = karma | pass | equals | asn | 1 | ASN reputation is good
203
241
  009 = karma | fail | equals | asn | -1 | ASN reputation is bad
204
242
  010 = karma | pass | equals | asn_all_good | 2 | ASN reputation is very good
205
- 011 = karma | fail | equals | asn_all_bad | -2 | ASN reputation is very bad
243
+ 011 = karma | fail | equals | asn_all_bad | -1 | ASN reputation is very bad
206
244
 
207
245
  012 = karma | fail | equals | rfc5321.MailFrom | -1 | RFC Ignorant MTA | Use a RFC compliant MTA
208
246
  013 = karma | fail | equals | rfc5321.RcptTo | -1 | RFC Ignorant MTA | Use a RFC compliant MTA
@@ -220,7 +258,7 @@ early_talker = -3
220
258
  032 = p0f | os_flavor | equals | XP | -2 | Windows XP, likely infected by malware | Upgrade to a supported OS
221
259
 
222
260
  ; give back the point penalized for running windows
223
- ; 080 = fcrdns | fcrdns | match | outlook.com | 1
261
+ 080 = fcrdns | fcrdns | match | outlook.com | 1
224
262
  ; 081 = fcrdns | fcrdns@1 = 1 if length gt 0
225
263
  ; 082 = fcrdns | err@1 = -1 if length gt 0
226
264
  ; 083 = fcrdns | fail@1 = -1 if length gt 0
@@ -316,32 +354,34 @@ early_talker = -3
316
354
  218 = clamd | fail | match | spam | -2 | Clam AntiVirus Spam
317
355
  ;219 = clamd | pass | equals | clean | 1 | Clam AntiVirus Executable
318
356
 
319
- 230 = rspamd | is_spam | equals | true | -2 | rspamd detected as spam
320
- 231 = rspamd | action | equals | greylist | -1 | rspamd suggested greylist
321
- 232 = rspamd | score | lt | 0 | 1 | rspamd positive score
322
- 233 = rspamd | score | gt | 6 | -1 | rspamd moderate score
323
- 234 = rspamd | score | gt | 10 | -1 | rspamd high score
324
- 235 = rspamd | is_spam | equals | false | 1 | rspamd detected as ham
325
- 236 = rspamd | action | match | reject | -2 | rspamd suggested reject
357
+ ;230 = rspamd | action | match | reject | -2 | rspamd suggested reject
358
+ ;231 = rspamd | action | equals | greylist | -1 | rspamd suggested greylist
359
+ 232 = rspamd | score | lt | 0 | 1 |
360
+ 233 = rspamd | score | lt | -5 | 1 |
361
+ 234 = rspamd | score | lt | -10 | 1 |
362
+ 235 = rspamd | score | gt | 6 | -1 |
363
+ 236 = rspamd | score | gt | 10 | -1 |
364
+ 237 = rspamd | is_spam | equals | true | -2 | rspamd detected as spam
365
+ 238 = rspamd | is_spam | equals | false | 1 | rspamd detected as ham
326
366
 
327
367
  237 = rspamd | symbols | match | DMARC_POLICY_ALLOW | 1 | DMARC policy allow
328
368
  238 = rspamd | symbols | match | DMARC_POLICY_REJECT | -6 | DMARC policy reject
329
369
  239 = rspamd | symbols | match | DMARC_POLICY_QUARANTINE | -4 | DMARC policy reject
330
370
  240 = rspamd | symbols | match | DMARC_POLICY_SOFTFAIL | -2 | DMARC policy softfail
331
371
 
332
- 251 = spamassassin | hits | lt | 0 | 1 |
333
- 252 = spamassassin | hits | lt | -2 | 1 |
334
- 253 = spamassassin | hits | lt | -5 | 1 |
335
- 254 = spamassassin | hits | lt | -10 | 2 |
336
- 255 = spamassassin | hits | lt | -20 | 5 |
337
- 256 = spamassassin | hits | gt | 1 | -1 |
338
- 257 = spamassassin | hits | gt | 2 | -1 |
339
- 259 = spamassassin | hits | gt | 3 | -2 |
340
- 260 = spamassassin | flag | equals | Yes | -5 | SpamAssassin detected as spam
341
- ;261 = spamassassin | hits | gt | 6 | -2 |
342
- ;263 = spamassassin | hits | gt | 8 | -2 |
343
- 264 = spamassassin | hits | gt | 9 | -2 |
344
- 265 = spamassassin | hits | gt | 20 | -10 |
372
+ 251 = spamassassin | score | lt | 0 | 1 |
373
+ 252 = spamassassin | score | lt | -2 | 1 |
374
+ 253 = spamassassin | score | lt | -5 | 1 |
375
+ 254 = spamassassin | score | lt | -10 | 2 |
376
+ 255 = spamassassin | score | lt | -20 | 5 |
377
+ 256 = spamassassin | score | gt | 1 | -1 |
378
+ 257 = spamassassin | score | gt | 2 | -1 |
379
+ 258 = spamassassin | score | gt | 3 | -2 |
380
+ ;259 = spamassassin | score | gt | 6 | -2 |
381
+ ;260 = spamassassin | score | gt | 8 | -2 |
382
+ 261 = spamassassin | score | gt | 9 | -2 |
383
+ 262 = spamassassin | score | gt | 20 | -10 |
384
+ ;263 = spamassassin | flag | equals | Yes | -5 | SpamAssassin detected as spam
345
385
 
346
386
  280 = known-senders | pass | equals | wks | 5 | Known Sender
347
387
  281 = known-senders | pass | length | gt 0 | 5 | Known Sender
package/index.js CHANGED
@@ -439,15 +439,17 @@ exports.should_we_deny = function (next, connection, hook) {
439
439
  rejectMsg = rejectMsg.replace(/\{uuid\}/, connection.uuid)
440
440
  }
441
441
 
442
+ const deny_rc = r.deny_rc ?? constants.DENY
443
+
442
444
  return this.apply_tarpit(connection, hook, score, () => {
443
- next(constants.DENY, rejectMsg)
445
+ next(deny_rc, rejectMsg)
444
446
  })
445
447
  }
446
448
 
447
449
  exports.hook_deny = function (next, connection, params) {
448
450
  if (this.should_we_skip(connection)) return next()
449
451
 
450
- const [_pi_rc, , pi_name, , , pi_hook] = params
452
+ const [pi_rc, , pi_name, , , pi_hook] = params
451
453
 
452
454
  // exceptions, whose 'DENY' should not be captured
453
455
  if (pi_name) {
@@ -464,9 +466,31 @@ exports.hook_deny = function (next, connection, params) {
464
466
  connection.results.add(this, { msg: `deny: ${pi_name}` })
465
467
  connection.results.incr(this, { score: -2 })
466
468
 
469
+ // Remember the worst-severity intercepted code so a later karma-issued
470
+ // deny doesn't escalate a soft reject (e.g. rspamd greylist) to a hard
471
+ // reject.
472
+ this.track_intercepted_rc(connection, pi_rc)
473
+
467
474
  next(constants.OK) // resume the connection
468
475
  }
469
476
 
477
+ exports.track_intercepted_rc = function (connection, pi_rc) {
478
+ const k = connection.results.get('karma')
479
+ if (!k) return
480
+
481
+ if (pi_rc === constants.DENY || pi_rc === constants.DENYDISCONNECT) {
482
+ connection.results.add(this, { deny_rc: constants.DENY })
483
+ return
484
+ }
485
+
486
+ if (
487
+ (pi_rc === constants.DENYSOFT || pi_rc === constants.DENYSOFTDISCONNECT) &&
488
+ k.deny_rc !== constants.DENY
489
+ ) {
490
+ connection.results.add(this, { deny_rc: constants.DENYSOFT })
491
+ }
492
+ }
493
+
470
494
  exports.hook_connect = function (next, connection) {
471
495
  if (this.should_we_skip(connection)) return next()
472
496
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haraka-plugin-karma",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "A heuristics scoring and reputation engine for SMTP connections",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "devDependencies": {
41
41
  "@haraka/eslint-config": "^2.0.4",
42
- "haraka-test-fixtures": "^1.4.1"
42
+ "haraka-test-fixtures": "^1.4.3"
43
43
  },
44
44
  "prettier": {
45
45
  "singleQuote": true,