GitHub Security Advisory: GHSA-p7fw-vjjm-2rwp
Package: github.com/lxc/incus/v6 (GO)
Severity: HIGH (CVSS 8.1)
CWE: CWE-863: Incorrect Authorization
Vulnerable versions: >= 6.12.0, <= 6.13.0
Patched in: 6.14.0

Summary: Incus creates nftables rules that partially bypass security options

Details:
### Summary

When using an ACL on a device connected to a bridge, Incus generates nftables rules that partially bypass security options `security.mac_filtering`, `security.ipv4_filtering` and `security.ipv6_filtering`. This can lead to ARP spoofing on the bridge and to fully spoof another VM/container on the same bridge.

### Details

In commit d137a063c2fe2a6983c995ba75c03731bee1557d, a few rules in the bridge input chain are moved to the top of the chain:

    ct state established,related accept

    iifname "{{.hostName}}" ether type arp accept
    iifname "{{.hostName}}" ip6 nexthdr ipv6-icmp icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert } accept

However, these rules accept packets that should be filtered and maybe dropped by later rules in the "MAC filtering", "IPv4 filtering" and "IPv6 filtering" snippets:

	iifname "{{.hostName}}" ether type arp arp saddr ether != {{.hwAddr}} drop
	iifname "{{.hostName}}" ether type ip6 icmpv6 type 136 @nh,528,48 != {{.hwAddrHex}} drop
    ...
    iifname "{{.hostName}}" ether type arp arp saddr ip != { {{.ipv4NetsList}} } drop
    ...
	iifname "{{.hostName}}" ether type ip6 icmpv6 type 136 {{.ipv6NetsPrefixList}} drop

Basically, the added rules partially bypass the security options `security.mac_filtering`, `security.ipv4_filtering` and `security.ipv6_filtering`. Doing so, they allow an attacker to perform ARP poisoning/spoofing attacks and send malicious Neighbor Advertisement (type 136).

### PoC

With this terraform infrastructure:

```
resource "incus_network_acl" "acl_allow_out" {
  name    = "acl-allow-out"
  egress = [
    {
      action           = "allow"
      destination      = "0.0.0.0-9.255.255.255,11.0.0.0-172.15.255.255,172.32.0.0-192.167.255.255,192.169.0.0-255.255.255.254"
      state            = "enabled"
    },
  ]
}
resource "incus_network_acl" "acl_allow_in" {
  name    = "acl-allow-in"
  ingress = [
    {
      action           = "allow"
      state            = "enabled"
    },
  ]
}

resource "incus_network" "br0" {
  name = "br0"
  config = {
    "ipv4.address"          = "10.0.0.1/24"
    "ipv4.nat"              = "true"
  }
}

resource "incus_instance" "machine1" {
  name  = "machine1"
  image = "images:archlinux/cloud"
  type = "virtual-machine"
  config = {
    "limits.memory" = "2GiB"
    "security.secureboot" = false
    "boot.autostart" = false
    "cloud-init.vendor-data" = <<-EOF
      #cloud-config
      package_update: true
      packages:
        - dhclient
        - tcpdump
      runcmd:
        - systemctl disable --now systemd.networkd.service
        - systemctl disable --now systemd.networkd.socket
    EOF
  }
  device {
    type = "disk"
    name = "root"
    properties = {
      pool = "default"
      path = "/"
      size = "64GiB"
    }
  }
  device {
    type = "nic"
    name = "eth0"
    properties = {
      network = incus_network.br0.name
      "security.ipv4_filtering" = true
      "security.acls" = join(",",
        [
          incus_network_a