diff --git a/.generator/src/generator/templates/api_client.j2 b/.generator/src/generator/templates/api_client.j2 index 61d6ee4152fb..9ac71ff36324 100644 --- a/.generator/src/generator/templates/api_client.j2 +++ b/.generator/src/generator/templates/api_client.j2 @@ -140,10 +140,10 @@ module {{ module_name }} sleep_time end - #Redact api and app key in the request header + #Redact api key, app key, and Authorization (Bearer) header in the request log def sanitize_request_header(request_header) sanitized_headers= request_header.dup - keys_to_redact = ["DD-API-KEY", "DD-APPLICATION-KEY"] + keys_to_redact = ["DD-API-KEY", "DD-APPLICATION-KEY", "Authorization"] keys_to_redact.each do |key_to_redact| if sanitized_headers.key?(key_to_redact) sanitized_headers[key_to_redact] = "REDACTED" diff --git a/lib/datadog_api_client/api_client.rb b/lib/datadog_api_client/api_client.rb index 86b4f6dad628..c8b7c698f6d1 100644 --- a/lib/datadog_api_client/api_client.rb +++ b/lib/datadog_api_client/api_client.rb @@ -151,10 +151,10 @@ def calculate_retry_interval(response, backoff_base, backoff_multiplier, attempt sleep_time end - #Redact api and app key in the request header + #Redact api key, app key, and Authorization (Bearer) header in the request log def sanitize_request_header(request_header) sanitized_headers= request_header.dup - keys_to_redact = ["DD-API-KEY", "DD-APPLICATION-KEY"] + keys_to_redact = ["DD-API-KEY", "DD-APPLICATION-KEY", "Authorization"] keys_to_redact.each do |key_to_redact| if sanitized_headers.key?(key_to_redact) sanitized_headers[key_to_redact] = "REDACTED" diff --git a/spec/api_client_spec.rb b/spec/api_client_spec.rb index 2231a991b3c8..de7c20b03911 100644 --- a/spec/api_client_spec.rb +++ b/spec/api_client_spec.rb @@ -191,6 +191,33 @@ end end + describe '#sanitize_request_header' do + let(:api_client) { DatadogAPIClient::APIClient.new } + + # Verifies the debug log path redacts api key, app key, and Authorization + # (Bearer) header before the @config.logger.debug call. Without redacting + # Authorization, callers running with debug logging and a PAT or delegated + # token would leak the bearer to stderr / CI artifacts / log shippers. + # See CRED-2625. + it 'redacts DD-API-KEY, DD-APPLICATION-KEY, and Authorization' do + headers = { + 'DD-API-KEY' => 'api-key-secret-value', + 'DD-APPLICATION-KEY' => 'app-key-secret-value', + 'Authorization' => 'Bearer ddpat_supersecret_should_not_leak', + 'Content-Type' => 'application/json', + } + sanitized = api_client.sanitize_request_header(headers) + + expect(sanitized['DD-API-KEY']).to eq('REDACTED') + expect(sanitized['DD-APPLICATION-KEY']).to eq('REDACTED') + expect(sanitized['Authorization']).to eq('REDACTED') + # Non-credential headers pass through unchanged. + expect(sanitized['Content-Type']).to eq('application/json') + # Original hash unchanged (defensive dup). + expect(headers['Authorization']).to eq('Bearer ddpat_supersecret_should_not_leak') + end + end + describe '#sanitize_filename' do let(:api_client) { DatadogAPIClient::APIClient.new }