Summary
The updateExtClient handler in controllers/ext_client.go uses logic.GetExtClientByName(clientid) which searches ALL external clients across ALL networks, while every other ext_client endpoint correctly uses logic.GetExtClient(clientid, network) which scopes the lookup by network. This allows a user with access to one network to modify external clients belonging to a different network.
Vulnerable Code
In controllers/ext_client.go line 921:
func updateExtClient(w http.ResponseWriter, r *http.Request) {
var params = mux.Vars(r)
clientid := params["clientid"]
// BUG: Uses GetExtClientByName which searches ALL networks
oldExtClient, err := logic.GetExtClientByName(clientid)
GetExtClientByName in logic/clients.go (line 69) iterates ALL clients without network filtering:
func GetExtClientByName(ID string) (models.ExtClient, error) {
clients, err := GetAllExtClients() // All clients, all networks
for i := range clients {
if clients[i].ClientID == ID {
return clients[i], nil
}
}
}
Secure Comparison
Every other endpoint correctly uses the network-scoped lookup:
| Endpoint |
Line |
Lookup |
| GET (getExtClient) |
131 |
GetExtClient(clientid, network) ✅ |
| GET conf (getExtClientConf) |
172 |
GetExtClient(clientid, networkid) ✅ |
| POST (createExtClient) |
499 |
GetExtClient(extclient.ClientID, networkid) ✅ |
| PUT (updateExtClient) |
921 |
GetExtClientByName(clientid) ❌ |
| DELETE (deleteExtClient) |
1061 |
GetExtClient(clientid, network) ✅ |
Note: The {network} URL parameter IS available (line 948: gateway.NetID = params["network"]) but is not used for the initial client lookup.
Impact
- Severity: High - Cross-network boundary violation
- A user with access to Network A can modify external clients (VPN peers) belonging to Network B
- Can change client configuration including allowed IPs, DNS settings, public keys, and ACLs
- Affects network segmentation which is a core security feature
Suggested Fix
Replace line 921:
// Before (vulnerable):
oldExtClient, err := logic.GetExtClientByName(clientid)
// After (fixed):
network := params["network"]
oldExtClient, err := logic.GetExtClient(clientid, network)
Note
Per your SECURITY.md, vulnerabilities should be reported to info@netmaker.io. Since private vulnerability reporting is not enabled on GitHub, I'm filing this as an issue. Please feel free to convert this to a security advisory. I'm happy to coordinate on disclosure timeline.
Discovery
Found through automated security research comparing lookup function usage patterns across ext_client endpoints.
Summary
The
updateExtClienthandler incontrollers/ext_client.gouseslogic.GetExtClientByName(clientid)which searches ALL external clients across ALL networks, while every other ext_client endpoint correctly useslogic.GetExtClient(clientid, network)which scopes the lookup by network. This allows a user with access to one network to modify external clients belonging to a different network.Vulnerable Code
In
controllers/ext_client.goline 921:GetExtClientByNameinlogic/clients.go(line 69) iterates ALL clients without network filtering:Secure Comparison
Every other endpoint correctly uses the network-scoped lookup:
GetExtClient(clientid, network)✅GetExtClient(clientid, networkid)✅GetExtClient(extclient.ClientID, networkid)✅GetExtClientByName(clientid)❌GetExtClient(clientid, network)✅Note: The
{network}URL parameter IS available (line 948:gateway.NetID = params["network"]) but is not used for the initial client lookup.Impact
Suggested Fix
Replace line 921:
Note
Per your SECURITY.md, vulnerabilities should be reported to info@netmaker.io. Since private vulnerability reporting is not enabled on GitHub, I'm filing this as an issue. Please feel free to convert this to a security advisory. I'm happy to coordinate on disclosure timeline.
Discovery
Found through automated security research comparing lookup function usage patterns across ext_client endpoints.