Fail2ban filter for error 400 on nginx

Your failregex is not accurate (moreover it is vulnerable) because it is searching and can find 400 literally everywhere and not as a response code only.
The begin anchor (^) is only working for <HOST> tag and stops to operate hereafter due to catch-all .* and not end-anchored, because .*$ is not an anchor at all, so ultimately the regex is unanchored from both sides, what is always bad, because:

  • it's vulnerable in sense of accuracy (e. g. false positives)
  • it makes parsing extremely slow (especially on some long messages)

Also you don't need extra filter for such simple thing, you can set it directly in jail, so this would be fully enough in your jail.local:

[ban-400]
logpath = ...
filter =
port = 80,443
failregex = ^<ADDR> \S+ \S+(?: \[\])? "[^"]*" 400\s
enabled = true

This failregex is accurate and as fast as possible (it finds 400 only as response code).

Remark: (nginx is not affected)
If a quote-character can be also enclosed between quotes as escaped value like \" (nginx escapes it as \x22, see excerpt, so it is rather escaped as hex value and " should not occur at all), you could replace "[^"]*" with "(?:[^"]*|(?:[^"\\]*|\\.)*)", which can be a bit slower than former.

Also please note the fail2ban :: wiki :: Best practice.