VYPR
Moderate severityOSV Advisory· Published Dec 9, 2025· Updated Dec 10, 2025

CNI Plugins Portmap nftables backend intercepts non-local traffic

CVE-2025-67499

Description

The CNI portmap plugin allows containers to emulate opening a host port, forwarding that traffic to the container. Versions 1.6.0 through 1.8.0 inadvertently forward all traffic with the same destination port as the host port when the portmap plugin is configured with the nftables backend, thus ignoring the destination IP. This includes traffic not intended for the node itself, i.e. traffic to containers hosted on the node. Containers that request HostPort forwarding can intercept all traffic destined for that port. This requires that the portmap plugin be explicitly configured to use the nftables backend. This issue is fixed in version 1.9.0. To workaround, configure the portmap plugin to use the iptables backend. It does not have this vulnerability.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

CNI portmap plugin with nftables backend in versions 1.6.0-1.8.0 forwards traffic by port only, ignoring destination IP, allowing container interception of unintended traffic.

Vulnerability

Details

The CNI portmap plugin's nftables backend, introduced in version 1.6.0, incorrectly constructs forwarding rules that only match on the destination port without considering the destination IP address [1]. This causes all traffic destined for the host on that port (including traffic intended for other containers or external hosts) to be redirected to the container requesting the HostPort mapping.

Exploitation

Prerequisites

Exploitation requires the portmap plugin to be explicitly configured with the nftables backend (the default is iptables) [1]. An attacker with the ability to create a container that requests HostPort forwarding can then intercept any traffic on that port, regardless of the intended recipient [1]. No additional authentication or network access is needed beyond standard container deployment permissions.

Impact

A malicious container can eavesdrop on communications destined for the same port on the host node. This includes traffic from other containers as well as external traffic that the host would normally process or forward [1]. The vulnerability undermines the isolation expected between containers sharing a node.

Mitigation

The issue is fixed in CNI plugins version 1.9.0 [2]. The fix, implemented in commit 9b3772e1, restructures the nftables chain to insert a jump to the hostports chain only after matching the destination IP address [3]. As a workaround, operators can configure the portmap plugin to use the iptables backend, which does not have this vulnerability [1].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/containernetworking/pluginsGo
>= 1.6.0, < 1.9.01.9.0

Affected products

3
  • v1.6.0, v1.6.1, v1.6.2, …+ 1 more
    • (no CPE)range: v1.6.0, v1.6.1, v1.6.2, …
    • (no CPE)range: >= 1.6.0, < 1.9.0
  • CNI/portmapllm-create
    Range: >=1.6.0, <=1.8.0

Patches

1
9b3772e1a7ab

portmap: ensure nftables backend only intercept local traffic

https://github.com/containernetworking/pluginsEtienne ChampetierNov 4, 2025via ghsa
2 files changed · +86 44
  • plugins/meta/portmap/portmap_nftables.go+40 34 modified
    @@ -26,9 +26,14 @@ import (
     const (
     	tableName = "cni_hostport"
     
    +	// Intermediate chain to jump to both 'hostip_hostports' and 'hostports'
    +	hostPortsAllChain = "hostports_all"
    +	// This chain was used for rules with hostIP, we do not use it anymore,
    +	// but we keep it to make upgrade transparent
     	hostIPHostPortsChain = "hostip_hostports"
    -	hostPortsChain       = "hostports"
    -	masqueradingChain    = "masquerading"
    +	// Chain containing all the rules
    +	hostPortsChain    = "hostports"
    +	masqueradingChain = "masquerading"
     )
     
     // The nftables portmap implementation is fairly similar to the iptables implementation:
    @@ -104,58 +109,69 @@ func (pmNFT *portMapperNFTables) forwardPorts(config *PortMapConf, containerNet
     	})
     
     	tx.Add(&knftables.Chain{
    -		Name: "hostports",
    +		Name: hostPortsChain,
     	})
    +
     	tx.Add(&knftables.Chain{
    -		Name: "hostip_hostports",
    +		Name: hostIPHostPortsChain,
     	})
     
    +	// setup intermediate chain
     	tx.Add(&knftables.Chain{
    -		Name:     "prerouting",
    -		Type:     knftables.PtrTo(knftables.NATType),
    -		Hook:     knftables.PtrTo(knftables.PreroutingHook),
    -		Priority: knftables.PtrTo(knftables.DNATPriority),
    +		Name: hostPortsAllChain,
     	})
    +
     	tx.Flush(&knftables.Chain{
    -		Name: "prerouting",
    +		Name: hostPortsAllChain,
     	})
    +
     	tx.Add(&knftables.Rule{
    -		Chain: "prerouting",
    +		Chain: hostPortsAllChain,
     		Rule: knftables.Concat(
    -			conditions,
     			"jump", hostIPHostPortsChain,
     		),
     	})
    +
     	tx.Add(&knftables.Rule{
    -		Chain: "prerouting",
    +		Chain: hostPortsAllChain,
     		Rule: knftables.Concat(
    -			conditions,
     			"jump", hostPortsChain,
     		),
     	})
     
     	tx.Add(&knftables.Chain{
    -		Name:     "output",
    +		Name:     "prerouting",
     		Type:     knftables.PtrTo(knftables.NATType),
    -		Hook:     knftables.PtrTo(knftables.OutputHook),
    +		Hook:     knftables.PtrTo(knftables.PreroutingHook),
     		Priority: knftables.PtrTo(knftables.DNATPriority),
     	})
     	tx.Flush(&knftables.Chain{
    -		Name: "output",
    +		Name: "prerouting",
     	})
     	tx.Add(&knftables.Rule{
    -		Chain: "output",
    +		Chain: "prerouting",
     		Rule: knftables.Concat(
     			conditions,
    -			"jump", hostIPHostPortsChain,
    +			"fib daddr type local",
    +			"jump", hostPortsAllChain,
     		),
     	})
    +
    +	tx.Add(&knftables.Chain{
    +		Name:     "output",
    +		Type:     knftables.PtrTo(knftables.NATType),
    +		Hook:     knftables.PtrTo(knftables.OutputHook),
    +		Priority: knftables.PtrTo(knftables.DNATPriority),
    +	})
    +	tx.Flush(&knftables.Chain{
    +		Name: "output",
    +	})
     	tx.Add(&knftables.Rule{
     		Chain: "output",
     		Rule: knftables.Concat(
     			conditions,
     			"fib daddr type local",
    -			"jump", hostPortsChain,
    +			"jump", hostPortsAllChain,
     		),
     	})
     
    @@ -184,8 +200,10 @@ func (pmNFT *portMapperNFTables) forwardPorts(config *PortMapConf, containerNet
     		}
     
     		if useHostIP {
    +			// we add the rule to 'hostports' instead of 'hostip_hostports'
    +			// as we want to remove 'hostip_hostports' long-term
     			tx.Add(&knftables.Rule{
    -				Chain: hostIPHostPortsChain,
    +				Chain: hostPortsChain,
     				Rule: knftables.Concat(
     					ipX, "daddr", e.HostIP,
     					e.Protocol, "dport", e.HostPort,
    @@ -243,7 +261,7 @@ func (pmNFT *portMapperNFTables) forwardPorts(config *PortMapConf, containerNet
     func (pmNFT *portMapperNFTables) checkPorts(config *PortMapConf, containerNet net.IPNet) error {
     	isV6 := (containerNet.IP.To4() == nil)
     
    -	var hostPorts, hostIPHostPorts, masqueradings int
    +	var hostPorts, masqueradings int
     	for _, e := range config.RuntimeConfig.PortMaps {
     		if e.HostIP != "" {
     			hostIP := net.ParseIP(e.HostIP)
    @@ -252,14 +270,8 @@ func (pmNFT *portMapperNFTables) checkPorts(config *PortMapConf, containerNet ne
     			if isV6 != isHostV6 {
     				continue
     			}
    -			if hostIP.IsUnspecified() {
    -				hostPorts++
    -			} else {
    -				hostIPHostPorts++
    -			}
    -		} else {
    -			hostPorts++
     		}
    +		hostPorts++
     	}
     	if *config.SNAT {
     		masqueradings = 1
    @@ -278,12 +290,6 @@ func (pmNFT *portMapperNFTables) checkPorts(config *PortMapConf, containerNet ne
     			return err
     		}
     	}
    -	if hostIPHostPorts > 0 {
    -		err := checkPortsAgainstRules(nft, hostIPHostPortsChain, config.ContainerID, hostIPHostPorts)
    -		if err != nil {
    -			return err
    -		}
    -	}
     	if masqueradings > 0 {
     		err := checkPortsAgainstRules(nft, masqueradingChain, config.ContainerID, masqueradings)
     		if err != nil {
    
  • plugins/meta/portmap/portmap_nftables_test.go+46 10 modified
    @@ -84,21 +84,22 @@ var _ = Describe("portmapping configuration (nftables)", func() {
     add table ip cni_hostport { comment "CNI portmap plugin" ; }
     add chain ip cni_hostport hostip_hostports
     add chain ip cni_hostport hostports
    +add chain ip cni_hostport hostports_all
     add chain ip cni_hostport masquerading { type nat hook postrouting priority 100 ; }
     add chain ip cni_hostport output { type nat hook output priority -100 ; }
     add chain ip cni_hostport prerouting { type nat hook prerouting priority -100 ; }
    -add rule ip cni_hostport hostip_hostports ip daddr 192.168.0.2 tcp dport 8083 dnat to 10.0.0.2:83 comment "icee6giejonei6so"
     add rule ip cni_hostport hostports tcp dport 8080 dnat to 10.0.0.2:80 comment "icee6giejonei6so"
     add rule ip cni_hostport hostports tcp dport 8081 dnat to 10.0.0.2:80 comment "icee6giejonei6so"
     add rule ip cni_hostport hostports udp dport 8080 dnat to 10.0.0.2:81 comment "icee6giejonei6so"
     add rule ip cni_hostport hostports udp dport 8082 dnat to 10.0.0.2:82 comment "icee6giejonei6so"
    +add rule ip cni_hostport hostports ip daddr 192.168.0.2 tcp dport 8083 dnat to 10.0.0.2:83 comment "icee6giejonei6so"
     add rule ip cni_hostport hostports tcp dport 8084 dnat to 10.0.0.2:84 comment "icee6giejonei6so"
    +add rule ip cni_hostport hostports_all jump hostip_hostports
    +add rule ip cni_hostport hostports_all jump hostports
     add rule ip cni_hostport masquerading ip saddr 10.0.0.2 ip daddr 10.0.0.2 masquerade comment "icee6giejonei6so"
     add rule ip cni_hostport masquerading ip saddr 127.0.0.1 ip daddr 10.0.0.2 masquerade comment "icee6giejonei6so"
    -add rule ip cni_hostport output a b jump hostip_hostports
    -add rule ip cni_hostport output a b fib daddr type local jump hostports
    -add rule ip cni_hostport prerouting a b jump hostip_hostports
    -add rule ip cni_hostport prerouting a b jump hostports
    +add rule ip cni_hostport output a b fib daddr type local jump hostports_all
    +add rule ip cni_hostport prerouting a b fib daddr type local jump hostports_all
     `)
     				actualRules := strings.TrimSpace(ipv4Fake.Dump())
     				Expect(actualRules).To(Equal(expectedRules))
    @@ -113,18 +114,53 @@ add rule ip cni_hostport prerouting a b jump hostports
     add table ip6 cni_hostport { comment "CNI portmap plugin" ; }
     add chain ip6 cni_hostport hostip_hostports
     add chain ip6 cni_hostport hostports
    +add chain ip6 cni_hostport hostports_all
     add chain ip6 cni_hostport output { type nat hook output priority -100 ; }
     add chain ip6 cni_hostport prerouting { type nat hook prerouting priority -100 ; }
    -add rule ip6 cni_hostport hostip_hostports ip6 daddr 2001:db8:a::1 tcp dport 8085 dnat to [2001:db8::2]:85 comment "icee6giejonei6so"
     add rule ip6 cni_hostport hostports tcp dport 8080 dnat to [2001:db8::2]:80 comment "icee6giejonei6so"
     add rule ip6 cni_hostport hostports tcp dport 8081 dnat to [2001:db8::2]:80 comment "icee6giejonei6so"
     add rule ip6 cni_hostport hostports udp dport 8080 dnat to [2001:db8::2]:81 comment "icee6giejonei6so"
     add rule ip6 cni_hostport hostports udp dport 8082 dnat to [2001:db8::2]:82 comment "icee6giejonei6so"
    +add rule ip6 cni_hostport hostports ip6 daddr 2001:db8:a::1 tcp dport 8085 dnat to [2001:db8::2]:85 comment "icee6giejonei6so"
     add rule ip6 cni_hostport hostports tcp dport 8086 dnat to [2001:db8::2]:86 comment "icee6giejonei6so"
    -add rule ip6 cni_hostport output c d jump hostip_hostports
    -add rule ip6 cni_hostport output c d fib daddr type local jump hostports
    -add rule ip6 cni_hostport prerouting c d jump hostip_hostports
    -add rule ip6 cni_hostport prerouting c d jump hostports
    +add rule ip6 cni_hostport hostports_all jump hostip_hostports
    +add rule ip6 cni_hostport hostports_all jump hostports
    +add rule ip6 cni_hostport output c d fib daddr type local jump hostports_all
    +add rule ip6 cni_hostport prerouting c d fib daddr type local jump hostports_all
    +`)
    +				actualRules = strings.TrimSpace(ipv6Fake.Dump())
    +				Expect(actualRules).To(Equal(expectedRules))
    +
    +				err = pmNFT.unforwardPorts(conf)
    +				Expect(err).NotTo(HaveOccurred())
    +
    +				expectedRules = strings.TrimSpace(`
    +add table ip cni_hostport { comment "CNI portmap plugin" ; }
    +add chain ip cni_hostport hostip_hostports
    +add chain ip cni_hostport hostports
    +add chain ip cni_hostport hostports_all
    +add chain ip cni_hostport masquerading { type nat hook postrouting priority 100 ; }
    +add chain ip cni_hostport output { type nat hook output priority -100 ; }
    +add chain ip cni_hostport prerouting { type nat hook prerouting priority -100 ; }
    +add rule ip cni_hostport hostports_all jump hostip_hostports
    +add rule ip cni_hostport hostports_all jump hostports
    +add rule ip cni_hostport output a b fib daddr type local jump hostports_all
    +add rule ip cni_hostport prerouting a b fib daddr type local jump hostports_all
    +`)
    +				actualRules = strings.TrimSpace(ipv4Fake.Dump())
    +				Expect(actualRules).To(Equal(expectedRules))
    +
    +				expectedRules = strings.TrimSpace(`
    +add table ip6 cni_hostport { comment "CNI portmap plugin" ; }
    +add chain ip6 cni_hostport hostip_hostports
    +add chain ip6 cni_hostport hostports
    +add chain ip6 cni_hostport hostports_all
    +add chain ip6 cni_hostport output { type nat hook output priority -100 ; }
    +add chain ip6 cni_hostport prerouting { type nat hook prerouting priority -100 ; }
    +add rule ip6 cni_hostport hostports_all jump hostip_hostports
    +add rule ip6 cni_hostport hostports_all jump hostports
    +add rule ip6 cni_hostport output c d fib daddr type local jump hostports_all
    +add rule ip6 cni_hostport prerouting c d fib daddr type local jump hostports_all
     `)
     				actualRules = strings.TrimSpace(ipv6Fake.Dump())
     				Expect(actualRules).To(Equal(expectedRules))
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.