Skip to content
Merged
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public async Task InvokeAsync(
// Check if path is excluded
if (IsExcludedPath(context.Request.Path))
{
_logger.LogDebug("Path {Path} is excluded from tenant validation", context.Request.Path);
_logger.LogDebug("Path {Path} is excluded from tenant validation", SanitizeForLog(context.Request.Path.Value));
await _next(context);
return;
}
Expand All @@ -65,7 +65,7 @@ public async Task InvokeAsync(
_logger.LogWarning(
"Tenant validation failed: {Error}. Path: {Path}",
validationResult.Error.Message,

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validationResult.Error.Message can contain user-controlled tenant identifiers (e.g., mismatch errors include header/subdomain/JWT values) and is currently logged without sanitization. To fully mitigate CWE-117/log-forging here, sanitize the {Error} value as well (or log a stable error code and keep the raw message only for the response).

Suggested change
validationResult.Error.Message,
SanitizeForLog(validationResult.Error.Message),

Copilot uses AI. Check for mistakes.
context.Request.Path);
SanitizeForLog(context.Request.Path.Value));

await WriteErrorResponse(context, validationResult.Error.Message, StatusCodes.Status403Forbidden);
return;
Expand All @@ -80,7 +80,7 @@ public async Task InvokeAsync(

if (tenantResult.IsFailure || tenantResult.Value is null)
{
_logger.LogWarning("Tenant {TenantId} not found or inactive", tenantId);
_logger.LogWarning("Tenant {TenantId} not found or inactive", SanitizeForLog(tenantId));
await WriteErrorResponse(
context,
TenantErrors.TenantNotFound(tenantId).Message,
Expand All @@ -90,7 +90,7 @@ await WriteErrorResponse(

if (!tenantResult.Value.IsActive)
{
_logger.LogWarning("Tenant {TenantId} is not active", tenantId);
_logger.LogWarning("Tenant {TenantId} is not active", SanitizeForLog(tenantId));
await WriteErrorResponse(
context,
TenantErrors.TenantAccessDenied(tenantId).Message,
Expand Down Expand Up @@ -205,6 +205,13 @@ private bool IsExcludedPath(PathString path)
pathValue.StartsWith(excluded, StringComparison.OrdinalIgnoreCase));
}

private static string SanitizeForLog(string? value)
{
if (string.IsNullOrEmpty(value))
return string.Empty;
return value.Replace("\r", "_").Replace("\n", "_").Replace("\t", "_");

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SanitizeForLog only replaces \r, \n, and \t. Log-injection can also be done with other control/newline characters (e.g., other char.IsControl chars, Unicode line separators, or ANSI escape sequences). Consider normalizing/replacing all control characters (e.g., via char.IsControl/\p{Cc}) so the helper provides a more comprehensive guarantee.

Suggested change
return value.Replace("\r", "_").Replace("\n", "_").Replace("\t", "_");
var sanitized = new System.Text.StringBuilder(value.Length);
foreach (var ch in value)
{
sanitized.Append(char.IsControl(ch) || ch == '\u2028' || ch == '\u2029' ? '_' : ch);
}
return sanitized.ToString();

Copilot uses AI. Check for mistakes.
}

private static async Task WriteErrorResponse(HttpContext context, string message, int statusCode)
{
context.Response.StatusCode = statusCode;
Expand Down
Loading