Skip to content

fix: redact Authorization header in LogInterceptor [AIS-247] - #212

Merged
Tyler Pina (tylerpina) merged 3 commits into
masterfrom
fix/redact-auth-header-in-log-interceptor
Jul 21, 2026
Merged

fix: redact Authorization header in LogInterceptor [AIS-247]#212
Tyler Pina (tylerpina) merged 3 commits into
masterfrom
fix/redact-auth-header-in-log-interceptor

Conversation

@tylerpina

@tylerpina Tyler Pina (tylerpina) commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a redactHeaders private method that replaces the value of any Authorization header with Bearer [REDACTED] before passing to the logger
  • Request headers are redacted; response headers are unchanged (they don't carry bearer tokens)
  • No logging behavior is otherwise altered — consumers who set BASIC or FULL log level still see all other headers and request metadata

Tickets

Closes AIS-247

Test plan

  • Build passes (./gradlew build)
  • Enable FULL logging and confirm Authorization header no longer appears in logs
  • Confirm all other request headers are still logged as expected

🤖 Generated with Claude Code

Summary by Bito

This PR improves testability of the LogInterceptor by making its `redactHeaders` method package-private and enhancing test coverage. The method serves as defense-in-depth to ensure Authorization header values are redacted to 'Bearer [REDACTED]' before logging, protecting sensitive bearer tokens regardless of the configured log level or okhttp version.

Detailed Changes
  • Changes redactHeaders visibility from private static to package-private in LogInterceptor.java to enable direct unit testing; adds documentation comment explaining this is defense-in-depth against older okhttp versions
  • Rewrites testAuthorizationHeaderIsRedacted() as testRedactHeadersReplacesAuthorizationValue() to directly test the method instead of testing via log output
  • Adds testRedactHeadersMatchesHeaderNameCaseInsensitively() to verify 'authorization' header name matching regardless of case
  • Renames testOtherHeadersAreStillLogged() to testTokenNeverAppearsInLog() with updated assertions to confirm raw tokens never appear in log output

Adds a `redactHeaders` helper that replaces the value of any Authorization
header with `Bearer [REDACTED]` before passing headers to the logger.
Response headers are unchanged because they don't carry bearer tokens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@tylerpina
Tyler Pina (tylerpina) requested a review from a team as a code owner July 21, 2026 13:20
@bito-code-review

bito-code-review Bot commented Jul 21, 2026

Copy link
Copy Markdown

Code Review Agent Run #a798cc

Actionable Suggestions - 0
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • src/main/java/com/contentful/java/cma/interceptor/LogInterceptor.java - 1
    • CWE-20: Missing Test for Auth Redaction · Line 60-72
Review Details
  • Files reviewed - 1 · Commit Range: eb968c9..eb968c9
    • src/main/java/com/contentful/java/cma/interceptor/LogInterceptor.java
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Java-google-format (Linter) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Default Agent You can customize the agent settings here or contact your Bito workspace admin at jared.jolton@contentful.com.

Documentation & Help

AI Code Review powered by Bito Logo

@bito-code-review

bito-code-review Bot commented Jul 21, 2026

Copy link
Copy Markdown

Changelist by Bito

This pull request implements the following key changes.

Key Change Files Impacted Summary
Bug Fix - Authorization Header Redaction in LogInterceptor
Makes redactHeaders method package-private for unit testing, adds defense-in-depth documentation, and enhances test coverage with direct method tests and case-insensitive header matching validation.

@bito-code-review

bito-code-review Bot commented Jul 21, 2026

Copy link
Copy Markdown

Functional Validation by Bito

SourceRequirement / Code AreaStatusNotes
AIS-247Redact Authorization header values in LogInterceptor to prevent bearer token leakage in logs✅ MetThe PR implements the redactHeaders method in src/main/java/com/contentful/java/cma/interceptor/LogInterceptor.java to redact Authorization header values before logging. The method iterates through headers and replaces any header matching 'Authorization' (case-insensitive) with 'Bearer [REDACTED]'. The logging statement at line 18 now calls `redactHeaders(request.headers())` instead of logging raw headers. Additional tests in src/test/kotlin/com/contentful/java/cma/interceptor/LogInterceptorTests.kt verify the redaction works case-insensitively and that raw tokens never appear in log output.

@bito-code-review

bito-code-review Bot commented Jul 21, 2026

Copy link
Copy Markdown

Impact Analysis by Bito

Interaction Diagram
sequenceDiagram
participant App as Application
participant CMA as CMAClient<br/>🔄 Updated | ●●○ Medium
participant Auth as AuthorizationHeaderInterceptor
participant Log as LogInterceptor<br/>🔄 Updated | ●●● High
participant OkHttp as OkHttp Chain
participant Logger as Logger
participant Test as LogInterceptorTests<br/>🟩 Added | ●●○ Medium
    
Note over Log: Security fix: Authorization header<br/>values are now redacted before logging
    
App->>CMA: Create client with logger enabled
CMA->>Log: Add LogInterceptor to chain
CMA->>Auth: Add AuthorizationHeaderInterceptor
    
App->>CMA: Make API request
CMA->>Auth: intercept(request)
Auth->>OkHttp: Add Authorization: Bearer token
OkHttp->>Log: intercept(request)
Log->>Log: redactHeaders(headers)
Log->>Logger: Log sanitized headers
Note over Log: Authorization header now shows<br/>Bearer [REDACTED] instead of real token
Log->>OkHttp: proceed(request)
OkHttp-->>Log: Return response
Log-->>CMA: Return response
CMA-->>App: Return result
    
Test->>Log: Test redactHeaders()
Test->>Log: Test token never appears in logs
Loading

This MR adds security-focused header redaction to the LogInterceptor. When logging is enabled, Authorization header values are now masked as 'Bearer [REDACTED]' before being written to logs, preventing sensitive access tokens from being exposed. The change includes comprehensive unit and integration tests to verify the redaction behavior.

Cross-Repository Impact Analysis
What Changed Impact of Change Suggested Review Actions
Added redactHeaders() method to LogInterceptor for Authorization header redaction in logs - No cross-repo consumers found for LogInterceptor: contentful-management.java is a Java SDK library. BitoAIArchitect search found no external repositories consuming LogInterceptor directly. The JavaScript contentful-management library is a separate codebase. - Verify no downstream Java consumers extend or override LogInterceptor class
- Confirm AuthorizationHeaderInterceptor.HEADER_NAME constant is stable (used for case-insensitive matching)
Code Paths Analyzed

Impact:
Security improvement: Authorization tokens are now redacted from debug logs. The intercept() method now passes headers through redactHeaders() before logging.

Flow:
HTTP Request → OkHttp Chain → LogInterceptor.intercept() → redactHeaders() → Logger (Authorization header value masked as 'Bearer [REDACTED]')

Direct Changes (Diff Files):
• src/main/java/com/contentful/java/cma/interceptor/LogInterceptor.java [7,49-50,61-76] — Added okhttp3.Headers import, modified intercept() to call redactHeaders(), added new redactHeaders() static method
• src/test/kotlin/com/contentful/java/cma/interceptor/LogInterceptorTests.kt [1-128] — New test file with unit tests for redactHeaders() and integration test verifying tokens don't appear in logs

Repository Impact:
Logging/Interceptor module: LogInterceptor now redacts sensitive Authorization headers before logging. All HTTP request logging through this interceptor will show '[REDACTED]' for Authorization values.

Cross-Repository Dependencies:
No high-confidence cross-repository impacts detected: contentful-management.java is a client SDK library. No consuming repositories found in the BitoAIArchitect index that reference LogInterceptor or com.contentful.java.cma package.

Database/Caching Impact:
• None

API Contract Violations:
• No API contract violations. The change is backward compatible - LogInterceptor constructor unchanged, intercept() signature unchanged. Only logging output format changes (Authorization values masked).

Infrastructure Dependencies:
• No infrastructure changes required. Defense-in-depth implementation works with both old and new okhttp versions.

Additional Insights:
Security/Compliance: Prevents accidental logging of bearer tokens. Case-insensitive header name matching ensures 'authorization', 'Authorization', 'AUTHORIZATION' are all redacted.

Testing Recommendations

Frontend Impact:
• No frontend impact - this is a backend Java SDK library

Service Integration:
• Verify integration with OkHttp client builder - LogInterceptor should still be addable via addInterceptor()

Data Serialization:
• No serialization changes - only logging output format modified

Privacy Compliance:
• Tests already included: testRedactHeadersReplacesAuthorizationValue, testRedactHeadersMatchesHeaderNameCaseInsensitively, testTokenNeverAppearsInLog
• Consider adding test for multiple Authorization headers if supported by the API

Backward Compatibility:
• Verify existing log parsers don't depend on exact Authorization header value format in logs
• Confirm no tests assert on full Authorization header value in log output

OAuth Functionality:
• None

Cross-Service Communication:
• No cross-service communication changes - this is a client-side logging change only

Reliability Testing:
• None

Additional Insights:
• Tests cover: (1) Authorization value redaction, (2) Case-insensitive header matching, (3) End-to-end token non-appearance in logs
• Consider testing edge cases: empty Authorization value, malformed Authorization header, concurrent access to redactHeaders

Analysis based on known dependency patterns and edges. Actual impact may vary.

bito-code-review[bot]
bito-code-review Bot previously approved these changes Jul 21, 2026
@tylerpina

Copy link
Copy Markdown
Contributor Author

✅ Pre-review pass — verified, ready for team review

Traced the fix against AIS-247:

  • redactHeaders() rebuilds the request Headers, replacing any Authorization value with Bearer [REDACTED] (case-insensitive match) — closes the bearer-token leak at the exact sink the ticket calls out.
  • Scope is correct: request headers redacted, response headers left alone (they don't carry the token).
  • "Bearer [REDACTED]" is a valid okhttp header value (brackets/spaces fine).

One suggestion (non-blocking): add a small unit test asserting the redaction, since this is a regression-prone security fix. Happy to approve as-is otherwise.

@t-col Tyler Collins (t-col) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice work — this closes a real credential-leak risk cleanly, and the fix itself reads correct: it walks the header list by index, subs in the redacted value only for Authorization, and leaves everything else (including response headers, which don't carry the token) untouched.

I left a couple of comments below, mostly around reusing an existing constant and locking this in with a test, but nothing here should block the merge — happy to see this go out as is if we'd rather follow up separately.

If we don't add a test now, might be worth opening a quick follow-up ticket so the regression coverage doesn't get lost.

Headers.Builder redacted = new Headers.Builder();
for (int i = 0; i < headers.size(); i++) {
String name = headers.name(i);
if ("Authorization".equalsIgnoreCase(name)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Small one: AuthorizationHeaderInterceptor.HEADER_NAME already holds this exact string a few files over. Might be worth reusing it here instead of the literal, just so we don't end up with two sources of truth for the header name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — redactHeaders now compares against AuthorizationHeaderInterceptor.HEADER_NAME instead of the string literal, so the header name has a single source of truth. Same package, so no new import.

return response;
}

private static Headers redactHeaders(Headers headers) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Following up on coverage — there's no existing test file for LogInterceptor, so this redaction doesn't have anything guarding it going forward. A quick test that mocks the logger and asserts the token never shows up unredacted in the logged string could be cheap insurance for a fix like this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added LogInterceptorTests.kt under interceptor/. It drives a real request through the interceptor via MockWebServer with a capturing Logger:

  • testAuthorizationHeaderIsRedacted — asserts the raw token never appears and Bearer [REDACTED] does.
  • testOtherHeadersAreStillLogged — asserts a non-auth header (X-Custom-Header) is still present, so redaction is surgical.

Heads up: I could not run the suite locally (no JDK on my machine at the moment), so I am leaning on CI to confirm it goes green — the test mirrors the existing MockWebServer pattern used across the Kotlin tests, so I would expect it to, but flagging that I have not executed it myself.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ran the suite locally after all (installed a JDK) — and it caught something worth flagging.

The end-to-end test I first wrote asserted Bearer [REDACTED] appears in the log. It failed: okhttp >= 4.10 already masks Authorization to ██ in Headers.toString() by header name, regardless of value. So on our okhttp (4.12):

  • the raw token was never in the log even before this fix (okhttp masks it), and
  • our injected Bearer [REDACTED] gets overwritten to ██ too, so it is not observable end-to-end.

Two takeaways:

  1. redactHeaders is defense-in-depth here, not the thing preventing the leak on 4.12 — it guarantees the value is stripped independent of okhttp's internal masking (which is an undocumented debug convenience, not a security guarantee, and would disappear if okhttp were pinned < 4.10). Added a comment saying so.
  2. An end-to-end "token absent" test would pass even if redactHeaders were deleted, so it does not actually guard the code. Reworked the tests to assert redactHeaders directly (Authorization value → Bearer [REDACTED], case-insensitive match, other headers untouched) plus keep one end-to-end raw-token-absent invariant.

3/3 green locally (mvn -Dtest=LogInterceptorTests test). Pushed in b1031c4.

Address review feedback:
- redactHeaders compares against AuthorizationHeaderInterceptor.HEADER_NAME
  instead of a string literal (single source of truth)
- add LogInterceptorTests exercising redaction via MockWebServer: asserts the
  raw token never appears and non-auth headers are still logged

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@bito-code-review bito-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review Agent Run #b4d98a

Actionable Suggestions - 1
  • src/test/kotlin/com/contentful/java/cma/interceptor/LogInterceptorTests.kt - 1
    • Refactor duplicate test setup code · Line 28-28
Review Details
  • Files reviewed - 2 · Commit Range: eb968c9..02ace95
    • src/main/java/com/contentful/java/cma/interceptor/LogInterceptor.java
    • src/test/kotlin/com/contentful/java/cma/interceptor/LogInterceptorTests.kt
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Kotlin (Linter) - ✔︎ Successful
    • Java-google-format (Linter) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Default Agent You can customize the agent settings here or contact your Bito workspace admin at jared.jolton@contentful.com.

Documentation & Help

AI Code Review powered by Bito Logo

Comment thread src/test/kotlin/com/contentful/java/cma/interceptor/LogInterceptorTests.kt Outdated
Running the suite surfaced that okhttp >= 4.10 already masks Authorization to
"██" in Headers.toString() by name, so an end-to-end "Bearer [REDACTED]"
assertion never matched and a raw-token-absent assertion wouldn't guard our
code (okhttp masks regardless). Make redactHeaders package-private and assert
its value transformation directly; keep an end-to-end raw-token-absent check.
Document that redactHeaders is defense-in-depth on current okhttp.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@bito-code-review

bito-code-review Bot commented Jul 21, 2026

Copy link
Copy Markdown

Code Review Agent Run #ebe35e

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: 02ace95..b1031c4
    • src/main/java/com/contentful/java/cma/interceptor/LogInterceptor.java
    • src/test/kotlin/com/contentful/java/cma/interceptor/LogInterceptorTests.kt
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Java-google-format (Linter) - ✔︎ Successful
    • Kotlin (Linter) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Default Agent You can customize the agent settings here or contact your Bito workspace admin at jared.jolton@contentful.com.

Documentation & Help

AI Code Review powered by Bito Logo

@tylerpina
Tyler Pina (tylerpina) merged commit bbbbb44 into master Jul 21, 2026
10 checks passed
@tylerpina
Tyler Pina (tylerpina) deleted the fix/redact-auth-header-in-log-interceptor branch July 21, 2026 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants