CVE-2023-22481 (PHP, published 2023-03-06T18:15Z)
Description: value: FreshRSS is a self-hosted RSS feed aggregator. When using the greader API, the provided password is logged in clear in `users/_/log_api.txt` in the case where the authentication fails. The issues occurs in `authorizationToUser()` in `greader.php`. If there is an issue with the request or the credentials, `unauthorized()` or `badRequest()` is called. Both these functions are printing the return of `debugInfo()` in the logs.  `debugInfo()` will return the content of the request. By default, this will be saved in `users/_/log_api.txt` and if the const `COPY_LOG_TO_SYSLOG` is true, in syslogs as well. Exploiting this issue requires having access to logs produced by FreshRSS. Using the information from the logs, a malicious individual could get users' API keys (would be displayed if the users fills in a bad username) or passwords.
Severity: nan (CVSS v3 base score: 5.5)
Weakness: CWE-532 \u2014 Insertion of Sensitive Information into Log File
Information written to log files can be of a sensitive nature and give valuable guidance to an attacker or expose sensitive user information.
Repository: https://github.com/FreshRSS/FreshRSS
Files changed:
Docker/FreshRSS.Apache.conf
cli/sensitive-log.sh
lib/lib_rss.php
p/api/fever.php
p/api/greader.php
Commit message: API avoid logging passwords (#5001)

* API avoid logging passwords
* Strip passwords and tokens from API logs
* Only log failed requests information when in debug mode

* Remove debug SHA

* Clean also Apache logs

* Better comments

* Redact also token parameters

* shfmt

* Simplify whitespace

* redacted

Vulnerable code:
CustomLog /dev/stdout combined_proxy
	Minz_Log::warning('Fever API: serviceUnavailable() ' . debugInfo(), API_LOG);
	return print_r(
		array(
			'INPUT' => $ORIGINAL_INPUT
		), true);
	return print_r(
		array(
			'INPUT' => $ORIGINAL_INPUT
		), true);
	Minz_Log::warning('badRequest() ' . debugInfo(), API_LOG);
	Minz_Log::warning('unauthorized() ' . debugInfo(), API_LOG);
	Minz_Log::warning('notImplemented() ' . debugInfo(), API_LOG);
	Minz_Log::warning('serviceUnavailable() ' . debugInfo(), API_LOG);
	Minz_Log::warning('checkCompatibility() ' . debugInfo(), API_LOG);
					Minz_Log::warning('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1], API_LOG);
					Minz_Log::warning('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1]);

Fixed code:
CustomLog "|/var/www/FreshRSS/cli/sensitive-log.sh" combined_proxy
#!/bin/sh
# Strips sensitive passwords from (Apache) logs

# For e.g. GNU systems such as Debian
# N.B.: `sed -u` is not available in BusyBox and without it there are buffering delays (even with stdbuf)
sed -Eu 's/([?&])(Passwd|token)=[^& \t]+/\1\2=redacted/ig' 2>/dev/null ||

	# For systems with gawk (not available by default in Docker of Debian or Alpine) or with BuzyBox such as Alpine
	$(which gawk || which awk) -v IGNORECASE=1 '{ print gensub(/([?&])(Passwd|token)=[^& \t]+/, "\\1\\2=redacted", "g") }'
/**
 * Remove passwords in FreshRSS logs.
 * See also ../cli/sensitive-log.sh for Web server logs.
 * @param array<string,mixed>|string $log
 * @return array<string,mixed>|string
 */
function sensitive_log($log) {
	if (is_array($log)) {
		foreach ($log as $k => $v) {
			if (in_array($k, ['api_key', 'Passwd', 'T'])) {
				$log[$k] = '██';
			} else {
				$log[$k] = sensitive_log($v);
			}
		}
	} elseif (is_string($log)) {
		$log = preg_replace([
				'/\b(auth=.*?\/)[^&]+/i',
				'/\b(Passwd=)[^&]+/i',
				'/\b(Authorization)[^&]+/i',
			], '$1█', $log);
	}
	return $log;
}

	Minz_Log::warning('Fever API: service unavailable!');
	Minz_Log::debug('Fever API: serviceUnavailable() ' . debugInfo(), API_LOG);
	$log = sensitive_log([
			'INPUT' => $ORIGINAL_INPUT,
		]);
	return print_r($log, true);
	$log = sensitive_log([
			'INPUT' => $ORIGINAL_INPUT,
		]);
	return print_r($log, true);
	Minz_Log::warning('GReader API: ' . __METHOD__, API_LOG);
	Minz_Log::debug('badRequest() ' . debugInfo(), API_LOG);
	Minz_Log::warning('GReader API: ' . __METHOD__, API_LOG);
	Minz_Log::debug('unauthorized() ' . debugInfo(), API_LOG);
	Minz_Log::warning('GReader API: ' . __METHOD__, API_LOG);
	Minz_Log::debug('notImplemented() ' . debugInfo(), API_LOG);
	Minz_Log::warning('GReader API: ' . __METHOD__, API_LOG);
	Minz_Log::debug('serviceUnavailable() ' . debugInfo(), API_LOG);
	Minz_Log::warning('GReader API: ' . __METHOD__, API_LOG);
	Minz_Log::debug('checkCompatibility() ' . debugInfo(), API_LOG);
					Minz_Log::warning('Invalid API authorisation for user ' . $user);