Severity: Medium / defense-in-depth · Source: 2026-08 security audit (M1 + M2), MCP .NET port
Location: dotnet/src/LightningEnable.Mcp/Program.cs (wallet HttpClient registrations, ~:180/:214), dotnet/src/LightningEnable.Mcp/Services/LndWalletService.cs:64 (scheme handling) and :70 (macaroon header).
Two related issues on the credential-bearing LND client:
-
Redirect-following client (M1). The wallet HttpClients use the framework-default handler (AllowAutoRedirect=true). LndWalletService.cs:70 attaches the LND admin macaroon as the custom header Grpc-Metadata-macaroon, which .NET does not strip on a cross-origin redirect (only the typed Authorization header is stripped). A 302 from a hostile hop in front of the LND REST endpoint replays the full admin macaroon to the redirect target → node takeover, bypassing the MCP confirmation/budget gates. The repo already applies AllowAutoRedirect=false to the L402 + discover_api clients for exactly this reason — just not to the ones carrying node credentials. (Python is unaffected: httpx defaults follow_redirects=False.)
-
Cleartext http:// + inert TLS knobs (M2). LndWalletService.cs:64 accepts an explicit http:// host with no warning, so the admin macaroon travels in cleartext on every request. The class docblock advertises LND_TLS_CERT_PATH / LND_SKIP_TLS_VERIFY, but neither is ever read in the .NET project — so an operator with LND's default self-signed cert has no working remedy and is nudged toward http://. (Python implements skip_tls_verify, but that disables validation wholesale.)
Precondition: an attacker already in the LND transport path (compromised reverse proxy, DNS hijack, MITM on a plaintext/verify-disabled connection). Hence defense-in-depth rather than remote exposure — but on node-draining credentials.
Fix: builder.Services.ConfigureHttpClientDefaults(b => b.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler { AllowAutoRedirect = false })) (keep the SSRF ConnectCallback on the agent-facing clients); implement LND_TLS_CERT_PATH cert-pinning via SslOptions.RemoteCertificateValidationCallback and honour LND_SKIP_TLS_VERIFY only with a loud warning; reject/warn on http:// for any non-loopback host; until implemented, delete the misleading LND_TLS_CERT_PATH/LND_SKIP_TLS_VERIFY lines from the .NET docblock. Add a regression test asserting a wallet-endpoint 302 is surfaced as an error, not followed.
Severity: Medium / defense-in-depth · Source: 2026-08 security audit (M1 + M2), MCP .NET port
Location:
dotnet/src/LightningEnable.Mcp/Program.cs(walletHttpClientregistrations, ~:180/:214),dotnet/src/LightningEnable.Mcp/Services/LndWalletService.cs:64(scheme handling) and:70(macaroon header).Two related issues on the credential-bearing LND client:
Redirect-following client (M1). The wallet
HttpClients use the framework-default handler (AllowAutoRedirect=true).LndWalletService.cs:70attaches the LND admin macaroon as the custom headerGrpc-Metadata-macaroon, which .NET does not strip on a cross-origin redirect (only the typedAuthorizationheader is stripped). A302from a hostile hop in front of the LND REST endpoint replays the full admin macaroon to the redirect target → node takeover, bypassing the MCP confirmation/budget gates. The repo already appliesAllowAutoRedirect=falseto the L402 + discover_api clients for exactly this reason — just not to the ones carrying node credentials. (Python is unaffected: httpx defaultsfollow_redirects=False.)Cleartext http:// + inert TLS knobs (M2).
LndWalletService.cs:64accepts an explicithttp://host with no warning, so the admin macaroon travels in cleartext on every request. The class docblock advertisesLND_TLS_CERT_PATH/LND_SKIP_TLS_VERIFY, but neither is ever read in the .NET project — so an operator with LND's default self-signed cert has no working remedy and is nudged towardhttp://. (Python implementsskip_tls_verify, but that disables validation wholesale.)Precondition: an attacker already in the LND transport path (compromised reverse proxy, DNS hijack, MITM on a plaintext/verify-disabled connection). Hence defense-in-depth rather than remote exposure — but on node-draining credentials.
Fix:
builder.Services.ConfigureHttpClientDefaults(b => b.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler { AllowAutoRedirect = false }))(keep the SSRF ConnectCallback on the agent-facing clients); implementLND_TLS_CERT_PATHcert-pinning viaSslOptions.RemoteCertificateValidationCallbackand honourLND_SKIP_TLS_VERIFYonly with a loud warning; reject/warn onhttp://for any non-loopback host; until implemented, delete the misleadingLND_TLS_CERT_PATH/LND_SKIP_TLS_VERIFYlines from the .NET docblock. Add a regression test asserting a wallet-endpoint 302 is surfaced as an error, not followed.