FortiGate BGP Route Redistribution Gone Wrong: How We Leaked Internal Routes to the Internet

FortiGate BGP Route Redistribution Gone Wrong: How We Leaked Internal Routes to the Internet

The ISP Call That Changed My Afternoon

Our ISP called us to report we were advertising a /24 that didn’t belong to us — a connected route had been redistributed into our eBGP session. I was sitting in our manufacturing plant security office, halfway through reviewing VPN logs, when the carrier engineer asked whether we intended to announce a test network from our edge FortiGate. We absolutely did not.

Our environment was running FortiOS 7.4.3 on the perimeter pair, with monitoring collectors on Ubuntu 22.04 and a small Python 3.11 script that pulled BGP neighbor state every five minutes. The script was fine. The firewall was stable. The problem was my configuration.

I made the wrong first assumption. I assumed the ISP had misread a dampened route or stale route-view output, because our public advertisements had been boring for years. Then I ran the local BGP checks and saw the test VLAN sitting in the outbound table. That was the moment the room got quiet.

Quiet is expensive.

The mistake was simple and ugly: the redistribute connected command had no route-map, so every interface subnet including a test VLAN was being advertised externally. In a plant network with OT jump hosts, management interfaces, guest wireless, temporary vendor segments, and public DMZ links all terminating on the FortiGate, “connected” was not a clean category. It was a junk drawer with BGP attached.

How Connected Redistribution Behaved on Our FortiGate

On FortiOS 7.4.3, connected redistribution under BGP does exactly what I asked it to do, not what I meant. If an interface has an active connected route in the routing table and BGP redistribution is enabled without policy, that connected network becomes eligible for advertisement. The FortiGate does not infer that a management VLAN is private, sensitive, temporary, or embarrassing.

Our intended export set was three provider-assigned public ranges. Our actual export set was 47 prefixes. After adding a prefix-list filter, advertised prefixes reduced from 47 to 3, only our allocated public ranges. That number landed hard because it gave us both the scope of the leak and a clean validation point after the fix.

What I didn’t expect was how ordinary the broken configuration looked during a quick review. There was no dramatic typo, no disabled route-map, no obvious neighbor error. The risk was hiding in a default-looking redistribution stanza that had probably passed through several maintenance windows because the BGP session stayed established.

BGP did not break. We did.

Here is the kind of configuration pattern that caused the exposure. I have removed our real ASNs and IPs, but the shape is the same as what I found on the edge firewall.

config router bgp
    set as 65010
    config neighbor
        edit "203.0.113.1"
            set remote-as 64500
        next
    end
    config redistribute "connected"
        set status enable
    end
end

That configuration is not sophisticated enough for an Internet edge. I now treat unfiltered redistribution as a production defect, even when the route table appears harmless at the time.

Why Missing Route Maps Created the Leak

The failure came from mixing routing convenience with security assumptions. My team had added connected redistribution during an earlier cleanup because it made public DMZ additions easier: create the interface, assign the subnet, and BGP picked it up. That saved a few minutes per change, but it also meant every future connected interface became a potential external announcement.

Manufacturing networks make this worse because we carry more “temporary” networks than anyone wants to admit. A vendor cell goes in for commissioning. A test VLAN appears for a line controller upgrade. A management subnet is built during a firewall migration and kept around because removing it requires a shutdown window. Those networks may be valid inside the plant, but they have no business crossing an eBGP boundary.

  • Management VLANs should never be eligible for external advertisement.
  • RFC1918 test networks should be blocked before BGP policy reaches a neighbor.
  • Public DMZ routes should be explicitly permitted by prefix and length.
  • Temporary interfaces need expiration dates and change tickets.
  • Outbound BGP policy should be reviewed whenever interfaces are added.

Convenience leaked the route.

The larger issue was ownership. Network changes and security review were close, but not identical, and that gap let a routing shortcut become an external exposure. I do not like designs where the safety of BGP export depends on everyone remembering which interfaces are safe forever. Memory is not a control.

You may also find this useful: Check out our guide on Python Network Config Backup: Automating Multi-Vendor Device Snapshots for more practical tips.

Build Prefix Lists and Route Maps for Export

The repair was to make export policy explicit. I built a prefix-list containing only the public ranges assigned to us, then attached it to a route-map, then referenced that route-map under connected redistribution. I also added a deny rule after the permitted prefixes so the policy read like a gate instead of a hint.

config router prefix-list
    edit "PL-BGP-EXPORT-PUBLIC"
        config rule
            edit 10
                set prefix 198.51.100.0 255.255.255.0
                set ge 24
                set le 24
            next
            edit 20
                set prefix 203.0.113.0 255.255.255.0
                set ge 24
                set le 24
            next
            edit 30
                set prefix 192.0.2.0 255.255.255.0
                set ge 24
                set le 24
            next
        end
    next
end

config router route-map
    edit "RM-BGP-EXPORT-CONNECTED"
        config rule
            edit 10
                set match-ip-address "PL-BGP-EXPORT-PUBLIC"
            next
            edit 100
                set action deny
            next
        end
    next
end

config router bgp
    config redistribute "connected"
        set status enable
        set route-map "RM-BGP-EXPORT-CONNECTED"
    end
end

I prefer exact prefix lengths on Internet export unless there is a documented reason to allow more-specifics. Broad prefix-list ranges age badly, especially when someone later adds a public NAT block, a cloud tunnel, or a temporary lab interface and assumes the old policy still expresses current intent.

The deny matters.

Some engineers argue that an implicit deny is enough. Technically, that may be true in the route-map behavior, but I like visible failure conditions on firewalls that multiple teams touch. When I read the config six months later at 2 a.m., I want the policy to show me what it refuses, not make me reconstruct defaults from memory.

Verify Advertisements Before Trusting the Fix

After applying the route-map, I did not trust the configuration screen. I checked the outbound BGP advertisements from the FortiGate CLI, confirmed the neighbor view with the ISP, and compared both against our monitoring output from the Ubuntu 22.04 collector. The Python 3.11 script was updated afterward to alert on any advertised prefix outside the approved list.

get router info bgp summary
get router info bgp neighbors 203.0.113.1 advertised-routes
get router info routing-table bgp
show router bgp

The first check told me the session stayed up. The second told me what we were actually offering to the ISP. The third helped confirm we were not learning anything unexpected during the cleanup. The fourth gave me the saved configuration view I needed for the incident record.

Verification beats confidence.

We also changed our review checklist. Any FortiGate interface addition on the perimeter now includes a BGP export impact check, even if the change request says “switchport only” or “temporary VLAN.” I do not care how harmless the ticket sounds. If the interface lands on a routing firewall, it deserves a routing review.

My opinion after this incident is blunt: connected redistribution on an Internet-facing FortiGate should be treated as unsafe until a route-map proves otherwise. FortiOS 7.4.3 gave us the tools we needed, but the firewall did not save us from a lazy export policy. That responsibility was ours.

A BGP route leak rarely starts with a complex failure; mine started with one missing route-map.

External References