matter-server is multi-homed — net1 is a macvlan on the IoT VLAN for Matter commissioning — and it binds its :5580 control WebSocket to 0.0.0.0. macvlan traffic bypasses Cilium policy, so the unauthenticated Matter control API was reachable from the whole IoT VLAN.
Verified today from edge-1 (on v30iot):
$ curl http://10.2.30.117:5580/
200
An unauthenticated IoT client could drive the Matter fabric over that socket — commission/remove/control devices, read fabric state. This is the sibling exposure flagged (report-only) when shelly-manager was fixed; you asked to close it too.
The fix
python-matter-server has a dedicated --listen-address flag, independent of --primary-interface. So the control socket and the Matter fabric interface are separable in the app's own CLI:
:5580 is then served only on the cluster pod CIDR. HA reaches it via the IPv4 ClusterIP Service (ws://matter-server.home-assistant.svc:5580/ws), which targets the pod IP.
Why nothing breaks
HA control path: ClusterIP (IPv4-only, 10.99.52.180) → podIP:5580. Intact.
Matter commissioning/discovery: unchanged — --primary-interface=net1 still pins link-local Matter ops to the IoT VLAN. --listen-address only moves the WebSocket bind; it does not touch the Matter SDK's interface selection.
No probes to reconcile: matter-server has none (a separate, deferred audit finding).
Confirmed before this change: current listeners are 0.0.0.0:5580 + [::]:5580; Service is single-stack IPv4, so binding the IPv4 pod IP loses no consumer.
Verified so far
kubectl kustomize builds; rendered args carry --listen-address=$(POD_IP) and the POD_IP downward-API env.
Post-merge checks (I'll run before calling it done)
curl http://<net1 ip>:5580/ from edge-1 now fails.
:5580 listens on the pod IP only (not 0.0.0.0).
HA's Matter integration reconnects; all 13 nodes re-subscribe.
Commissioning path (net1) still intact.
Still deferred (not this PR)
otbr:8081 has the same exposure and is next (via REST_HOST=$(POD_IP)), one at a time. The in-cluster CNP bypass and the no-probe gap remain report-only per your triage.
## The hole (same class as #142)
matter-server is multi-homed — `net1` is a macvlan on the **IoT VLAN** for Matter commissioning — and it binds its `:5580` control WebSocket to `0.0.0.0`. macvlan traffic bypasses Cilium policy, so the unauthenticated Matter control API was reachable from the whole IoT VLAN.
Verified today from `edge-1` (on v30iot):
```
$ curl http://10.2.30.117:5580/
200
```
An unauthenticated IoT client could drive the Matter fabric over that socket — commission/remove/control devices, read fabric state. This is the sibling exposure flagged (report-only) when shelly-manager was fixed; you asked to close it too.
## The fix
`python-matter-server` has a dedicated `--listen-address` flag, **independent** of `--primary-interface`. So the control socket and the Matter fabric interface are separable in the app's own CLI:
```yaml
args:
- --listen-address=$(POD_IP) # WebSocket → eth0 only
- --primary-interface=net1 # Matter commissioning → IoT VLAN (unchanged)
env:
- name: POD_IP
valueFrom: { fieldRef: { fieldPath: status.podIP } }
```
`:5580` is then served only on the cluster pod CIDR. HA reaches it via the IPv4 ClusterIP Service (`ws://matter-server.home-assistant.svc:5580/ws`), which targets the pod IP.
## Why nothing breaks
- **HA control path:** ClusterIP (IPv4-only, `10.99.52.180`) → podIP:5580. Intact.
- **Matter commissioning/discovery:** unchanged — `--primary-interface=net1` still pins link-local Matter ops to the IoT VLAN. `--listen-address` only moves the *WebSocket* bind; it does not touch the Matter SDK's interface selection.
- **No probes to reconcile:** matter-server has none (a separate, deferred audit finding).
Confirmed before this change: current listeners are `0.0.0.0:5580` + `[::]:5580`; Service is single-stack IPv4, so binding the IPv4 pod IP loses no consumer.
## Verified so far
`kubectl kustomize` builds; rendered args carry `--listen-address=$(POD_IP)` and the `POD_IP` downward-API env.
## Post-merge checks (I'll run before calling it done)
1. `curl http://<net1 ip>:5580/` from `edge-1` now **fails**.
2. `:5580` listens on the pod IP only (not `0.0.0.0`).
3. HA's Matter integration reconnects; all 13 nodes re-subscribe.
4. Commissioning path (net1) still intact.
## Still deferred (not this PR)
otbr:8081 has the same exposure and is next (via `REST_HOST=$(POD_IP)`), one at a time. The in-cluster CNP bypass and the no-probe gap remain report-only per your triage.
Same class as the shelly-manager bypass (#142). matter-server is
multi-homed — net1 is a macvlan on the IoT VLAN for Matter commissioning —
and it binds the :5580 control WebSocket to 0.0.0.0. macvlan traffic
bypasses Cilium policy, so the unauthenticated Matter control API was
reachable from the whole IoT VLAN.
Verified 2026-07-10 from edge-1 (on v30iot):
GET http://10.2.30.117:5580/ -> 200
An unauthenticated IoT client could drive the Matter fabric (commission /
remove / control devices, read fabric state) over that socket.
python-matter-server has a dedicated `--listen-address` flag, independent
of `--primary-interface`. Bind the WebSocket to the pod eth0 address
(--listen-address=$(POD_IP), POD_IP=status.podIP) so :5580 is served only
on the cluster pod CIDR. `--primary-interface=net1` is unchanged, so Matter
commissioning/discovery still uses the IoT VLAN. HA reaches the WebSocket
via the IPv4 ClusterIP Service (ws://matter-server...svc:5580/ws), which
targets the pod IP.
The Service is single-stack IPv4, so binding the IPv4 pod IP loses no
consumer. matter-server has no probes, so there is no probe path to
reconcile (that probe gap is a separate, deferred audit finding).
Verified: kubectl kustomize builds; rendered args carry
--listen-address=$(POD_IP) and the POD_IP downward-API env. Post-merge
checks to run: GET net1:5580 from the IoT VLAN now fails; :5580 listens on
the pod IP only; HA's Matter integration reconnects and all 13 nodes
re-subscribe; commissioning still works (net1 unchanged).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The hole (same class as #142)
matter-server is multi-homed —
net1is a macvlan on the IoT VLAN for Matter commissioning — and it binds its:5580control WebSocket to0.0.0.0. macvlan traffic bypasses Cilium policy, so the unauthenticated Matter control API was reachable from the whole IoT VLAN.Verified today from
edge-1(on v30iot):An unauthenticated IoT client could drive the Matter fabric over that socket — commission/remove/control devices, read fabric state. This is the sibling exposure flagged (report-only) when shelly-manager was fixed; you asked to close it too.
The fix
python-matter-serverhas a dedicated--listen-addressflag, independent of--primary-interface. So the control socket and the Matter fabric interface are separable in the app's own CLI::5580is then served only on the cluster pod CIDR. HA reaches it via the IPv4 ClusterIP Service (ws://matter-server.home-assistant.svc:5580/ws), which targets the pod IP.Why nothing breaks
10.99.52.180) → podIP:5580. Intact.--primary-interface=net1still pins link-local Matter ops to the IoT VLAN.--listen-addressonly moves the WebSocket bind; it does not touch the Matter SDK's interface selection.Confirmed before this change: current listeners are
0.0.0.0:5580+[::]:5580; Service is single-stack IPv4, so binding the IPv4 pod IP loses no consumer.Verified so far
kubectl kustomizebuilds; rendered args carry--listen-address=$(POD_IP)and thePOD_IPdownward-API env.Post-merge checks (I'll run before calling it done)
curl http://<net1 ip>:5580/fromedge-1now fails.:5580listens on the pod IP only (not0.0.0.0).Still deferred (not this PR)
otbr:8081 has the same exposure and is next (via
REST_HOST=$(POD_IP)), one at a time. The in-cluster CNP bypass and the no-probe gap remain report-only per your triage.