Symptom

After install, a new Krill server appeared in the app and accepted API calls before the user had set a cluster PIN. Even with the wrong PIN-derived bearer token, POST requests returned 200. Beacons were also broadcasting immediately on install.

Root cause

Three bugs compounded:

  1. Open-access auth mode (Plugins.kt): when pin_derived_key does not exist yet, configureAuthentication() returned UserIdPrincipal("krill-open") for any bearer token — a deliberate “open until postinst sets one” fallback that was architecturally wrong. The postinst starts the server (systemctl restart krill.service) before the install script calls krill-reset-pin, creating a window where the server was fully open.

  2. Beacons sent without PIN (ServerBeaconSender.kt): sendSignal() sent a beacon with an empty clusterToken when no PIN was configured, advertising the server to the LAN immediately on startup.

  3. Incoming beacons accepted without PIN (ServerBeaconWireHandler.kt): the handler accepted beacons with an empty token when this server also had no PIN — two unpinned servers would connect to each other. The PIN check was also positioned after ServerIdentity.getSelfWithInfo(), making it impossible to unit-test without environment deps.

Also: /krill-token returned an empty string when no PIN was set, which the WASM client used as its auth token.

Fix

Prevention