From bf0aa84fe77251868515b4497c30dbb2daeb0dbd Mon Sep 17 00:00:00 2001 From: djmaze <> Date: Sun, 25 Oct 2026 23:42:42 +0100 Subject: [PATCH] @ZaphodB fix(security): ?/Test integrity diagnostics answered without a login ServiceTest() ran Integrity::test() for any request. The test builds its base URL from $_SERVER['HTTP_HOST'], sends HEAD requests to it and prints the status and every response header. The client therefore chose where the server sent requests and read the result. Behind nginx the vhost is picked by server_name with the port ignored, so Host: : reaches the app and turns the diagnostic into a probe of the server's own TLS ports and their headers. Answer 404 unless an admin session is present. An admin's browser sends the real Host, so the diagnostic still works for the people it is for. Checked end to end with php -S (4 workers, no network): without a session the old code returned 200 with the diagnostics, this one returns 404 and nothing. --- .../v/0.0.0/app/libraries/snappymail/integrity.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/integrity.php b/snappymail/v/0.0.0/app/libraries/snappymail/integrity.php index e6d25e6bd..2397b9e37 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/integrity.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/integrity.php @@ -10,6 +10,16 @@ abstract class Integrity */ public static function test() { + // The integrity test sends HEAD requests to a URL built from the request's + // Host header and prints back every response header. Open to anyone, that + // lets a client choose the target (nginx ignores the port when matching + // server_name, so Host: : reaches it) and read the result. + // It is an admin diagnostic; an admin's own browser sends the real Host. + if (!\RainLoop\Api::Actions()->IsAdminLoggined(false)) { + \MailSo\Base\Http::StatusHeader(404); + return ''; + } + $result = static::phpVersion(); if ($result) { echo '

' . $result . '

';