From e59f16556af1e2ac5a926b44bd8781d162b30903 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Jul 2026 03:04:37 +0000 Subject: [PATCH] Log rejected sms-inbound webhook requests instead of dropping silently A token mismatch returned a bare 404 with no journal line at all, so "nothing is happening" was indistinguishable from "no request ever arrived" -- exactly what a stale provider URL looks like after a RELAY_TOKEN rotation (every full reinstall generates a new one, which invalidates whatever's still pasted into the DID's SMS tab until it's updated). Now logs the request's source IP and path length -- never the attempted path itself, since that's unauthenticated input from whoever hit the port, no reason to trust or echo it into the journal. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01JDyKC6Kdg7tofmYSmRtgww --- services/sms-inbound.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/services/sms-inbound.sh b/services/sms-inbound.sh index 7f1001d..028ace4 100644 --- a/services/sms-inbound.sh +++ b/services/sms-inbound.sh @@ -393,6 +393,19 @@ class Handler(BaseHTTPRequestHandler): # Constant-time compare: the token is a secret, and a naive == # leaks its prefix to anyone willing to time enough requests. if not TOKEN or not hmac.compare_digest(path.rstrip("/"), "/sms/" + TOKEN): + # A silent 404 here used to mean this line never printed at + # all -- "the box is up but nothing is happening" was + # indistinguishable from "no request ever arrived". Every + # RELAY_TOKEN rotation (a full reinstall generates a new one) + # invalidates whatever URL is still pasted into the provider, + # and that's exactly what this looks like: log something, + # never the attempted path itself (arbitrary attacker/scanner + # input, no reason to trust or echo it into the journal). + print("sms webhook: request with unrecognized path/token (len={}) from {} -- " + "does the URL pasted into the provider match this box's current " + "SMS_FORWARD_URL in /opt/sms-inbound/settings.env?".format( + len(path), self.client_address[0]), + flush=True) self._respond(404) return if rate_limited():