Security & Safe Use
What a streaming host exposes, what protects it, and how to keep it on a network you trust.
A host is remote control of its machine. This page covers what protects it and how to harden it.
The short version
- Keep the host on a network you trust — your LAN, or a VPN that puts client and host on one network. Don't port-forward it to the internet.
- Anyone who streams drives the machine. They see the screen and type, click and play as if they sat at it.
- Pairing is the boundary. Keep it required (the default), use a strong console password, and review paired devices now and then.
- Leave GameStream (Moonlight) off unless you need it. It pairs over plain HTTP.
- Host on a gaming or dedicated PC, not on the machine that holds your most sensitive data.
What a client can do
A paired client's mouse, keyboard, controller and pen input land in your desktop session. It can alt-tab, open a terminal, read files or change settings — anything the signed-in session can. On Windows it also sees and answers the secure desktop (UAC prompts, the lock screen), which is what lets you unlock a headless box. Every remote-access and game-streaming tool works this way; treat access to a host like handing someone your unlocked keyboard.
Keep it on a trusted network
Punktfunk isn't built for direct internet exposure: there is no rate-limited public login gateway and no DDoS protection. To stream from outside, use a VPN (WireGuard, Tailscale, your router's VPN) that puts the client on the host's network — the tunnel then handles internet-facing authentication. To let a friend in, see Friends over the internet.
Windows network profiles. The installer opens its firewall ports on Private and Domain networks only. On a Public network — Windows' default for an unknown one — clients can't connect, and the host logs a warning at startup. If the installer finds your network set to Public, it offers to make it Private or to open the firewall for Public networks as well; take the second only for a network you trust. On the move, stop the service when you don't need it.
What protects you
There are no accounts and no cloud. Trust is set up device to device, then pinned.
| Layer | What it does |
|---|---|
| PIN pairing | A new device can't stream until it pairs or you approve it in the console. The host shows a 4-digit PIN, and the SPAKE2 exchange binds both device identities to it. Any attempt uses up the PIN, so an attacker gets one online guess and nothing to crack offline. See Pairing & Trust. |
| Pinned identities | Each side stores the other's certificate fingerprint. Reconnects are mutually authenticated, and a changed host fingerprint forces a new pairing. |
| Management API | A paired device can read status and the library, upload logs, and run the host actions its access level allows. Pairing, removing devices and session control need the admin token, which works only from the host machine. |
| Web console | The admin surface. It answers loopback, private and link-local addresses and a Tailscale tailnet, and refuses the internet. Anyone who reaches port 47992 can try to sign in. To keep it on the host machine, set PUNKTFUNK_UI_BIND=127.0.0.1 in host.env — the installers ask. |
| Console password | Generated at install on Linux and SteamOS (~/.config/punktfunk/web-password); chosen or generated by the Windows installer and readable only by Administrators and SYSTEM. After the first sign-in only an argon2id hash is kept, and wrong guesses are rate-limited per address. See Forgot your Password?. |
| Shared clipboard | Off on the host until an operator turns it on, and a per-host switch on each client. See Shared clipboard. |
Pairing policy: open hosts and trust-on-first-use
serve --open turns required pairing off: the host advertises pair=optional and accepts unpaired
clients. Clients then offer trust-on-first-use (TOFU): the first connect shows the host's
fingerprint, you compare it with the one the host logs at startup, and the client pins it. TOFU
can't catch an impostor on that first connect; PIN pairing can. Clients never offer TOFU to a host
that requires pairing, to one typed in by hand, or to one whose policy is unknown.
GameStream / Moonlight compatibility is the weak-crypto path
To serve stock Moonlight clients, the host can also speak GameStream. That plane doesn't get the protections above: it pairs over plain HTTP, and a client that doesn't take the newer control encryption falls back to a legacy scheme that can reuse GCM nonces. An attacker on your network could intercept a pairing or recover input. The host logs a warning whenever the plane is on.
GameStream is off on every install. Turn it on or off with GameStream in Host → Settings, then Restart Punktfunk. If the setting shows as locked, remove the pin where it was set:
| Pinned by | Remove it |
|---|---|
PUNKTFUNK_GAMESTREAM=1 in host.env | Delete the line. |
serve --gamestream in a unit drop-in or PUNKTFUNK_HOST_CMD | Drop the flag. See What the unit starts. |
The SteamOS installer's --gamestream, on an older install | Update the host; the update moves it into the console setting. |
| NixOS | services.punktfunk.host.gamestream = false; — this also closes the GameStream ports. |
If you need Moonlight, pair it on a network you trust — not one you share with strangers.
Choosing which machine to host on
Hardening limits what an attacker can do; the machine you pick limits what they get.
The Windows host runs as SYSTEM
To capture the secure desktop and stream with nobody signed in, the Windows service runs as
LocalSystem, as Sunshine and Apollo do. A compromised host, or a device you shouldn't have
paired, gets that level. What narrows it:
- User-mode drivers. The virtual display, both virtual gamepads and the virtual pointer are UMDF drivers, so a driver bug stays in a restricted service account. The audio endpoints are instances of Steam's signed streaming-audio drivers; Punktfunk ships no kernel-mode driver.
- Sealed channels. The frame ring and the gamepad channels pass between host and drivers as duplicated handles to unnamed objects, so no other local process can open them by name.
- Locked secrets. The management token, the host identity key and the console password are readable by Administrators and SYSTEM only.
None of this stops an attacker who is already an administrator — they own the machine anyway. A
virtual display is also a real monitor: any process in your session can capture it like a physical
one. The host streams the composed desktop, so a window hidden from recording tools
(WDA_EXCLUDEFROMCAPTURE) still appears, and DRM-protected video shows black.
Run the Windows host on a gaming or dedicated PC, not on your work laptop or the box with your password vault.
The Linux host runs as your user
The Linux host runs in your desktop session as your own account, not root, so a compromise is scoped to that user.
Plugins run code on your host
Installing a plugin is a trust decision, like installing any program. What limits it:
- Pinned catalog entries. Each entry names one version and its package hash, and the host checks the hash before installing. A package republished under the same version is refused.
- Badges say who reviewed it. Verified: unom reviewed that exact package in the built-in catalog. External source: from a catalog you added — pinned and hash-checked, curated by someone else. Unverified: installed by hand from a package spec; nothing pins it.
- Signed sources. Adding a catalog source trusts every plugin in it. Paste the source's
ed25519:key when you add it, and the host refuses any index from it that isn't signed. - Declared programs only. A package declares which programs the host may start for it and the shape of their arguments; a library entry only fills in values. Paths outside what the package declares or you allowed are refused, and folder grants are read-only unless you allow a write.
- A sandbox per plugin (Linux). Each plugin runs in its own
bubblewrap sandbox: an empty home, no network unless
its manifest asks, read access to the paths it declared and you allowed, and its own PID namespace,
so it can't reach the host process. Your
~/.ssh, browser profile and the host's credentials aren't in it. A box that can't build a sandbox runs no plugins and says so on the Troubleshooting page. - A token per plugin. A plugin can register itself and manage its own library entries, nothing more — never hooks or device admission.
- Windows: a separate account. The plugin runner runs as
NT AUTHORITY\LocalService, not SYSTEM. Plugins share that account, so one can interfere with another's files; the per-plugin sandbox is Linux-only.
Hardening checklist
- Keep pairing required — don't run
serve --openoutside a network you control. - Use a strong console password, and keep it out of shared documents.
- Firewall TCP 47992 to trusted addresses if your LAN is shared — it is the admin console.
- Stay on a trusted network — LAN or VPN. Never port-forward the host.
- Leave GameStream off unless a Moonlight client needs it (above).
- Install plugins you trust, Verified ones first.
- Review paired devices under Devices in the web console; remove any you don't recognize.
- Keep the host updated — security fixes ship as patch releases.
- On a portable host, stop the service on untrusted networks.
Reporting a vulnerability
Email security@punktfunk.com. Don't open a public issue, pull
request or chat post — that exposes other users before a fix exists. Include the component and
version (for example punktfunk-host 0.39.0 on Windows, and which client), the impact and the
attacker's position (same LAN, paired client, local account, admin), and steps to reproduce or a
log.
We acknowledge reports within 3 business days, agree a disclosure date with you, and credit you
when the fix ships unless you'd rather stay anonymous. The full policy is in
SECURITY.md.