From 2b282c0c1c017c749a2992aeb713b40adbe988ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Busso?= <90727999+agustinbusso@users.noreply.github.com> Date: Wed, 26 Mar 2025 14:34:41 -0300 Subject: [PATCH 1/5] Work in progress --- ProcessMaker/Http/Kernel.php | 3 +- ProcessMaker/Http/Middleware/TrustHosts.php | 50 +++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 ProcessMaker/Http/Middleware/TrustHosts.php diff --git a/ProcessMaker/Http/Kernel.php b/ProcessMaker/Http/Kernel.php index c7d6d7ab8c..8331c0ade8 100644 --- a/ProcessMaker/Http/Kernel.php +++ b/ProcessMaker/Http/Kernel.php @@ -19,6 +19,7 @@ class Kernel extends HttpKernel \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, + Middleware\TrustHosts::class, Middleware\TrustProxies::class, Middleware\BrowserCache::class, ServerTimingMiddleware::class, @@ -87,7 +88,7 @@ class Kernel extends HttpKernel 'no-cache' => Middleware\NoCache::class, 'admin' => Middleware\IsAdmin::class, 'etag' => Middleware\Etag\HandleEtag::class, - 'file_size_check' => Middleware\FileSizeCheck::class, + 'file_size_check' => Middleware\FileSizeCheck::class ]; /** diff --git a/ProcessMaker/Http/Middleware/TrustHosts.php b/ProcessMaker/Http/Middleware/TrustHosts.php new file mode 100644 index 0000000000..5f80f36527 --- /dev/null +++ b/ProcessMaker/Http/Middleware/TrustHosts.php @@ -0,0 +1,50 @@ + + */ + public function hosts(): array + { + $trustedHost = $this->allSubdomainsOfApplicationUrl(); + + \Log::debug('TrustHosts middleware validating host', [ + 'host' => request()->getHost(), + 'trusted_pattern' => $trustedHost + ]); + + return [$trustedHost]; + } + + public function handle(\Illuminate\Http\Request $request, $next) + { + if ($request->hasHeader('X-Forwarded-Host')) { + $forwardedHost = $request->header('X-Forwarded-Host'); + $trustedPattern = $this->allSubdomainsOfApplicationUrl(); + + if (!$this->hostIsValid($forwardedHost, $trustedPattern)) { + \Log::warning('Rejected request with untrusted X-Forwarded-Host', [ + 'forwarded_host' => $forwardedHost, + 'trusted_pattern' => $trustedPattern + ]); + abort(400, 'Invalid Host Header'); + } + } + + return parent::handle($request, $next); + } + + protected function hostIsValid(string $host, string $pattern): bool + { + return preg_match('/' . str_replace('/', '\/', $pattern) . '/', $host) === 1; + } +} \ No newline at end of file From a29f76b472eccbf8c2c8be33e7ab94558aa6dfc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Busso?= <90727999+agustinbusso@users.noreply.github.com> Date: Thu, 27 Mar 2025 10:48:33 -0300 Subject: [PATCH 2/5] Remove log --- ProcessMaker/Http/Middleware/TrustHosts.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ProcessMaker/Http/Middleware/TrustHosts.php b/ProcessMaker/Http/Middleware/TrustHosts.php index 5f80f36527..32e492a0c3 100644 --- a/ProcessMaker/Http/Middleware/TrustHosts.php +++ b/ProcessMaker/Http/Middleware/TrustHosts.php @@ -16,12 +16,6 @@ class TrustHosts extends Middleware public function hosts(): array { $trustedHost = $this->allSubdomainsOfApplicationUrl(); - - \Log::debug('TrustHosts middleware validating host', [ - 'host' => request()->getHost(), - 'trusted_pattern' => $trustedHost - ]); - return [$trustedHost]; } From 2599d7b5ae7eb72bcbc81d7ee4b12dd24fbdff8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Busso?= <90727999+agustinbusso@users.noreply.github.com> Date: Thu, 27 Mar 2025 16:34:32 -0300 Subject: [PATCH 3/5] Move Request to use section --- ProcessMaker/Http/Middleware/TrustHosts.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ProcessMaker/Http/Middleware/TrustHosts.php b/ProcessMaker/Http/Middleware/TrustHosts.php index 32e492a0c3..68330a6e89 100644 --- a/ProcessMaker/Http/Middleware/TrustHosts.php +++ b/ProcessMaker/Http/Middleware/TrustHosts.php @@ -4,22 +4,17 @@ use Illuminate\Http\Middleware\TrustHosts as Middleware; use Closure; +use Illuminate\Http\Request; class TrustHosts extends Middleware { - - /** - * Get the host patterns that should be trusted. - * - * @return array - */ public function hosts(): array { $trustedHost = $this->allSubdomainsOfApplicationUrl(); return [$trustedHost]; } - public function handle(\Illuminate\Http\Request $request, $next) + public function handle(Request $request, $next) { if ($request->hasHeader('X-Forwarded-Host')) { $forwardedHost = $request->header('X-Forwarded-Host'); From 13b029ca694aea3604ae88d30872e87d7aeba2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Busso?= <90727999+agustinbusso@users.noreply.github.com> Date: Thu, 27 Mar 2025 16:50:31 -0300 Subject: [PATCH 4/5] Add tests for TrustHosts middleware --- .../Http/Middleware/TrustHostsTest.php | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tests/Feature/Http/Middleware/TrustHostsTest.php diff --git a/tests/Feature/Http/Middleware/TrustHostsTest.php b/tests/Feature/Http/Middleware/TrustHostsTest.php new file mode 100644 index 0000000000..262fab49eb --- /dev/null +++ b/tests/Feature/Http/Middleware/TrustHostsTest.php @@ -0,0 +1,61 @@ +middleware = new TrustHosts($this->app); + } + + public function test_valid_trusted_host() + { + // Set app URL for testing + Config::set('app.url', 'https://example.processmaker.net'); + + $request = Request::create('https://subdomain.example.processmaker.net'); + $request->headers->set('X-Forwarded-Host', 'subdomain.example.processmaker.net'); + + $response = $this->middleware->handle($request, function ($req) { + return response()->json(['status' => 'success']); + }); + + $this->assertEquals(200, $response->status()); + } + + public function test_invalid_trusted_host() + { + // Set app URL for testing + Config::set('app.url', 'https://example.processmaker.net'); + + $request = Request::create('https://malicious-site.com'); + $request->headers->set('X-Forwarded-Host', 'malicious-site.com'); + + $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class); + $this->expectExceptionMessage('Invalid Host Header'); + + $this->middleware->handle($request, function ($req) { + return response()->json(['status' => 'success']); + }); + } + + public function test_missing_forwarded_host() + { + $request = Request::create('https://example.processmaker.net'); + + $response = $this->middleware->handle($request, function ($req) { + return response()->json(['status' => 'success']); + }); + + $this->assertEquals(200, $response->status()); + } +} \ No newline at end of file From dc70ddeacc9cd929467f7bca315fe0abae292727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Busso?= <90727999+agustinbusso@users.noreply.github.com> Date: Fri, 4 Apr 2025 09:54:32 -0300 Subject: [PATCH 5/5] Test commit --- .env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/.env.example b/.env.example index 702c98dee6..ab98bd3acd 100644 --- a/.env.example +++ b/.env.example @@ -51,3 +51,4 @@ CUSTOM_EXECUTORS=false CACHE_SETTING_DRIVER=cache_settings CACHE_SETTING_PREFIX=settings: AI_ENABLE_RAG_COLLECTIONS=false +AI_ENABLE_AGENTS=false