commit ccd0fb34b4f024eb9651fc9ee26104a67d33e5b0
parent fbf6112d5c4c87ea61ca05c10299c860317de406
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 6 Aug 2026 16:07:39 +0200
fix base_url check: handle NULL, enforce '/' termination
Diffstat:
1 file changed, 44 insertions(+), 3 deletions(-)
diff --git a/src/backend/paivana-httpd_pay.c b/src/backend/paivana-httpd_pay.c
@@ -163,6 +163,49 @@ PAIVANA_HTTPD_payment_create (struct MHD_Connection *connection)
/**
+ * Is @a website a URL below our own base URL?
+ *
+ * Used to bound where a client may send itself once it has paid for
+ * an order that carries no fulfillment URL of its own: without this
+ * the client picks the redirect target and the site the access cookie
+ * is minted for.
+ *
+ * The comparison is on whole path segments. A bare prefix test would
+ * accept "https://example.com.evil.net/" for a base URL of
+ * "https://example.com", because strip_trailing_slashes() has removed
+ * the '/' that used to terminate it.
+ *
+ * @param website candidate URL, from the client
+ * @return true if @a website is our base URL or something below it
+ */
+static bool
+under_our_base_url (const char *website)
+{
+ size_t blen;
+
+ if (NULL == PH_base_url)
+ {
+ /* BASE_URL is optional; without it we have nothing to compare
+ against and must not guess. Note that dereferencing it here
+ used to be an unconditional crash. */
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Cannot check the target of an order without a"
+ " fulfillment URL: BASE_URL is not configured\n");
+ return false;
+ }
+ blen = strlen (PH_base_url);
+ if (0 != strncmp (website,
+ PH_base_url,
+ blen))
+ return false;
+ /* PH_base_url has no trailing '/' (strip_trailing_slashes()), so
+ require the boundary here rather than inheriting it. */
+ return ('\0' == website[blen]) ||
+ ('/' == website[blen]);
+}
+
+
+/**
* Check that the @a contract that was paid is reasonable for the
* request in @a ph, that is that we would indeed consider this
* contract to apply for the website and duration indicated
@@ -221,9 +264,7 @@ check_contract (struct PayRequest *ph,
return false;
}
if ( ( (NULL == target) &&
- (0 != strncmp (ph->website,
- PH_base_url,
- strlen (PH_base_url))) ) ||
+ (! under_our_base_url (ph->website)) ) ||
(! TALER_is_web_url (ph->website)) )
{
/* Bad: the order has no fulfillment URL, and on top of that