Skip to content

CMM-1217 Redact sensitive data from mobile network logs#22572

Merged
adalpari merged 3 commits intotrunkfrom
internal/CMM-1217-Redact-sensitive-data-from-mobile-network-logs
Feb 9, 2026
Merged

CMM-1217 Redact sensitive data from mobile network logs#22572
adalpari merged 3 commits intotrunkfrom
internal/CMM-1217-Redact-sensitive-data-from-mobile-network-logs

Conversation

@adalpari
Copy link
Contributor

@adalpari adalpari commented Feb 6, 2026

Description

Redact request bodies for sensitive endpoints (xmlrpc.php and wp-login.php) in the network request tracking feature (Chucker). These endpoints carry credentials in their request bodies, which should not be stored in the on-device log.

The requests are still fully logged (URL, method, headers, status code, response) — only the request body is replaced with a [Body redacted] placeholder. The actual network call is unaffected.

This is achieved via a RedactedBodyChain wrapper that presents a redacted request to Chucker while delegating proceed() to the original chain with the real body intact.
Adding more sensitive endpoints in the future only requires appending to REDACTED_BODY_PATHS.

Testing instructions

Screenshot 2026-02-06 at 18 33 30

Redacted body for sensitive endpoints:

  1. Enable the Network Debugging experimental feature
  2. Go to Help/Support and enable Track Network Requests
  3. Perform an action that triggers an xmlrpc.php or wp-login.php request (e.g. open a self-hosted site and go to posts)
  4. Tap View Network Requests to open Chucker
  5. Find the xmlrpc.php / wp-login.php entry
  • Verify the request body shows [Body redacted — contains sensitive information]
  • Verify the response body, headers, and status code are still visible

Non-sensitive endpoints unaffected:

  1. With tracking still enabled, perform an action that triggers a regular API call (e.g. open Reader)
  2. Open View Network Requests
  • Verify regular requests still show the full request body as before

Network calls work correctly:

  1. With tracking enabled, perform various actions (login, browse, post)
  • Verify all functionality works normally — redaction only affects what Chucker logs, not the actual requests

@adalpari
Copy link
Contributor Author

adalpari commented Feb 6, 2026

@claude

@claude
Copy link
Contributor

claude bot commented Feb 6, 2026

Claude finished @adalpari's task in 1m 23s —— View job


Code Review Complete ✓

Todo List:

  • Read repository guidelines (CLAUDE.md)
  • Read and analyze the changed file
  • Review security aspects (data redaction implementation)
  • Review code quality and maintainability
  • Review error handling and edge cases
  • Review testing approach
  • Provide comprehensive feedback

Summary

Overall, this is a well-designed and secure implementation that effectively addresses the security concern of redacting sensitive credentials from network logs. The approach is clean, maintainable, and follows good architectural patterns. I've identified a few areas for improvement below.

✅ Strengths

  1. Excellent Security Design: The RedactedBodyChain wrapper pattern is clever - it presents redacted data to Chucker while ensuring the actual network call proceeds with the original body intact.

  2. Clean Architecture: The use of a wrapper chain that delegates to the original is a solid pattern that keeps concerns separated.

  3. Maintainability: The REDACTED_BODY_PATHS list makes it trivial to add new endpoints in the future.

  4. Performance Conscious: Good comment explaining why reading preferences on every request is acceptable (SharedPreferences caching).

  5. Thread Safety: Proper double-check locking pattern for Chucker interceptor initialization.

🔍 Issues & Suggestions

1. Security: Path Matching Could Be Bypassed (Medium Priority)

Location: libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/TrackNetworkRequestsInterceptor.kt:90-93

The current implementation uses path.endsWith() which could miss edge cases:

private fun shouldRedactRequestBody(request: Request): Boolean {
    val path = request.url.encodedPath
    return REDACTED_BODY_PATHS.any { path.endsWith(it) }
}

Concerns:

  • A URL like /some/path/xmlrpc.php/extra would not match xmlrpc.php with endsWith()
  • Query parameters are correctly excluded (using encodedPath), which is good
  • However, URL fragments or trailing slashes could cause issues

Recommendation: Consider using contains() or a more robust pattern:

private fun shouldRedactRequestBody(request: Request): Boolean {
    val path = request.url.encodedPath
    return REDACTED_BODY_PATHS.any { sensitivePath ->
        path.contains("/$sensitivePath") || path.endsWith(sensitivePath)
    }
}

Or even better, use the path segments:

private fun shouldRedactRequestBody(request: Request): Boolean {
    val pathSegments = request.url.pathSegments
    return REDACTED_BODY_PATHS.any { it in pathSegments }
}

2. Missing Unit Tests (High Priority)

Location: No test file exists for TrackNetworkRequestsInterceptor

This security-critical code lacks unit test coverage. Tests should verify:

  • Redaction works for xmlrpc.php and wp-login.php endpoints
  • Non-sensitive endpoints are not affected
  • Edge cases: URLs with query params, trailing slashes, nested paths
  • Thread safety of the interceptor
  • The RedactedBodyChain correctly delegates proceed() to the original chain

Recommendation: Add unit tests at:
libs/fluxc/src/test/java/org/wordpress/android/fluxc/network/TrackNetworkRequestsInterceptorTest.kt

3. Potential NPE in RedactedBodyChain (Low Priority)

Location: libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/TrackNetworkRequestsInterceptor.kt:136

val contentType = original.body?.contentType()
    ?: "text/plain".toMediaType()

While the fallback handles a null body gracefully, if original.body is null, you're creating a redacted body for a request that originally had no body. This is technically correct for the logging purpose, but might be worth a comment explaining the intention.

Recommendation: Add a clarifying comment:

// Use plain text content type if original has no body
// (the redacted placeholder still needs a content type)
val contentType = original.body?.contentType()
    ?: "text/plain".toMediaType()

4. Documentation: Clarify Logging vs Network Behavior (Low Priority)

Location: libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/TrackNetworkRequestsInterceptor.kt:126-130

The class-level KDoc is excellent, but the RedactedBodyChain could benefit from a note that the redaction is logging-only.

Current:

/**
 * A [Interceptor.Chain] wrapper that presents a redacted request body
 * to Chucker while ensuring the actual network call uses the original
 * request with the real body.
 */

Suggested Enhancement:

/**
 * A [Interceptor.Chain] wrapper that presents a redacted request body
 * to Chucker for logging purposes, while ensuring the actual network call 
 * uses the original request with the real body intact.
 * 
 * This achieves selective logging redaction without affecting the 
 * actual HTTP request/response.
 */

5. Consider: HTTPS-Only Validation (Optional Enhancement)

While not strictly required for this PR, consider validating that sensitive endpoints are only accessed over HTTPS. This could be a separate enhancement:

private fun shouldRedactRequestBody(request: Request): Boolean {
    val path = request.url.encodedPath
    val isSensitive = REDACTED_BODY_PATHS.any { path.endsWith(it) }
    
    // Optional: Log warning if sensitive endpoint accessed over HTTP
    if (isSensitive && request.url.scheme != "https") {
        // Log warning about insecure connection to sensitive endpoint
    }
    
    return isSensitive
}

📋 Testing Verification

The PR description provides comprehensive testing instructions. When testing, pay special attention to:

  • URLs with trailing slashes: /xmlrpc.php/
  • URLs with query parameters: /xmlrpc.php?test=1
  • Nested paths: /some/path/to/xmlrpc.php
  • Edge case: What if a site has /api/xmlrpc.php-backup (should NOT be redacted)

🎯 Recommendations Priority

  1. High: Add unit tests for this security-critical code
  2. Medium: Review and strengthen the path matching logic
  3. Low: Enhance documentation and add clarifying comments

Conclusion

This is solid work that addresses a real security concern. With unit tests and slightly more robust path matching, this will be production-ready. The core design pattern is excellent and the code is clean and maintainable.


@dangermattic
Copy link
Collaborator

dangermattic commented Feb 6, 2026

1 Warning
⚠️ PR is not assigned to a milestone.

Generated by 🚫 Danger

@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 6, 2026

@wpmobilebot
Copy link
Contributor

App Icon📲 You can test the changes from this Pull Request in Jetpack Android by scanning the QR code below to install the corresponding build.

App NameJetpack Android
FlavorJalapeno
Build TypeDebug
Versionpr22572-0efea6f
Build Number1483
Application IDcom.jetpack.android.prealpha
Commit0efea6f
Installation URL6onaqvhatdd50
Note: Google Login is not supported on these builds.

@wpmobilebot
Copy link
Contributor

App Icon📲 You can test the changes from this Pull Request in WordPress Android by scanning the QR code below to install the corresponding build.

App NameWordPress Android
FlavorJalapeno
Build TypeDebug
Versionpr22572-0efea6f
Build Number1483
Application IDorg.wordpress.android.prealpha
Commit0efea6f
Installation URL0r1dtk4g76uo8
Note: Google Login is not supported on these builds.

@codecov
Copy link

codecov bot commented Feb 6, 2026

Codecov Report

❌ Patch coverage is 0% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 38.22%. Comparing base (908e00d) to head (0efea6f).
⚠️ Report is 5 commits behind head on trunk.

Files with missing lines Patch % Lines
...d/fluxc/network/TrackNetworkRequestsInterceptor.kt 0.00% 28 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##            trunk   #22572      +/-   ##
==========================================
- Coverage   38.23%   38.22%   -0.01%     
==========================================
  Files        2237     2237              
  Lines      111111   111138      +27     
  Branches    15544    15546       +2     
==========================================
  Hits        42486    42486              
- Misses      65087    65114      +27     
  Partials     3538     3538              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@adalpari adalpari marked this pull request as ready for review February 6, 2026 18:04
@adalpari adalpari requested a review from nbradbury February 6, 2026 18:04
Copy link
Contributor

@nbradbury nbradbury left a comment

Choose a reason for hiding this comment

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

Looks good! :shipit:

Image

@adalpari adalpari merged commit b5f3bf4 into trunk Feb 9, 2026
27 of 30 checks passed
@adalpari adalpari deleted the internal/CMM-1217-Redact-sensitive-data-from-mobile-network-logs branch February 9, 2026 08:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants