diff --git a/packages/server/.env.example b/packages/server/.env.example index 84fc6ce782a..afa0ca5a0d4 100644 --- a/packages/server/.env.example +++ b/packages/server/.env.example @@ -37,6 +37,8 @@ PORT=3000 # DEBUG=true # LOG_PATH=/your_log_path/.flowise/logs # LOG_LEVEL=info #(error | warn | info | verbose | debug) +LOG_SANITIZE_BODY_FIELDS=password,pwd,pass,secret,token,apikey,api_key,accesstoken,access_token,refreshtoken,refresh_token,clientsecret,client_secret,privatekey,private_key,secretkey,secret_key,auth,authorization,credential,credentials +LOG_SANITIZE_HEADER_FIELDS=authorization,x-api-key,x-auth-token,cookie # TOOL_FUNCTION_BUILTIN_DEP=crypto,fs # TOOL_FUNCTION_EXTERNAL_DEP=moment,lodash # ALLOW_BUILTIN_DEP=false @@ -180,4 +182,4 @@ JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES=43200 ############################################################################################################ # PUPPETEER_EXECUTABLE_FILE_PATH='C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe' -# PLAYWRIGHT_EXECUTABLE_FILE_PATH='C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe' \ No newline at end of file +# PLAYWRIGHT_EXECUTABLE_FILE_PATH='C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe' diff --git a/packages/server/src/utils/logger.ts b/packages/server/src/utils/logger.ts index da64ee68f1f..d57398ed24b 100644 --- a/packages/server/src/utils/logger.ts +++ b/packages/server/src/utils/logger.ts @@ -193,25 +193,63 @@ requestLogger = createLogger({ ] }) +function getSensitiveBodyFields(): string[] { + return (process.env.LOG_SANITIZE_BODY_FIELDS as string) + .toLowerCase() + .split(',') + .map((f) => f.trim()) +} + +function getSensitiveHeaderFields(): string[] { + return (process.env.LOG_SANITIZE_HEADER_FIELDS as string) + .toLowerCase() + .split(',') + .map((f) => f.trim()) +} + +function sanitizeObject(obj: any): any { + if (!obj || typeof obj !== 'object') return obj + + const sensitiveFields = getSensitiveBodyFields() + const sanitized = Array.isArray(obj) ? [...obj] : { ...obj } + Object.keys(sanitized).forEach((key) => { + const lowerKey = key.toLowerCase() + if (sensitiveFields.includes(lowerKey)) { + sanitized[key] = '********' + } else if (typeof sanitized[key] === 'string') { + if (sanitized[key].includes('@') && sanitized[key].includes('.')) { + sanitized[key] = sanitized[key].replace(/([^@\s]+)@([^@\s]+)/g, '**********') + } + } + }) + + return sanitized +} + export function expressRequestLogger(req: Request, res: Response, next: NextFunction): void { const unwantedLogURLs = ['/api/v1/node-icon/', '/api/v1/components-credentials-icon/', '/api/v1/ping'] if (/\/api\/v1\//i.test(req.url) && !unwantedLogURLs.some((url) => new RegExp(url, 'i').test(req.url))) { - // Create a sanitized copy of the request body - const sanitizedBody = { ...req.body } - if (sanitizedBody.password) { - sanitizedBody.password = '********' - } + const sanitizedBody = sanitizeObject(req.body) + + const sanitizedQuery = sanitizeObject(req.query) + const sanitizedHeaders = { ...req.headers } + + const sensitiveHeaders = getSensitiveHeaderFields() + sensitiveHeaders.forEach((header) => { + if (sanitizedHeaders[header]) { + sanitizedHeaders[header] = '********' + } + }) - // Use the shared requestLogger with request-specific metadata const requestMetadata = { request: { method: req.method, url: req.url, - body: sanitizedBody, // Use sanitized body instead of raw body - query: req.query, + body: sanitizedBody, + query: sanitizedQuery, params: req.params, - headers: req.headers + headers: sanitizedHeaders } }