VYPR
Low severityNVD Advisory· Published Mar 10, 2021· Updated May 29, 2025

October CMS vulnerable to Potential Host Header Poisoning on misconfigured servers

CVE-2021-21265

Description

October is a free, open-source, self-hosted CMS platform based on the Laravel PHP Framework. In October before version 1.1.2, when running on poorly configured servers (i.e. the server routes any request, regardless of the HOST header to an October CMS instance) the potential exists for Host Header Poisoning attacks to succeed. This has been addressed in version 1.1.2 by adding a feature to allow a set of trusted hosts to be specified in the application. As a workaround one may set the configuration setting cms.linkPolicy to force.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
october/backendPackagist
< 1.1.21.1.2

Affected products

1

Patches

4
555ab61f2313

Add app.trustedHosts config and force host checks on password reset (#5423)

https://github.com/octobercms/octoberBen ThomsonJan 4, 2021via ghsa
2 files changed · +46 1
  • config/app.php+31 1 modified
    @@ -43,6 +43,36 @@
     
         'url' => 'http://localhost',
     
    +    /*
    +    |--------------------------------------------------------------------------
    +    | Trusted hosts
    +    |--------------------------------------------------------------------------
    +    |
    +    | You may specify valid hosts for your application as an array or boolean
    +    | below. This helps prevent host header poisoning attacks.
    +    |
    +    | Possible values:
    +    |  - `true`: Trust the host specified in app.url, as well as the "www"
    +    |            subdomain, if applicable.
    +    |  - `false`: Disable the trusted hosts feature.
    +    |  - array: Defines the domains to be trusted hosts. Each item should be
    +    |           a string defining a domain, IP address, or a regex pattern.
    +    |
    +    | Example of array values:
    +    |
    +    |    'trustedHosts' => [
    +    |       'example.com',           // Matches just example.com
    +    |       'www.example.com',       // Matches just www.example.com
    +    |       '^(.+\.)?example\.com$', // Matches example.com and all subdomains
    +    |       'https://example.com',   // Matches just example.com
    +    |    ],
    +    |
    +    | NOTE: Even when set to `false`, this functionality is explicitly enabled
    +    | on the Backend password reset flow for security reasons.
    +    */
    +
    +    'trustedHosts' => true,
    +
         /*
         |--------------------------------------------------------------------------
         | Application Timezone
    @@ -148,7 +178,7 @@
         */
     
         'loadDiscoveredPackages' => false,
    -    
    +
         /*
         |--------------------------------------------------------------------------
         | Class Aliases
    
  • modules/backend/controllers/Auth.php+15 0 modified
    @@ -13,6 +13,7 @@
     use ValidationException;
     use Exception;
     use Config;
    +use October\Rain\Foundation\Http\Middleware\CheckForTrustedHost;
     
     /**
      * Authentication controller
    @@ -147,6 +148,20 @@ public function restore()
          */
         public function restore_onSubmit()
         {
    +        // Force Trusted Host verification on password reset link generation
    +        // regardless of config to protect against host header poisoning
    +        $trustedHosts = Config::get('app.trustedHosts', false);
    +        if ($trustedHosts === false) {
    +            $hosts = CheckForTrustedHost::processTrustedHosts(true);
    +
    +            if (count($hosts)) {
    +                Request::setTrustedHosts($hosts);
    +
    +                // Trigger the host validation logic
    +                Request::getHost();
    +            }
    +        }
    +
             $rules = [
                 'login' => 'required|between:2,255'
             ];
    
f638d3f78cfe

Add app.trustedHosts config and force host checks on password reset (#5423)

https://github.com/octobercms/octoberBen ThomsonJan 4, 2021via ghsa
2 files changed · +45 0
  • config/app.php+30 0 modified
    @@ -43,6 +43,36 @@
     
         'url' => 'http://localhost',
     
    +    /*
    +    |--------------------------------------------------------------------------
    +    | Trusted hosts
    +    |--------------------------------------------------------------------------
    +    |
    +    | You may specify valid hosts for your application as an array or boolean
    +    | below. This helps prevent host header poisoning attacks.
    +    |
    +    | Possible values:
    +    |  - `true`: Trust the host specified in app.url, as well as the "www"
    +    |            subdomain, if applicable.
    +    |  - `false`: Disable the trusted hosts feature.
    +    |  - array: Defines the domains to be trusted hosts. Each item should be
    +    |           a string defining a domain, IP address, or a regex pattern.
    +    |
    +    | Example of array values:
    +    |
    +    |    'trustedHosts' => [
    +    |       'example.com',           // Matches just example.com
    +    |       'www.example.com',       // Matches just www.example.com
    +    |       '^(.+\.)?example\.com$', // Matches example.com and all subdomains
    +    |       'https://example.com',   // Matches just example.com
    +    |    ],
    +    |
    +    | NOTE: Even when set to `false`, this functionality is explicitly enabled
    +    | on the Backend password reset flow for security reasons.
    +    */
    +
    +    'trustedHosts' => true,
    +
         /*
         |--------------------------------------------------------------------------
         | Application Timezone
    
  • modules/backend/controllers/Auth.php+15 0 modified
    @@ -13,6 +13,7 @@
     use ValidationException;
     use Exception;
     use Config;
    +use October\Rain\Foundation\Http\Middleware\CheckForTrustedHost;
     
     /**
      * Authentication controller
    @@ -147,6 +148,20 @@ public function restore()
          */
         public function restore_onSubmit()
         {
    +        // Force Trusted Host verification on password reset link generation
    +        // regardless of config to protect against host header poisoning
    +        $trustedHosts = Config::get('app.trustedHosts', false);
    +        if ($trustedHosts === false) {
    +            $hosts = CheckForTrustedHost::processTrustedHosts(true);
    +
    +            if (count($hosts)) {
    +                Request::setTrustedHosts($hosts);
    +
    +                // Trigger the host validation logic
    +                Request::getHost();
    +            }
    +        }
    +
             $rules = [
                 'login' => 'required|between:2,255'
             ];
    
f29865ae3db7

Add trusted hosts support to library (#549)

https://github.com/octobercms/libraryBen ThomsonJan 4, 2021via ghsa
4 files changed · +377 6
  • src/Foundation/Http/Kernel.php+7 6 modified
    @@ -10,13 +10,13 @@ class Kernel extends HttpKernel
          * @var array
          */
         protected $bootstrappers = [
    -        '\October\Rain\Foundation\Bootstrap\RegisterClassLoader',
    -        '\October\Rain\Foundation\Bootstrap\LoadEnvironmentVariables',
    -        '\October\Rain\Foundation\Bootstrap\LoadConfiguration',
    -        '\October\Rain\Foundation\Bootstrap\LoadTranslation',
    +        \October\Rain\Foundation\Bootstrap\RegisterClassLoader::class,
    +        \October\Rain\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    +        \October\Rain\Foundation\Bootstrap\LoadConfiguration::class,
    +        \October\Rain\Foundation\Bootstrap\LoadTranslation::class,
             \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
             \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    -        '\October\Rain\Foundation\Bootstrap\RegisterOctober',
    +        \October\Rain\Foundation\Bootstrap\RegisterOctober::class,
             \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
             \Illuminate\Foundation\Bootstrap\BootProviders::class,
         ];
    @@ -27,7 +27,8 @@ class Kernel extends HttpKernel
          * @var array
          */
         protected $middleware = [
    -        '\October\Rain\Foundation\Http\Middleware\CheckForMaintenanceMode',
    +        \October\Rain\Foundation\Http\Middleware\CheckForTrustedHost::class,
    +        \October\Rain\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
         ];
     
         /**
    
  • src/Foundation/Http/Middleware/CheckForTrustedHost.php+82 0 added
    @@ -0,0 +1,82 @@
    +<?php namespace October\Rain\Foundation\Http\Middleware;
    +
    +use Config;
    +use October\Rain\Http\Middleware\TrustHosts as BaseMiddleware;
    +
    +class CheckForTrustedHost extends BaseMiddleware
    +{
    +    /**
    +     * Get the host patterns that should be trusted.
    +     *
    +     * Trusted hosts should be defined in the `config/app.php` configuration file as an array, ie.:
    +     *
    +     *   'trustedHosts' => [
    +     *      'example.com',           // Matches just example.com
    +     *      'www.example.com',       // Matches just www.example.com
    +     *      '^(.+\.)?example\.com$', // Matches example.com and all subdomains
    +     *      'https://example.com',   // Matches just example.com
    +     *   ],
    +     *
    +     * or as a boolean - if true, it will trust the `app.url` host and all subdomains, if false it
    +     * will disable the feature entirely.
    +     *
    +     * Hosts can be defined as regex patterns for complex matching.
    +     *
    +     * @return array
    +     */
    +    public function hosts()
    +    {
    +        return self::processTrustedHosts(Config::get('app.trustedHosts', []));
    +    }
    +
    +    /**
    +     * Processes the trusted hosts into an array of patterns the match for host header checks.
    +     *
    +     * @param array|bool $hosts
    +     * @return array
    +     */
    +    public static function processTrustedHosts($hosts)
    +    {
    +        if ($hosts === true) {
    +            $url = Config::get('app.url', null);
    +
    +            // If no app URL is set, then disable trusted hosts.
    +            if (is_null($url)) {
    +                return [];
    +            }
    +
    +            // Allow both the domain and the `www` subdomain for app.url
    +            // regardless of the presence of www in the app.url value
    +            $host = parse_url($url, PHP_URL_HOST);
    +            if (preg_match('/^www\.(.*?)$/i', $host, $matches)) {
    +                $host = '^(www\.)?' . preg_quote($matches[1]) . '$';
    +            } else {
    +                $host = '^(www\.)?' . preg_quote($host) . '$';
    +            }
    +
    +            $hosts = [$host];
    +        } elseif ($hosts === false) {
    +            return [];
    +        }
    +
    +        $hosts = array_map(function ($host) {
    +            // If a URL is provided, extract the host
    +            if (filter_var($host, FILTER_VALIDATE_URL)) {
    +                $host = parse_url($host, PHP_URL_HOST);
    +            }
    +
    +            // Prepare IP address & plain hostname values to be processed by the regex filter
    +            if (
    +                filter_var($host, FILTER_VALIDATE_IP)
    +                || filter_var($host, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)
    +            ) {
    +                return '^' . preg_quote($host) . '$';
    +            }
    +
    +            // Allow everything else through as is
    +            return $host;
    +        }, $hosts);
    +
    +        return $hosts;
    +    }
    +}
    
  • src/Http/Middleware/TrustHosts.php+71 0 added
    @@ -0,0 +1,71 @@
    +<?php namespace October\Rain\Http\Middleware;
    +
    +use Illuminate\Contracts\Foundation\Application;
    +use Illuminate\Http\Request;
    +
    +abstract class TrustHosts
    +{
    +    /**
    +     * The application instance.
    +     *
    +     * @var \Illuminate\Contracts\Foundation\Application
    +     */
    +    protected $app;
    +
    +    /**
    +     * Create a new middleware instance.
    +     *
    +     * @param  \Illuminate\Contracts\Foundation\Application  $app
    +     * @return void
    +     */
    +    public function __construct(Application $app)
    +    {
    +        $this->app = $app;
    +    }
    +
    +    /**
    +     * Get the host patterns that should be trusted.
    +     *
    +     * @return array
    +     */
    +    abstract public function hosts();
    +
    +    /**
    +     * Handle the incoming request.
    +     *
    +     * @param  \Illuminate\Http\Request  $request
    +     * @param  callable  $next
    +     * @return \Illuminate\Http\Response
    +     */
    +    public function handle(Request $request, $next)
    +    {
    +        if ($this->shouldSpecifyTrustedHosts()) {
    +            Request::setTrustedHosts(array_filter($this->hosts()));
    +        }
    +
    +        return $next($request);
    +    }
    +
    +    /**
    +     * Determine if the application should specify trusted hosts.
    +     *
    +     * @return bool
    +     */
    +    protected function shouldSpecifyTrustedHosts()
    +    {
    +        return $this->app['config']->get('app.env') !== 'local'
    +            && $this->app->runningUnitTests() === false;
    +    }
    +
    +    /**
    +     * Get a regular expression matching the application URL and all of its subdomains.
    +     *
    +     * @return string|null
    +     */
    +    protected function allSubdomainsOfApplicationUrl()
    +    {
    +        if ($host = parse_url($this->app['config']->get('app.url'), PHP_URL_HOST)) {
    +            return '^(.+\.)?'.preg_quote($host).'$';
    +        }
    +    }
    +}
    
  • tests/Foundation/Http/Middleware/CheckForTrustedHostTest.php+217 0 added
    @@ -0,0 +1,217 @@
    +<?php
    +
    +use Illuminate\Http\Request;
    +use Illuminate\Routing\Route;
    +use Illuminate\Routing\RouteCollection;
    +use October\Rain\Router\UrlGenerator;
    +use October\Rain\Foundation\Http\Middleware\CheckForTrustedHost;
    +use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
    +
    +/**
    + * Adaptation of https://github.com/laravel/framework/pull/27206. Credit to @shrft for original implentation.
    + */
    +class CheckForTrustedHostTest extends TestCase
    +{
    +    protected static $orignalTrustHosts;
    +
    +    public static function setUpBeforeClass(): void
    +    {
    +        self::$orignalTrustHosts = Request::getTrustedHosts();
    +    }
    +
    +    public static function tearDownAfterClass(): void
    +    {
    +        Request::setTrustedHosts(self::$orignalTrustHosts);
    +    }
    +
    +    public function testTrustedHost()
    +    {
    +        $trustedHosts = ['octobercms.com'];
    +        $headers = ['HOST' => 'octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://octobercms.com', $url);
    +    }
    +
    +    public function testTrustedHostWwwSubdomain()
    +    {
    +        $trustedHosts = ['www.octobercms.com'];
    +        $headers = ['HOST' => 'www.octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://www.octobercms.com', $url);
    +    }
    +
    +    public function testTrustedHostWwwSubdomainFailure()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['octobercms.com'];
    +        $headers = ['HOST' => 'www.octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    public function testTrustedHostWwwRegex()
    +    {
    +        $trustedHosts = ['^(www\.)?octobercms\.com$'];
    +        $headers = ['HOST' => 'octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://octobercms.com', $url);
    +
    +        $headers = ['HOST' => 'www.octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://www.octobercms.com', $url);
    +    }
    +
    +    public function testTrustedIpHost()
    +    {
    +        $trustedHosts = ['127.0.0.1'];
    +        $headers = ['HOST' => '127.0.0.1'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://127.0.0.1', $url);
    +    }
    +
    +    public function testNoTrustedHostsSet()
    +    {
    +        $trustedHosts = false;
    +        $headers = ['HOST' => 'malicious.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://malicious.com', $url);
    +    }
    +
    +    public function testThrowExceptionForUntrustedHosts()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['octobercms.com'];
    +        $headers = ['HOST' => 'malicious.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    public function testThrowExceptionForUntrustedServerName()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['octobercms.com'];
    +        $headers = [];
    +        $servers = ['SERVER_NAME' => 'malicious.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    public function testThrowExceptionForUntrustedServerAddr()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['octobercms.com'];
    +        $headers = [];
    +        $servers = ['SERVER_ADDR' => 'malicious.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    public function testRegexTrustedHost()
    +    {
    +        $trustedHosts = ['^[a-z0-9]+\.octobercms\.com$'];
    +        $headers = ['HOST' => 'test123.octobercms.com'];
    +        $servers = [];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://test123.octobercms.com', $url);
    +
    +        $headers = ['HOST' => 'test456.octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://test456.octobercms.com', $url);
    +    }
    +
    +    public function testRegexFailTrustedHost()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['^[a-z0-9]+\.octobercms\.com$'];
    +        $headers = ['HOST' => 'test.123.octobercms.com'];
    +        $servers = [];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    public function testArrayTrustedHost()
    +    {
    +        $trustedHosts = ['test1.octobercms.com', 'test2.octobercms.com'];
    +        $headers = ['HOST' => 'test1.octobercms.com'];
    +        $servers = [];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://test1.octobercms.com', $url);
    +
    +        $headers = ['HOST' => 'test2.octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://test2.octobercms.com', $url);
    +    }
    +
    +    public function testArrayFailTrustedHost()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['test1.octobercms.com', 'test2.octobercms.com'];
    +        $headers = ['HOST' => 'test3.octobercms.com'];
    +        $servers = [];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    protected function createUrlGenerator($trustedHosts = [], $headers = [], $servers = [])
    +    {
    +        $middleware = $this->getMockBuilder(CheckForTrustedHost::class)
    +            ->disableOriginalConstructor()
    +            ->setMethods(['hosts', 'shouldSpecifyTrustedHosts'])
    +            ->getMock();
    +
    +        $middleware->expects($this->any())
    +            ->method('hosts')
    +            ->willReturn(CheckForTrustedHost::processTrustedHosts($trustedHosts));
    +
    +        $middleware->expects($this->any())
    +            ->method('shouldSpecifyTrustedHosts')
    +            ->willReturn(true);
    +
    +        $request = new Request;
    +
    +        foreach ($headers as $key => $val) {
    +            $request->headers->set($key, $val);
    +        }
    +
    +        foreach ($servers as $key => $val) {
    +            $request->server->set($key, $val);
    +        }
    +
    +        $middleware->handle($request, function () {
    +        });
    +
    +        $routes = new RouteCollection;
    +        $routes->add(new Route('GET', 'foo', [
    +            'uses' => 'FooController@index',
    +            'as' => 'foo_index',
    +        ]));
    +
    +        return new UrlGenerator($routes, $request);
    +    }
    +}
    
f86fcbcd066d

Add trusted hosts support to library (#549)

https://github.com/octobercms/libraryBen ThomsonJan 4, 2021via ghsa
4 files changed · +377 6
  • src/Foundation/Http/Kernel.php+7 6 modified
    @@ -10,13 +10,13 @@ class Kernel extends HttpKernel
          * @var array
          */
         protected $bootstrappers = [
    -        '\October\Rain\Foundation\Bootstrap\RegisterClassLoader',
    -        '\October\Rain\Foundation\Bootstrap\LoadEnvironmentVariables',
    -        '\October\Rain\Foundation\Bootstrap\LoadConfiguration',
    -        '\October\Rain\Foundation\Bootstrap\LoadTranslation',
    +        \October\Rain\Foundation\Bootstrap\RegisterClassLoader::class,
    +        \October\Rain\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    +        \October\Rain\Foundation\Bootstrap\LoadConfiguration::class,
    +        \October\Rain\Foundation\Bootstrap\LoadTranslation::class,
             \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
             \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    -        '\October\Rain\Foundation\Bootstrap\RegisterOctober',
    +        \October\Rain\Foundation\Bootstrap\RegisterOctober::class,
             \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
             \Illuminate\Foundation\Bootstrap\BootProviders::class,
         ];
    @@ -27,7 +27,8 @@ class Kernel extends HttpKernel
          * @var array
          */
         protected $middleware = [
    -        '\October\Rain\Foundation\Http\Middleware\CheckForMaintenanceMode',
    +        \October\Rain\Foundation\Http\Middleware\CheckForTrustedHost::class,
    +        \October\Rain\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
         ];
     
         /**
    
  • src/Foundation/Http/Middleware/CheckForTrustedHost.php+82 0 added
    @@ -0,0 +1,82 @@
    +<?php namespace October\Rain\Foundation\Http\Middleware;
    +
    +use Config;
    +use October\Rain\Http\Middleware\TrustHosts as BaseMiddleware;
    +
    +class CheckForTrustedHost extends BaseMiddleware
    +{
    +    /**
    +     * Get the host patterns that should be trusted.
    +     *
    +     * Trusted hosts should be defined in the `config/app.php` configuration file as an array, ie.:
    +     *
    +     *   'trustedHosts' => [
    +     *      'example.com',           // Matches just example.com
    +     *      'www.example.com',       // Matches just www.example.com
    +     *      '^(.+\.)?example\.com$', // Matches example.com and all subdomains
    +     *      'https://example.com',   // Matches just example.com
    +     *   ],
    +     *
    +     * or as a boolean - if true, it will trust the `app.url` host and all subdomains, if false it
    +     * will disable the feature entirely.
    +     *
    +     * Hosts can be defined as regex patterns for complex matching.
    +     *
    +     * @return array
    +     */
    +    public function hosts()
    +    {
    +        return self::processTrustedHosts(Config::get('app.trustedHosts', []));
    +    }
    +
    +    /**
    +     * Processes the trusted hosts into an array of patterns the match for host header checks.
    +     *
    +     * @param array|bool $hosts
    +     * @return array
    +     */
    +    public static function processTrustedHosts($hosts)
    +    {
    +        if ($hosts === true) {
    +            $url = Config::get('app.url', null);
    +
    +            // If no app URL is set, then disable trusted hosts.
    +            if (is_null($url)) {
    +                return [];
    +            }
    +
    +            // Allow both the domain and the `www` subdomain for app.url
    +            // regardless of the presence of www in the app.url value
    +            $host = parse_url($url, PHP_URL_HOST);
    +            if (preg_match('/^www\.(.*?)$/i', $host, $matches)) {
    +                $host = '^(www\.)?' . preg_quote($matches[1]) . '$';
    +            } else {
    +                $host = '^(www\.)?' . preg_quote($host) . '$';
    +            }
    +
    +            $hosts = [$host];
    +        } elseif ($hosts === false) {
    +            return [];
    +        }
    +
    +        $hosts = array_map(function ($host) {
    +            // If a URL is provided, extract the host
    +            if (filter_var($host, FILTER_VALIDATE_URL)) {
    +                $host = parse_url($host, PHP_URL_HOST);
    +            }
    +
    +            // Prepare IP address & plain hostname values to be processed by the regex filter
    +            if (
    +                filter_var($host, FILTER_VALIDATE_IP)
    +                || filter_var($host, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)
    +            ) {
    +                return '^' . preg_quote($host) . '$';
    +            }
    +
    +            // Allow everything else through as is
    +            return $host;
    +        }, $hosts);
    +
    +        return $hosts;
    +    }
    +}
    
  • src/Http/Middleware/TrustHosts.php+71 0 added
    @@ -0,0 +1,71 @@
    +<?php namespace October\Rain\Http\Middleware;
    +
    +use Illuminate\Contracts\Foundation\Application;
    +use Illuminate\Http\Request;
    +
    +abstract class TrustHosts
    +{
    +    /**
    +     * The application instance.
    +     *
    +     * @var \Illuminate\Contracts\Foundation\Application
    +     */
    +    protected $app;
    +
    +    /**
    +     * Create a new middleware instance.
    +     *
    +     * @param  \Illuminate\Contracts\Foundation\Application  $app
    +     * @return void
    +     */
    +    public function __construct(Application $app)
    +    {
    +        $this->app = $app;
    +    }
    +
    +    /**
    +     * Get the host patterns that should be trusted.
    +     *
    +     * @return array
    +     */
    +    abstract public function hosts();
    +
    +    /**
    +     * Handle the incoming request.
    +     *
    +     * @param  \Illuminate\Http\Request  $request
    +     * @param  callable  $next
    +     * @return \Illuminate\Http\Response
    +     */
    +    public function handle(Request $request, $next)
    +    {
    +        if ($this->shouldSpecifyTrustedHosts()) {
    +            Request::setTrustedHosts(array_filter($this->hosts()));
    +        }
    +
    +        return $next($request);
    +    }
    +
    +    /**
    +     * Determine if the application should specify trusted hosts.
    +     *
    +     * @return bool
    +     */
    +    protected function shouldSpecifyTrustedHosts()
    +    {
    +        return $this->app['config']->get('app.env') !== 'local'
    +            && $this->app->runningUnitTests() === false;
    +    }
    +
    +    /**
    +     * Get a regular expression matching the application URL and all of its subdomains.
    +     *
    +     * @return string|null
    +     */
    +    protected function allSubdomainsOfApplicationUrl()
    +    {
    +        if ($host = parse_url($this->app['config']->get('app.url'), PHP_URL_HOST)) {
    +            return '^(.+\.)?'.preg_quote($host).'$';
    +        }
    +    }
    +}
    
  • tests/Foundation/Http/Middleware/CheckForTrustedHostTest.php+217 0 added
    @@ -0,0 +1,217 @@
    +<?php
    +
    +use Illuminate\Http\Request;
    +use Illuminate\Routing\Route;
    +use Illuminate\Routing\RouteCollection;
    +use October\Rain\Router\UrlGenerator;
    +use October\Rain\Foundation\Http\Middleware\CheckForTrustedHost;
    +use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
    +
    +/**
    + * Adaptation of https://github.com/laravel/framework/pull/27206. Credit to @shrft for original implentation.
    + */
    +class CheckForTrustedHostTest extends TestCase
    +{
    +    protected static $orignalTrustHosts;
    +
    +    public static function setUpBeforeClass(): void
    +    {
    +        self::$orignalTrustHosts = Request::getTrustedHosts();
    +    }
    +
    +    public static function tearDownAfterClass(): void
    +    {
    +        Request::setTrustedHosts(self::$orignalTrustHosts);
    +    }
    +
    +    public function testTrustedHost()
    +    {
    +        $trustedHosts = ['octobercms.com'];
    +        $headers = ['HOST' => 'octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://octobercms.com', $url);
    +    }
    +
    +    public function testTrustedHostWwwSubdomain()
    +    {
    +        $trustedHosts = ['www.octobercms.com'];
    +        $headers = ['HOST' => 'www.octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://www.octobercms.com', $url);
    +    }
    +
    +    public function testTrustedHostWwwSubdomainFailure()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['octobercms.com'];
    +        $headers = ['HOST' => 'www.octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    public function testTrustedHostWwwRegex()
    +    {
    +        $trustedHosts = ['^(www\.)?octobercms\.com$'];
    +        $headers = ['HOST' => 'octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://octobercms.com', $url);
    +
    +        $headers = ['HOST' => 'www.octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://www.octobercms.com', $url);
    +    }
    +
    +    public function testTrustedIpHost()
    +    {
    +        $trustedHosts = ['127.0.0.1'];
    +        $headers = ['HOST' => '127.0.0.1'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://127.0.0.1', $url);
    +    }
    +
    +    public function testNoTrustedHostsSet()
    +    {
    +        $trustedHosts = false;
    +        $headers = ['HOST' => 'malicious.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://malicious.com', $url);
    +    }
    +
    +    public function testThrowExceptionForUntrustedHosts()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['octobercms.com'];
    +        $headers = ['HOST' => 'malicious.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    public function testThrowExceptionForUntrustedServerName()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['octobercms.com'];
    +        $headers = [];
    +        $servers = ['SERVER_NAME' => 'malicious.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    public function testThrowExceptionForUntrustedServerAddr()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['octobercms.com'];
    +        $headers = [];
    +        $servers = ['SERVER_ADDR' => 'malicious.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    public function testRegexTrustedHost()
    +    {
    +        $trustedHosts = ['^[a-z0-9]+\.octobercms\.com$'];
    +        $headers = ['HOST' => 'test123.octobercms.com'];
    +        $servers = [];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://test123.octobercms.com', $url);
    +
    +        $headers = ['HOST' => 'test456.octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://test456.octobercms.com', $url);
    +    }
    +
    +    public function testRegexFailTrustedHost()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['^[a-z0-9]+\.octobercms\.com$'];
    +        $headers = ['HOST' => 'test.123.octobercms.com'];
    +        $servers = [];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    public function testArrayTrustedHost()
    +    {
    +        $trustedHosts = ['test1.octobercms.com', 'test2.octobercms.com'];
    +        $headers = ['HOST' => 'test1.octobercms.com'];
    +        $servers = [];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://test1.octobercms.com', $url);
    +
    +        $headers = ['HOST' => 'test2.octobercms.com'];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $url = $urlGenerator->to('/');
    +
    +        $this->assertEquals('http://test2.octobercms.com', $url);
    +    }
    +
    +    public function testArrayFailTrustedHost()
    +    {
    +        $this->expectException(SuspiciousOperationException::class);
    +
    +        $trustedHosts = ['test1.octobercms.com', 'test2.octobercms.com'];
    +        $headers = ['HOST' => 'test3.octobercms.com'];
    +        $servers = [];
    +        $urlGenerator = $this->createUrlGenerator($trustedHosts, $headers, $servers);
    +        $urlGenerator->to('/');
    +    }
    +
    +    protected function createUrlGenerator($trustedHosts = [], $headers = [], $servers = [])
    +    {
    +        $middleware = $this->getMockBuilder(CheckForTrustedHost::class)
    +            ->disableOriginalConstructor()
    +            ->setMethods(['hosts', 'shouldSpecifyTrustedHosts'])
    +            ->getMock();
    +
    +        $middleware->expects($this->any())
    +            ->method('hosts')
    +            ->willReturn(CheckForTrustedHost::processTrustedHosts($trustedHosts));
    +
    +        $middleware->expects($this->any())
    +            ->method('shouldSpecifyTrustedHosts')
    +            ->willReturn(true);
    +
    +        $request = new Request;
    +
    +        foreach ($headers as $key => $val) {
    +            $request->headers->set($key, $val);
    +        }
    +
    +        foreach ($servers as $key => $val) {
    +            $request->server->set($key, $val);
    +        }
    +
    +        $middleware->handle($request, function () {
    +        });
    +
    +        $routes = new RouteCollection;
    +        $routes->add(new Route('GET', 'foo', [
    +            'uses' => 'FooController@index',
    +            'as' => 'foo_index',
    +        ]));
    +
    +        return new UrlGenerator($routes, $request);
    +    }
    +}
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.