If you have a FortiGate with SSL VPN exposed to the internet, you already know what the auth logs look like. Constant failed login attempts from IPs all over the world, hammering usernames. Most of it is automated. Most of it never stops on its own.
The usual answer is GeoIP blocking, which helps, but attackers route through residential proxies in allowed countries constantly. What actually stops it is making the firewall ban the IP the moment an attack starts — automatically, without a human in the loop. FortiGate can do this natively with an automation stitch. Here's exactly how to build it.
What an Automation Stitch Is
FortiOS has a feature called automation stitches — an event-driven trigger/action system built into the firewall. You define a trigger (a specific log event), and an action (run a CLI script, send an email, call a webhook). When the trigger fires, the action runs. No external tooling required.
The key piece that makes this work for IP banning is the %%log.remip%% macro — a variable
that FortiOS substitutes with the source IP from the triggering log event when it runs the CLI action.
Building the Stitch
Step 1: Create the CLI Action
First, create the action that will do the actual banning. In the CLI:
config system automation-action
edit "ban-ssl-vpn-attacker"
set action-type cli-script
set script "config user banned
edit 0
set addr %%log.remip%%
set expires 0
next
end"
set accprofile "super_admin"
next
end
The expires 0 means permanent ban. Change it to a value in seconds if you'd rather have
a timed ban — 86400 for 24 hours, for example. The accprofile needs to be
a profile with sufficient permission to run CLI commands; super_admin works but scope it
down if your security posture demands it.
Step 2: Create the Trigger
Now create the trigger that fires on SSL VPN authentication failures:
config system automation-trigger
edit "ssl-vpn-login-fail"
set event-type log-event
set logid 39424
set trigger-frequency once
next
end
Log ID 39424 is the SSL VPN authentication failure event in FortiOS. The
trigger-frequency once means it fires on the first failure — you can adjust this
to require multiple failures if you want a threshold. Be aware that some legitimate users
mistype their password, so a threshold of 3-5 may be more appropriate for your environment.
diagnose debug application sslvpn -1 and attempt a bad login to confirm.
Step 3: Wire Them Together
config system automation-stitch
edit "auto-ban-ssl-brute"
set trigger "ssl-vpn-login-fail"
set action "ban-ssl-vpn-attacker"
set status enable
next
end
Verifying It Works
Once the stitch is enabled, attempt a failed SSL VPN login from a test IP (or check your logs for recent failures). Then verify the ban table:
diagnose user banned-ip list
You should see the source IP appear in the banned list within seconds of the failed auth event being logged. To manually unban an IP during testing:
diagnose user banned-ip delete <ip-address>
Results in Production
After deploying this on a client FortiGate that was taking consistent brute force traffic, the banned IP list crossed 30 entries within the first hour. The auth failure rate in the logs dropped to near zero within a day as the bots hit the wall and moved on. The ones that don't move on just keep accumulating bans — their second IP gets banned as fast as the first.
Wrapping Up
FortiOS automation stitches are underused. Most people set up GeoIP and call it a day, but this
is genuinely reactive — the firewall is defending itself in real time. The %%log.remip%%
macro is the piece that makes it dynamic, and once you understand how it works, you can apply the
same pattern to other attack surfaces: admin login failures, IPS triggers, whatever shows up
consistently in your logs.
No SIEM license, no external scripts, no scheduled tasks. Just FortiOS watching its own logs and acting on them. That's how it should work.