From b6e39ff2a297f7377709e50f533c0a30af78c894 Mon Sep 17 00:00:00 2001 From: JerrettDavis Date: Mon, 22 Jun 2026 19:33:27 -0500 Subject: [PATCH] fix(security): remove account identifiers from log output (CWE-312) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeQL cs/cleartext-storage-of-sensitive-information flagged two log statements that serialised account-scoped identifiers into structured log events — a concern for a financial application under PII logging policy. • FlowLedgerApiClient.GetJsonAsync: dropped {Url} from the LogError template; URLs may carry ?accountId= query parameters. The operation description alone is sufficient to identify the failed call. • FinancialSyncService.SeedRecurringFlowsAsync: dropped {ProviderId} from the LogWarning template; provider account IDs are account-scoped identifiers that should not appear in log output. The seed name provides enough diagnostic context. Resolves CodeQL alerts #1 and #2 (HIGH / cs/cleartext-storage-of-sensitive-information). Co-Authored-By: Claude Opus 4.6 --- .../Sync/FinancialSyncService.cs | 7 +++++-- src/FlowLedger.Web/ApiClient/FlowLedgerApiClient.cs | 8 ++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/FlowLedger.Infrastructure/Sync/FinancialSyncService.cs b/src/FlowLedger.Infrastructure/Sync/FinancialSyncService.cs index 210434d..b3bf853 100644 --- a/src/FlowLedger.Infrastructure/Sync/FinancialSyncService.cs +++ b/src/FlowLedger.Infrastructure/Sync/FinancialSyncService.cs @@ -318,9 +318,12 @@ private async Task SeedRecurringFlowsAsync( // Resolve domain account; skip seeds whose provider account wasn't synced. if (!providerIdToAccount.TryGetValue(seed.ProviderAccountId, out var account)) { + // Do not log the raw provider account ID — it is an account-scoped + // identifier that should not appear in log output (financial app PII policy). + // The seed name provides enough context for diagnostics. _logger.LogWarning( - "Skipping recurring flow seed '{Name}': provider account '{ProviderId}' not found.", - seed.Name, seed.ProviderAccountId); + "Skipping recurring flow seed '{Name}': associated provider account not found in synced set.", + seed.Name); continue; } diff --git a/src/FlowLedger.Web/ApiClient/FlowLedgerApiClient.cs b/src/FlowLedger.Web/ApiClient/FlowLedgerApiClient.cs index 2d4772a..5edbc73 100644 --- a/src/FlowLedger.Web/ApiClient/FlowLedgerApiClient.cs +++ b/src/FlowLedger.Web/ApiClient/FlowLedgerApiClient.cs @@ -88,9 +88,13 @@ private async Task ExecuteAsync(string operationDescription, Func> if (!response.IsSuccessStatusCode) { + // Do not log the raw URL here — it may contain account identifiers + // embedded as query parameters (e.g. ?accountId=...) that constitute + // PII in a financial application. The operation description is sufficient + // to identify the failed call without exposing account-scoped data. _logger.LogError( - "Non-success status {StatusCode} from {Url} during {Operation}", - (int)response.StatusCode, url, operationDescription); + "Non-success status {StatusCode} during {Operation}", + (int)response.StatusCode, operationDescription); throw new ApiClientException( $"Couldn't {operationDescription} (server returned {(int)response.StatusCode}).", response.StatusCode);