api: redact the Authorization header before request headers are written to the debug2 log
Description
access_log() in api/api/middlewares.py passes the complete request header set to custom_logging(), which writes it at the debug2 level in api/api/alogging.py:
logger.debug2(f'Receiving headers {headers}')The same function already masks credential-bearing values elsewhere in the request:
if 'password' in query:
query['password'] = '****'
if 'password' in body:
body['password'] = '****'
if 'key' in body and '/agents' in path:
body['key'] = '****'No equivalent handling is applied to the headers, so Authorization is written verbatim alongside the rest.
The line dates from 4.9.0 and the migration to Connexion 3, Starlette and Uvicorn; it is absent in 4.8.x and still present on 5.x.
debug2 is not the default level (info) and selecting it requires editing api/configuration/api.yaml and restarting the manager, so this is a consistency gap in the logging path rather than a change in who can reach the data. It is worth closing because the surrounding code already expresses the intent that request credentials do not reach the log, and the headers are the one path where that intent is not carried through.
Suggested improvement
- Mask
Authorizationinaccess_log()alongside the existing masks, before the headers are handed tocustom_logging(). - Alternatively, log an allowlist of non-sensitive headers rather than the full dictionary. This is the more durable option: it covers
Cookieand any other credential-bearing header rather than one name, and it stays correct as headers are added.
Open decisions
- Denylist or allowlist. The allowlist is broader but needs a maintained list, and anything omitted from it silently stops being logged, which is a debugging regression for whoever set
debug2in the first place. - Whether the JSON log (
api.json) needs the same treatment, or whether the change belongs at a single point that both formats pass through. - Whether other daemons write request headers at debug levels through a similar path, so this can be closed once rather than per component.
Credit
Raised by Houssam Sahli at Malleum.
Source: wazuh/wazuh