[GH-ISSUE #4351] Security: port policies are ignored when accessing docker containers #8488

Open
opened 2026-08-05 01:18:14 -04:00 by saavagebueno · 4 comments
Owner

Originally created by @AbsurdlySuspicious on GitHub (Aug 14, 2025).
Original GitHub issue: https://github.com/netbirdio/netbird/issues/4351

Describe the problem

Policies do not work when accessing docker containers on target host: all ports are freely accessible

To Reproduce

Steps to reproduce the behavior:

  1. Setup netbird on hosts A and B
  2. Setup docker containers on 3001 and 3002 on host A
  3. Setup netbird policy that allows access only to port 3001 from host B to host A
  4. Try to access port 3002 on host A from host B and receive successful response

Expected behavior

Port 3002 in example above is not accessible

Are you using NetBird Cloud?

No

NetBird version

0.54.1 on target host

Is any other VPN software installed?

No

Additional context

Since docker redirects packets in iptables nat PREROUTING chain acl rules in INPUT chain are not traversed. ACL should be enforced during prerouting and/or in DOCKER-USER chain.

This applies to iptables-legacy, I'm not sure if this is reproducible on nftables

Have you tried these troubleshooting steps?

  • Reviewed client troubleshooting (if applicable)
  • Checked for newer NetBird versions
  • Searched for similar issues on GitHub (including closed ones)
  • Restarted the NetBird client
  • Disabled other VPN software
  • Checked firewall settings
Originally created by @AbsurdlySuspicious on GitHub (Aug 14, 2025). Original GitHub issue: https://github.com/netbirdio/netbird/issues/4351 **Describe the problem** Policies do not work when accessing docker containers on target host: all ports are freely accessible **To Reproduce** Steps to reproduce the behavior: 1. Setup netbird on hosts A and B 2. Setup docker containers on 3001 and 3002 on host A 3. Setup netbird policy that allows access only to port 3001 from host B to host A 4. Try to access port 3002 on host A from host B and receive successful response **Expected behavior** Port 3002 in example above is not accessible **Are you using NetBird Cloud?** No **NetBird version** 0.54.1 on target host **Is any other VPN software installed?** No **Additional context** Since docker redirects packets in iptables nat PREROUTING chain acl rules in INPUT chain are not traversed. ACL should be enforced during prerouting and/or in DOCKER-USER chain. This applies to iptables-legacy, I'm not sure if this is reproducible on nftables **Have you tried these troubleshooting steps?** - [x] Reviewed [client troubleshooting](https://docs.netbird.io/how-to/troubleshooting-client) (if applicable) - [x] Checked for newer NetBird versions - [x] Searched for similar issues on GitHub (including closed ones) - [x] Restarted the NetBird client - [x] Disabled other VPN software - [x] Checked firewall settings
saavagebueno added the triage-needed label 2026-08-05 01:18:14 -04:00
Author
Owner

@AbsurdlySuspicious commented on GitHub (Mar 18, 2026):

Bumping this issue. This is not currently obvious that you need to configure DOCKER-USER chain manually to properly secure your peer. Given that ports mapping in compose does 0.0.0.0 listen by default I consider this as a quite serious issue.

Also related to #4233

<!-- gh-comment-id:4085248849 --> @AbsurdlySuspicious commented on GitHub (Mar 18, 2026): Bumping this issue. This is not currently obvious that you need to configure `DOCKER-USER` chain manually to properly secure your peer. Given that `ports` mapping in compose does `0.0.0.0` listen by default I consider this as a quite serious issue. Also related to #4233
Author
Owner

@lixmal commented on GitHub (Mar 23, 2026):

I'm unable to reproduce your issue.

NetBird installs rules in the mangle PREROUTING chain that mark allowed packets before Docker's DNAT rewrites the destination. The FORWARD chain then only accepts marked packets from the WireGuard interface:

  chain netbird-mangle-prerouting {
      iifname "wt0" ip saddr @nb0000001 tcp dport 3001 fib daddr type local meta mark set 0x1bd20
  }

  chain netbird-acl-forward-filter {
      meta mark 0x0001bd20 accept
      iifname "wt0" jump netbird-rt-fwd
      iifname "wt0" drop
  }

Unmarked traffic from wt0 (like port 3002) is dropped in the forward chain. This works identically with both iptables and nftables backends.

For the input path (docker listens on 0.0.0.0:3001), it would go through these rules:

  chain netbird-acl-input-filter {
      iifname "wt0" jump netbird-acl-input-rules
      iifname "wt0" drop
  }

  chain netbird-acl-input-rules {
      ct state established,related accept
      ip saddr @nb0000001 tcp dport 3001 accept
  }

Maybe you have something else going on. Providing a debug bundle would help

<!-- gh-comment-id:4111997594 --> @lixmal commented on GitHub (Mar 23, 2026): I'm unable to reproduce your issue. NetBird installs rules in the mangle PREROUTING chain that mark allowed packets before Docker's DNAT rewrites the destination. The FORWARD chain then only accepts marked packets from the WireGuard interface: ``` chain netbird-mangle-prerouting { iifname "wt0" ip saddr @nb0000001 tcp dport 3001 fib daddr type local meta mark set 0x1bd20 } chain netbird-acl-forward-filter { meta mark 0x0001bd20 accept iifname "wt0" jump netbird-rt-fwd iifname "wt0" drop } ``` Unmarked traffic from wt0 (like port 3002) is dropped in the forward chain. This works identically with both iptables and nftables backends. For the input path (docker listens on `0.0.0.0:3001`), it would go through these rules: ``` chain netbird-acl-input-filter { iifname "wt0" jump netbird-acl-input-rules iifname "wt0" drop } chain netbird-acl-input-rules { ct state established,related accept ip saddr @nb0000001 tcp dport 3001 accept } ``` Maybe you have something else going on. Providing a debug bundle would help
Author
Owner

@AbsurdlySuspicious commented on GitHub (Mar 25, 2026):

I've mentioned this in issue text:

This applies to iptables-legacy, I'm not sure if this is reproducible on nftables

It seems that this is not reproducible on nftables and iptables-nft, since nb creates custom tables with custom priorities there.

As far as I can tell, netbird does not touch nat table at all on native iptables

<!-- gh-comment-id:4126651219 --> @AbsurdlySuspicious commented on GitHub (Mar 25, 2026): I've mentioned this in issue text: > This applies to iptables-legacy, I'm not sure if this is reproducible on nftables It seems that this is not reproducible on nftables and iptables-nft, since nb creates custom tables with custom priorities there. As far as I can tell, netbird does not touch nat table at all on native iptables
Author
Owner

@lixmal commented on GitHub (Mar 25, 2026):

iptables-nft and iptables-legacy are handled exactly the same by netbird, I can't reproduce the issue there either.

I suppose what could happen is that docker inserts rules above netbird's after netbird has started. IPtables is notoriously bad for that, however we can probably enforce this a little bit stricter.

A debug bundle of your setup would help confirm what's going on

<!-- gh-comment-id:4127631767 --> @lixmal commented on GitHub (Mar 25, 2026): `iptables-nft` and `iptables-legacy` are handled exactly the same by netbird, I can't reproduce the issue there either. I suppose what _could_ happen is that docker inserts rules above netbird's _after_ netbird has started. IPtables is notoriously bad for that, however we can probably enforce this a little bit stricter. A debug bundle of your setup would help confirm what's going on
Sign in to join this conversation.
No Label triage-needed
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DYNR/netbird#8488