Skip to content

Security and threat model

Part Reachable by Main risks
Smart Proxy (TCP 25565) The internet, by design Malformed or flooding connections; players getting past bans
Web panel and API (8080) Your network; optionally the internet through a tunnel Password guessing, stolen sessions, cross-site attacks, a compromised account
Docker socket NetherNode only Whoever controls NetherNode controls Docker, which is root on the machine
Agent connections (/api/agent) Whoever can reach the panel Strangers trying to join; a compromised node
Minecraft servers Players, through the proxy Server and mod vulnerabilities; they run in containers without extra privileges
Modules (edge builds) The panel machine (web pages on 127.0.0.1) The software a module runs; each is its own unprivileged container with only its server’s folders, on a network shared only with that server
Data folder The machine’s users Worlds, backups, the database, and secret.key

The most important fact: an administrator account is effectively root on the machine, because NetherNode can start containers. Give accounts only to people you’d trust with the machine, give everyone else the lowest role that works, and turn on two-factor sign-in.

  • Handshakes are parsed with strict size limits before anything else happens, and the parsers are fuzz-tested.
  • Connection rates are limited per IP address.
  • Bans (by name, UUID or IP, per server or everywhere) are enforced before a login reaches a server or wakes a sleeping one.
  • Server ports are bound to loopback, so players can only reach servers through the proxy.
  • Passwords are hashed with Argon2id; sign-in is rate limited per address and per account, and wrong-password and unknown-account errors look the same.
  • Optional two-factor sign-in (TOTP) with single-use recovery codes; a code can’t be reused.
  • Sessions are random tokens in HttpOnly, SameSite=Lax cookies (Secure over HTTPS), stored only as hashes, renewed with use, and ended after 7 days idle or 30 days in all. New sessions on every sign-in; a password change signs out other devices.
  • Every request that changes something needs a CSRF token.
  • Responses carry a Content Security Policy that allows only NetherNode’s own scripts (no inline scripts), plus X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy, and HSTS over HTTPS.
  • Every API call checks the caller’s role on the server; the panel hiding a button is never the only protection.
  • File access is confined to each server’s folder; archive extraction rejects path tricks, links, and zip bombs.
  • Changes are recorded in the audit log, with who made them.

Agents on other machines connect out to the panel over a WebSocket, inside which both sides prove their keys and encrypt everything (Noise XX), so a proxy in between can’t read or change it.

  • An agent only joins with a single-use code that expires after 30 minutes. Codes are stored as hashes, and every attempt is audited.
  • Once joined, each side accepts only the other’s key. A removed node’s key is refused.
  • The handshake and every message are size-limited, and their parsers are fuzz-tested.
  • An agent only acts on its own servers, inside their folders, with the same container settings the panel uses. The panel checks everything an agent reports against its own records, so a node can’t speak for servers that aren’t on it.
  • Whoever controls the panel controls every node’s Docker. A compromised node can lie about its own servers, but can’t reach the panel’s database or other nodes.
  • To GitHub, about twice a day: a request for the newest release, unless turned off in Settings › Notifications. Nothing about the install is sent.
  • To Modrinth or CurseForge, once a day: a request for the versions of each modpack your servers run, under the same setting.
  • To the install counter, once a day: only if an owner turned counting on (what’s sent).
  • To Discord: the events you chose, if a webhook is set. On edge builds this includes servers’ join addresses and, for crashes, the last lines of their console; Discord then fetches the bot’s picture from GitHub and players’ heads from mc-heads.net (by their UUID).
  • To Mojang, Modrinth and CurseForge: lookups for player names, mods and modpacks when you use those features.
  • To Mojang, Paper, Purpur, Fabric, Quilt, Forge and NeoForge: version lists, when you create a server or pick a version.
  • To Mojang: players’ skins, for their heads in the panel (kept for a day).
  • To Modrinth’s and CurseForge’s image servers: mod and modpack icons. The panel fetches them so your browser doesn’t contact those sites.
  • To GitHub, when you update the panel or a node updates: the new image (from wherever the current one came from, GitHub’s registry by default) or the new release.
  • To GitHub’s container registry, on edge builds: module images, the first time a module starts. A BlueMap module also downloads the game’s client from Mojang for its textures.
  • To Mojang, the first time someone views an inventory for a Minecraft version: a download of that version’s game client, for its item icons. It’s kept in the data folder’s cache/minecraft, and only its textures are shown. Items from mods are drawn from the mod’s own file, which the panel copies from the server’s mods folder into cache/mods. Copies unused for two weeks are removed (game clients stay while a server runs that version), and Settings › Storage clears them.

RCON passwords, management secrets, the CurseForge API key, the Discord webhook URL, two-factor secrets and the panel’s key for talking to other machines are encrypted with secret.key (ChaCha20-Poly1305). Anything NetherNode decrypts is also masked in its logs, along with session cookies and password-like values.

  • Don’t expose port 8080 to the internet. Use your network, a VPN, or a Cloudflare Tunnel with Cloudflare Access in front, so strangers never reach the sign-in page.
  • Turn on two-factor sign-in, at least for owners and administrators.
  • Back up the data folder, including secret.key, somewhere else. Without the key, stored secrets can’t be read.
  • Keep NetherNode, Docker, and the host updated. The server images are pulled fresh when servers are created. Module images (edge builds) are pinned to exact versions in NetherNode itself and change only when NetherNode does.
  • Review the audit log now and then, and remove accounts that aren’t used.

Please report security problems privately to the maintainers rather than in a public issue, with steps to reproduce.