Files
zoneminder/web/api/app/Lib/Error/ZmErrorHandler.php
T
Nic Boet 91b06f6d02 fix(api): keep credentials out of cake_error.log
Cake logs every uncaught exception, 4xx included, with "Request URL:"
and the full query string. API clients may authenticate with ?token=,
?auth= or ?user=&pass=, so a 401, 404 or 500 wrote a working access
token, auth hash or password to cake_error.log and error.log in
ZM_LOGDIR, both world-readable.

ZmErrorHandler extends Cake's ErrorHandler and replaces the values of
token, auth, pass and password with [redacted] in the logged message.
core.php uses it for both errors and exceptions.

Credentials in the query string still reach web server and proxy
access logs; that is outside the API code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit b80568847d)
2026-10-30 18:53:27 -04:00

42 lines
1.2 KiB
PHP

<?php
App::uses('ErrorHandler', 'Error');
/**
* Cake's ErrorHandler, without credentials in the log.
*
* Cake logs every uncaught exception (401, 404, 500, ...) to cake_error.log
* with "Request URL: " and the query string. API clients may authenticate with
* ?token=, ?auth=, ?user=&pass= in the query string, so each failed request
* wrote a working credential to a world-readable log.
*/
class ZmErrorHandler extends ErrorHandler {
/**
* Query parameters that carry a credential.
*
* @var array
*/
public static $secretParams = array('token', 'auth', 'pass', 'password');
/**
* Replace the values of credential parameters in a URL or in any text that
* contains one.
*
* @param string $text A URL, query string or log message
* @return string The text with each credential value replaced by [redacted]
*/
public static function redact($text) {
$names = implode('|', array_map('preg_quote', static::$secretParams));
// The URL Cake puts in error bodies is HTML-escaped, so & may be &amp;
return preg_replace('/((?:[?&]|&amp;)(?:'.$names.')=)[^&#\s]*/i', '$1[redacted]', $text);
}
/**
* {@inheritDoc}
*/
protected static function _getMessage($exception) {
return static::redact(parent::_getMessage($exception));
}
}