Tor: allow password auth on private networks (#3375)
What changed, and why it matters
This change expands when Eclair will allow password-based authentication to a Tor control port. Previously, only loopback addresses (the same machine) were considered safe enough for password auth. Now, private/site-local and link-local networks are also treated as local, so password auth is permitted there too. This is intentional for cluster deployments, but it slightly relaxes a security boundary around how Eclair talks to Tor.
Review whether cluster deployments using this feature protect the private network segment adequately. Ensure Tor control passwords are strong and the network segment is trusted, since password auth is less resistant to sniffing/credential compromise than safecookie. No immediate patch action is indicated by the commit itself.
Security signals we found
Relaxation of authentication-method restriction for Tor control port
Password authentication now permitted on site-local and link-local addresses
Original code explicitly rejected password auth for non-loopback addresses
Warning about cleartext onion private key remains for non-local addresses
Evidence from the diff
TorProtocolHandler.checkControlAddress() now treats isSiteLocalAddress and isLinkLocalAddress as local in addition to isLoopbackAddress. As a result, Password authentication is no longer rejected for private/site-local or link-local Tor control ports. The commit explicitly frames this as a feature for cluster deployments, not a vulnerability fix. The change is minimal (+1/-1) and the warning for non-local control ports remains for other cases.
Changed components
eclair-core/src/main/scala/fr/acinq/eclair/tor/TorProtocolHandler.scalaInspect captured patch +1 / −1
### eclair-core/src/main/scala/fr/acinq/eclair/tor/TorProtocolHandler.scala
@@ -73,7 +73,7 @@ class TorProtocolHandler(authentication: Authentication,
* password authentication on a local control port, and require safecookie otherwise, which authenticates the server.
*/
private def checkControlAddress(remoteAddress: InetSocketAddress): Unit = {
- val isLocal = Option(remoteAddress.getAddress).exists(_.isLoopbackAddress)
+ val isLocal = Option(remoteAddress.getAddress).exists(a => a.isLoopbackAddress|| a.isSiteLocalAddress || a.isLinkLocalAddress)
authentication match {
case _: Password if !isLocal => throw TorException(s"cannot use password authentication with a remote control port ($remoteAddress): use safecookie instead")
case _ if !isLocal => log.warning("tor control port {} is not local: our onion private key will be sent in cleartext over the network", remoteAddress)Why this scored 38/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.