What changed, and why it matters
This commit adds a server-side check to make sure users cannot set negative Lightning Network routing fees through the API. Previously, the API accepted negative values for base and proportional relay fees, which could cause a node to pay others when forwarding payments or create confusing, loss-inducing channel policies. The fix rejects such inputs with a validation error.
Review whether negative fee values could already exist in persisted channel configurations or database state, and consider adding similar validation at the business-logic layer (eclairApi.updateRelayFee) as defense in depth. No immediate emergency action is indicated.
Security signals we found
Input validation added for API fee parameters
Negative fee values previously accepted by updateRelayFee endpoint
Potential for fee policy manipulation leading to unintended payment forwarding losses
Fixes referenced issue #3204
Evidence from the diff
The patch modifies the updateRelayfee HTTP endpoint in Eclair’s API. Before forwarding feeBaseMsat and feeProportionalMillionths to eclairApi.updateRelayFee, it now validates that neither value is negative. If either is negative, the endpoint returns an Akka HTTP ValidationRejection with the message ‘Fees must be nonnegative’. This closes a gap where malformed or malicious API clients could set negative routing fees.
Changed components
eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Fees.scalaupdateRelayfee API endpointInspect captured patch +6 / −2
diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Fees.scala b/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Fees.scala
index d83f8a6..684c4a7 100644
--- a/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Fees.scala
+++ b/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Fees.scala
@@ -16,7 +16,7 @@
package fr.acinq.eclair.api.handlers
-import akka.http.scaladsl.server.Route
+import akka.http.scaladsl.server.{Route, ValidationRejection}
import fr.acinq.eclair.MilliSatoshi
import fr.acinq.eclair.api.Service
import fr.acinq.eclair.api.directives.EclairDirectives
@@ -36,7 +36,11 @@ trait Fees {
val updateRelayFee: Route = postRequest("updaterelayfee") { implicit t =>
withNodesIdentifier { nodes =>
formFields("feeBaseMsat".as[MilliSatoshi], "feeProportionalMillionths".as[Long]) { (feeBase, feeProportional) =>
- complete(eclairApi.updateRelayFee(nodes, feeBase, feeProportional))
+ if (feeBase.toLong < 0 || feeProportional < 0) {
+ reject(ValidationRejection("Fees must be nonnegative"))
+ } else {
+ complete(eclairApi.updateRelayFee(nodes, feeBase, feeProportional))
+ }
}
}
}
Why this scored 54/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.