Skip to content

fix(lightning): don't let the LNBits Host header break TLS verification#3899

Merged
davidleomay merged 1 commit into
developfrom
fix/lnbits-host-header-tls
Jun 17, 2026
Merged

fix(lightning): don't let the LNBits Host header break TLS verification#3899
davidleomay merged 1 commit into
developfrom
fix/lnbits-host-header-tls

Conversation

@Danswar

@Danswar Danswar commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Problem

GET /v1/lnurlp/:id (and lnurlw/lnurld) started returning 500 on PRD:

Hostname/IP does not match certificate's altnames: Host: api.dfx.swiss. is not in
the cert's altnames: DNS:localhost, DNS:lnd, DNS:vm-dfx-btc-inp-prd..., IP:10.0.1.4

Root cause

#3893 added a Host: <public hostname> header to the LNBits requests so LNBits builds
correct public LNURLs and passes its HTTPS check. But the HTTP client derives the TLS
SNI/servername from that Host header, so Node began validating the node's
self-signed cert against api.dfx.swiss.

On PRD, LND and LNBits are reached over the private IP and serve a cert whose SANs
are localhost / lnd / <vm-dns> / <private-ip>api.dfx.swiss is not among them, so
every LNURL call failed with ERR_TLS_CERT_ALTNAME_INVALID.

Fix

The cert is already pinned via the ca on the shared agent — that pin is the real
identity guarantee for a private self-signed node, and full chain verification is kept
(rejectUnauthorized stays on). The SAN/hostname match is redundant here and is exactly
what the spoofed Host header poisons, so we skip only the hostname check. The Host
header stays intact for LNBits, and the fix is host-agnostic, so it also holds once
dfxprd reaches LNBits as lnd.

Note / follow-up for review

This drops the hostname check (not chain verification) — a fast, safe unblock for the
live outage. The cleaner long-term fix is to add the public hostname to the node cert
SANs (tlsextradomain=api.dfx.swiss already exists in the dfxprd migration lnd.conf;
the live cert just predates it). Once the cert carries the SAN, this override can be
removed. @davidleomay — flagging since this is your #3893 area; happy to switch to the
SAN approach if you prefer.

#3893 added a 'Host: <public hostname>' header to the LNBits requests so
LNBits can build correct public LNURLs and pass its HTTPS check. But the
HTTP client derives the TLS servername from that Host header, so Node began
validating the node's self-signed cert against api.dfx.swiss.

LND and LNBits are reached over the private IP on PRD and serve a cert whose
SANs are localhost/lnd/<vm-dns>/<private-ip> — api.dfx.swiss is not among
them, so every /v1/lnurlp/* (and lnurlw/lnurld) call failed with
ERR_TLS_CERT_ALTNAME_INVALID (500).

The cert is already pinned via the CA on the shared agent, which is the real
identity guarantee for a private self-signed node; the SAN/hostname match is
redundant and is exactly what the spoofed Host header poisons. Skip the
hostname check (keep full chain verification) so the Host header stays intact
for LNBits while TLS no longer depends on it. Host-agnostic, so it also holds
once dfxprd reaches LNBits as 'lnd'.

@davidleomay davidleomay left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Just needs to survive 24h until Azure cutover — on dfxprd LNBits is HTTP so this becomes dead code. Cleanup tracked in DFXServer/server#408.

@davidleomay davidleomay merged commit 94cd87a into develop Jun 17, 2026
7 checks passed
@davidleomay davidleomay deleted the fix/lnbits-host-header-tls branch June 17, 2026 00:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants