Back to Networking Knowledge Hub

NetBird v0.76 - Securing the Local Daemon

v0.76 closes a high-severity local privilege escalation in the NetBird daemon's IPC interface. The daemon now verifies who is calling it using kernel-level identity checks, and privileged operations require actual privileges.

v0.76 is a small release. Most of it is client fixes and management server cleanup, the usual stuff. But one change in here fixes a problem that's been in NetBird since version 0.5.0 back in March 2022.

Here's the short version. The NetBird daemon would talk to anyone on the machine who asked. It never checked who was on the other end of the connection. In v0.76 it does, and that closes a local privilege escalation that could get an unprivileged user a root shell.

If you're running anything from 0.5.0 through 0.75.1, go ahead and upgrade. The rest of this is just what happened and what changed.

The Unauthenticated Daemon Socket

The NetBird client is split into two pieces: a daemon that runs with elevated privileges and does the real work, and a UI or CLI that tells the daemon what to do. They talk over a local gRPC interface. Pretty standard setup, and a lot of software works this way.

The problem was that the interface had no authentication on it at all. On Linux, macOS, and FreeBSD, the daemon exposed a Unix domain socket at with permissions, meaning world-readable and world-writable. On Windows it was an unauthenticated loopback TCP listener on . Either way, any local process running as any user could connect and call every RPC the daemon offered, with no credentials required.

From there, an unprivileged user could do quite a lot. Read the network configuration, rewrite security-relevant settings that live in root-owned config files, disconnect the VPN, re-register the device to an attacker-controlled NetBird account, and, with the right conditions on the management side, chain NetBird's built-in SSH server into a root shell. That last one is why the advisory rates this 8.8 High with the vector .

The full writeup is published as GHSA-qcpp-8vwj-hhwr , and there's no CVE assigned to it yet. We've also published a detailed security advisory that goes much deeper than I will here: exactly what an attacker could and couldn't do, what was never affected, mitigations if you can't upgrade right away, and how the disclosure was handled. If you're assessing your own exposure, that's the one to read. It was reported to us through responsible disclosure by @neewek , so a big thank you there.

How v0.76 Fixes It

The fix ( #6967 ) does two things: the daemon now knows who is calling it, and the operations that can actually hurt you now require real privileges.

The Daemon Checks Your ID

Identity comes from the kernel, not from anything the caller sends. That part matters, because anything the client says about itself can be faked.

  • Linux uses to pull the UID and GID of the connecting process.
  • macOS and FreeBSD use for the same thing.
  • Windows drops the loopback TCP listener entirely and moves to named pipes, reading the client token off the pipe. Admin daemons get pipes in the namespace with owner verification, and unprivileged daemons fall back to plain names.

From there, callers get sorted into privileged (root or administrator), unprivileged (a normal user), or same-as-daemon, which covers rootless containers and netstack mode and gets treated as privileged. If the daemon can't figure out who you are, it rejects the call instead of guessing.

On Windows there's one more detail worth flagging. The daemon migrates legacy addresses over to named pipes automatically, and it will not silently fall back to the old unauthenticated TCP listener if something goes wrong. Falling back would quietly reopen the exact hole this fixes, so it throws an error instead.

Privileged Operations Need Privileges

Of course, knowing who's calling only helps if you actually act on it. These operations now require root or administrator:

  • Enabling the SSH server
  • Enabling SSH root login
  • Disabling SSH authentication
  • Changing the management URL while SSH is enabled
  • Deregistering the peer while SSH is enabled

That list is the attack chain from earlier, gated at every step.

Going the other direction stays open on purpose. Disabling any of those features is still an unprivileged operation, and so is setting a value that's already set. There's no reason to make a regular user call to turn SSH root login off, and blocking that would just push people toward running more things as root than they need to.

The optional HTTP/JSON gateway that shipped in v0.75 gets the same treatment. It captures the connection identity, rejects spoofed forwarding headers, and encodes the real identity into the request metadata, so an external caller can't impersonate somebody else on the way through.

You'll Get a Useful Error, Not a gRPC Stack Trace

When the daemon turns something down, it returns with an payload that spells out what privileges the operation needed and what command to run to elevate. The CLI and the desktop app surface that as actual guidance.

This sounds like a small thing next to the security fix, but it's the part most people will actually run into. If you've got a script that enables the SSH server, it needs now, and the error will tell you that in plain language instead of handing you an opaque gRPC failure and letting you go dig through logs.

What This Means for Your Setup

Most people won't notice anything. Connecting, disconnecting, checking status, switching profiles, browsing peers and resources, all of that is unchanged and still works as a normal user.

Two groups should look a little closer:

If you automate NetBird configuration, check whether your scripts touch anything on that guarded list. Enabling the SSH server or changing the management URL on an SSH-enabled peer needs elevation now. Anything that only reads state or disables features is good to go as-is.

If you're on Windows and connect to the daemon directly, the transport changed from loopback TCP to named pipes. The bundled client handles this for you and migrates the address automatically. Custom tooling that was pointing at will need updating, and it's not going to fall back to TCP for you.

Do note that there's no config flag to turn any of this off, and that's on purpose. An opt-out would just put the vulnerability right back where it was.

Also in v0.76

The rest of the release is the normal maintenance pass.

Management server. Reverse-proxy domain targets now force routing-peer DNS resolution ( #6872 ), the Postgres path correctly reads the reverse-proxy service and target columns ( #6886 ), and user deletion now does an explicit account ID check ( #6944 ). That last one is security-adjacent too, so it's a good one to pick up.

Client. Interface names with dots in them are now escaped properly for sysctl configuration ( #6930 ), which doesn't affect many people, but it's rough if you're one of them. Route selection got unified in the route manager ( #6928 ), now parses as a proper Go duration ( #6947 ), and a UI crash on Windows builds without dark-mode support is fixed ( #6958 ). UI release binaries are also built with the production tag now ( #6898 ).

Mobile. Android picks up in the profile manager binding ( #6926 ) and peer detail export ( #6925 ), bringing it closer to what the desktop app got in v0.75. On iOS, tunnel reconfiguration callbacks are now serialized ( #6870 ).

Infrastructure. pprof is configurable in the signal component ( #6963 ), and the legacy Dex and Zitadel getting-started scripts are deprecated ( #6952 ).

Go Ahead and Upgrade

Every version from 0.5.0 through 0.75.1 is affected, on every platform we ship a daemon for. That's Linux, macOS, FreeBSD, and Windows. There's no partial mitigation here and no workaround that leaves the socket open, so upgrading to v0.76.0 is the fix.

If you manage a fleet, self-hosted servers and clients can be rolled separately, but the client is where this vulnerability lives. I do recommend prioritizing anything with untrusted local users on it: shared workstations, jump boxes, build agents, multi-user development machines, anything where somebody who isn't you has a shell.

With all that, go ahead and get updated. And if you ever find something like this in NetBird, the security policy is right there. We'd much rather hear from you directly.