From 9e711a502077a49db72843a5a2bdff8ba924c036 Mon Sep 17 00:00:00 2001 From: SashaMIT <33847880+SashaMIT@users.noreply.github.com> Date: Fri, 7 Aug 2026 03:05:13 +0700 Subject: [PATCH] Warn at startup when binding to a non-loopback address The multisig gRPC service is plaintext and unauthenticated: any caller that can reach the port can request signatures for every key this daemon holds. The default bind is loopback, which keeps that power on the local machine, but --address 0.0.0.0 silently exposes a signing oracle to the network. Log a prominent warning at startup when the bind address is not loopback so the exposure is a deliberate operator choice rather than a configuration slip. Mirrors the client-side warning for non-loopback tofnd hosts in axelarnetwork/axelar-core#2387. --- src/main.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 047e0762..5e08beab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ mod mnemonic; mod multisig; // gather logs; need to set RUST_LOG=info -use tracing::{info, span, Level}; +use tracing::{info, span, warn, Level}; // error handling pub type TofndResult = anyhow::Result; @@ -45,6 +45,18 @@ async fn main() -> TofndResult<()> { let cfg = parse_args()?; let socket_address = addr(&cfg.ip, cfg.port)?; + // The gRPC server is plaintext and unauthenticated: any caller that can + // reach the port can request signatures for every key this daemon holds. + // Loopback binds keep that power on the local machine, but a non-loopback + // bind exposes a signing oracle to the network. Warn loudly so exposing it + // is a deliberate operator choice rather than a silent configuration slip. + if !socket_address.ip().is_loopback() { + warn!( + "tofnd is binding to {}, which is not a loopback address: the gRPC service is plaintext and unauthenticated, so any party that can reach this port can request signatures with this validator's keys. Restrict network access to this port.", + socket_address.ip() + ); + } + // immediately read an encryption password from stdin let password = cfg.password_method.execute()?;