← Back to ProDirt Blog

FortiGate Auto-Ban: Automatically Block SSL VPN Brute Force Attackers

Built a FortiGate automation stitch that reads failed SSL VPN login events and immediately bans the source IP — no SIEM, no scripts, no third-party anything.

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.

ℹ️ Log ID note: 39424 is the standard SSL VPN auth failure ID on FortiOS 7.x. If you're on an older version, verify the log ID in your own traffic logs before deploying. Run 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.

⚠️ Watch your legitimate users. If you have users who frequently mistype passwords or are coming from dynamic IPs, a threshold trigger is safer than a single-failure ban. Also make sure your admin access IPs are in a trusted address group that's excluded from this logic — locking yourself out is a bad day.

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.