Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export DEBUG="true"
export APP_ENCODING="UTF-8"
export APP_DEFAULT_LOCALE="en_US"
export APP_DEFAULT_TIMEZONE="UTC"
# SECURITY: Set this to your domain to prevent Host Header Injection attacks
# This is REQUIRED in production for password resets and other security features
export APP_FULL_BASE_URL="https://yourdomain.com"
export SECURITY_SALT="__SALT__"

# Uncomment these to define cache configuration via environment variables.
Expand Down
12 changes: 7 additions & 5 deletions config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@
* /.htaccess
* /webroot/.htaccess
* And uncomment the baseUrl key below.
* - fullBaseUrl - A base URL to use for absolute links. When set to false (default)
* CakePHP generates required value based on `HTTP_HOST` environment variable.
* However, you can define it manually to optimize performance or if you
* are concerned about people manipulating the `Host` header.
* - fullBaseUrl - SECURITY: A base URL to use for absolute links.
* IMPORTANT: This MUST be set in production to prevent Host Header Injection attacks
* that can compromise password reset and other security-critical features.
* Set this via APP_FULL_BASE_URL environment variable or directly in config.
* Example: 'https://yourdomain.com'
* When not set, the application will throw an exception in production mode.
* - imageBaseUrl - Web path to the public images/ directory under webroot.
* - cssBaseUrl - Web path to the public css/ directory under webroot.
* - jsBaseUrl - Web path to the public js/ directory under webroot.
Expand All @@ -57,7 +59,7 @@
'webroot' => 'webroot',
'wwwRoot' => WWW_ROOT,
//'baseUrl' => env('SCRIPT_NAME'),
'fullBaseUrl' => false,
'fullBaseUrl' => env('APP_FULL_BASE_URL', false),
'imageBaseUrl' => 'img/',
'cssBaseUrl' => 'css/',
'jsBaseUrl' => 'js/',
Expand Down
42 changes: 28 additions & 14 deletions config/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,29 +144,43 @@
}

/*
* Set the full base URL.
* SECURITY: Validate and set the full base URL.
* This URL is used as the base of all absolute links.
* Can be very useful for CLI/Commandline applications.
*
* IMPORTANT: In production, App.fullBaseUrl MUST be explicitly configured to prevent
* Host Header Injection attacks. Relying on the HTTP_HOST header can allow attackers
* to hijack password reset tokens and other security-critical operations.
*
* Set APP_FULL_BASE_URL in your environment variables or configure App.fullBaseUrl
* in config/app.php or config/app_local.php
*
* Example: APP_FULL_BASE_URL=https://yourdomain.com
*/
$fullBaseUrl = Configure::read('App.fullBaseUrl');
if (!$fullBaseUrl) {
$httpHost = env('HTTP_HOST');

/*
* When using proxies or load balancers, SSL/TLS connections might
* get terminated before reaching the server. If you trust the proxy,
* you can enable `$trustProxy` to rely on the `X-Forwarded-Proto`
* header to determine whether to generate URLs using `https`.
*
* See also https://book.cakephp.org/5/en/controllers/request-response.html#trusting-proxy-headers
* Only enforce fullBaseUrl requirement when we're in a web request context.
* This allows CLI tools (like PHPStan) to load the bootstrap without throwing.
*/
$trustProxy = false;

$s = null;
if (env('HTTPS') || ($trustProxy && env('HTTP_X_FORWARDED_PROTO') === 'https')) {
$s = 's';
if (!Configure::read('debug') && $httpHost) {
throw new \Cake\Core\Exception\CakeException(
'SECURITY: App.fullBaseUrl is not configured. ' .
'This is required in production to prevent Host Header Injection attacks. ' .
'Set APP_FULL_BASE_URL environment variable or configure App.fullBaseUrl in config/app.php'
);
}

$httpHost = env('HTTP_HOST');
/*
* Development mode fallback: Use HTTP_HOST for convenience.
* WARNING: This is ONLY safe in development. Never use this pattern in production!
*/
if ($httpHost) {
$s = null;
if (env('HTTPS')) {
$s = 's';
}
$fullBaseUrl = 'http' . $s . '://' . $httpHost;
}
unset($httpHost, $s);
Expand Down