Skip to content

OpenAPI Validator: sanitize request method logging and remove method from problem details#3033

Draft
predic8 wants to merge 4 commits into
masterfrom
openapi-validator-method-problem-details
Draft

OpenAPI Validator: sanitize request method logging and remove method from problem details#3033
predic8 wants to merge 4 commits into
masterfrom
openapi-validator-method-problem-details

Conversation

@predic8

@predic8 predic8 commented Jul 3, 2026

Copy link
Copy Markdown
Member

…ssignment

Summary by CodeRabbit

  • Bug Fixes
    • Improved OpenAPI validation failure logging by truncating and masking non-printable characters in request method and URI for request/response paths and “no matching API found” details.
    • Sanitized related validation error messages (including method/path details) and improved correlation-id header masking to prevent raw non-printable values from appearing.
  • Tests
    • Updated unit tests to reflect the renamed non-printable masking helper.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e74ef37a-a5c4-4337-8e50-dd7bad0f9c5a

📥 Commits

Reviewing files that changed from the base of the PR and between fba0f77 and 2f01977.

📒 Files selected for processing (2)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java
  • core/src/main/java/com/predic8/membrane/core/transport/http/HttpServerHandler.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • core/src/main/java/com/predic8/membrane/core/transport/http/HttpServerHandler.java

📝 Walkthrough

Walkthrough

This change renames the non-printable masking helper, updates callers to the new name, and applies masked or masked-and-truncated request values in OpenAPI validation and error reporting. Validation error strings and tests are updated to use the renamed helper.

Changes

Masking helper and logging updates

Layer / File(s) Summary
Rename masking helper
core/src/main/java/com/predic8/membrane/core/util/text/StringUtil.java
Renames the public non-printable masking helper and updates truncate-and-mask delegation to use the new helper name.
Update masking call sites
core/src/main/java/com/predic8/membrane/core/interceptor/log/CorrelationIdInterceptor.java, core/src/main/java/com/predic8/membrane/core/transport/http/HttpServerHandler.java, core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java
Switches existing masking call sites and OpenAPI name sanitization to the renamed helper.
Sanitize OpenAPI validation output
core/src/main/java/com/predic8/membrane/core/openapi/OpenAPIValidator.java, core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java, core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationError.java, core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationErrors.java
Applies masked or masked-and-truncated request values in OpenAPI validation failure paths, updates flow references to Flow.REQUEST, and sanitizes validation error strings.
Update masking tests
core/src/test/java/com/predic8/membrane/core/util/StringUtilTest.java
Updates the existing masking tests to call the renamed helper.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • membrane/api-gateway#2032: Introduces the non-printable masking utility that this change renames and applies across call sites.
  • membrane/api-gateway#2982: Touches the same OpenAPI validation flow that now sanitizes request values and validation error text.
  • membrane/api-gateway#3032: Updates HTTP invalid-method handling and sanitization behavior in the same request-processing path.

Suggested reviewers: christiangoerdes, t-burch

Poem

A rabbit hopped through logs at night,
And masked the chars that weren’t quite right. 🐇
The method field took a gentle bow,
Cleaner errors bloom here now.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title matches the sanitization work, but it wrongly says the method was removed from problem details; the PR sanitizes method/path values instead. Revise it to describe method/path sanitization in OpenAPI validation logs and error details, rather than removing the method from problem details.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch openapi-validator-method-problem-details

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java`:
- Around line 134-136: The OpenAPI validation failure logs still write the
request URI unsanitized while only masking the method, so update both the
handleRequest and handleResponse logging paths in OpenAPIInterceptor to pass
exc.getRequest().getUri() through maskNonPrintableCharacters as well. Keep the
existing log structure in the request/response validation blocks, but ensure
both method and URI are sanitized before being interpolated into the
warning/info message.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 016c32c2-ad6d-4548-9a1a-ea920ff9bdb4

📥 Commits

Reviewing files that changed from the base of the PR and between ad3142e and f683a72.

📒 Files selected for processing (2)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationErrors.java
💤 Files with no reviewable changes (1)
  • core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationErrors.java

…` and introduce `truncateAndMaskNonPrintable` utility

@coderabbitai coderabbitai Bot 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.

♻️ Duplicate comments (1)
core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java (1)

192-195: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

URI still logged unmasked in handleResponse — prior fix only applied to handleRequest.

exc.getRequest().getUri() is logged raw here while the method is masked. A previous review already flagged this exact pattern in both handleRequest and handleResponse; only the handleRequest log statement (Lines 135-139) was fixed. The URI is still attacker-controlled and can carry CRLF/non-printable characters, so log injection remains possible via this response-validation log line.

🛡️ Proposed fix
                 log.info("OpenAPI response validation failed for {} {} against '{}': {}",
-                        maskNonPrintable(exc.getRequest().getMethod()), exc.getRequest().getUri(),
+                        truncateAndMaskNonPrintable(exc.getRequest().getMethod(), 20),
+                        truncateAndMaskNonPrintable(exc.getRequest().getUri()),
                         rec.api.getInfo().getTitle(), errors);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java`
around lines 192 - 195, The response-validation log in
OpenAPIInterceptor.handleResponse still prints exc.getRequest().getUri() raw
while only the method is masked. Update this log statement to sanitize the URI
the same way as handleRequest by applying the existing maskNonPrintable helper
(or equivalent shared masking) to the request URI before logging. Keep the log
context and reference the handleResponse path so both request and response
validation logs consistently avoid attacker-controlled control characters.
🧹 Nitpick comments (1)
core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java (1)

136-137: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inconsistent helper reference style.

Line 136 calls the fully-qualified StringUtil.truncateAndMaskNonPrintable(...) while line 137 (and the handleResponse log call) use the statically-imported form. Consider using the static import consistently for readability.

♻️ Proposed fix
-                        StringUtil.truncateAndMaskNonPrintable(exc.getRequest().getMethod(),20),
+                        truncateAndMaskNonPrintable(exc.getRequest().getMethod(), 20),
                         truncateAndMaskNonPrintable(exc.getRequest().getUri()),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java`
around lines 136 - 137, The logging call in OpenAPIInterceptor uses mixed helper
reference styles for truncateAndMaskNonPrintable, which is inconsistent with the
rest of the class. Update the request log formatting in the relevant log call to
use the statically imported truncateAndMaskNonPrintable consistently, matching
the handleResponse usage and avoiding the explicit StringUtil. prefix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In
`@core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java`:
- Around line 192-195: The response-validation log in
OpenAPIInterceptor.handleResponse still prints exc.getRequest().getUri() raw
while only the method is masked. Update this log statement to sanitize the URI
the same way as handleRequest by applying the existing maskNonPrintable helper
(or equivalent shared masking) to the request URI before logging. Keep the log
context and reference the handleResponse path so both request and response
validation logs consistently avoid attacker-controlled control characters.

---

Nitpick comments:
In
`@core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java`:
- Around line 136-137: The logging call in OpenAPIInterceptor uses mixed helper
reference styles for truncateAndMaskNonPrintable, which is inconsistent with the
rest of the class. Update the request log formatting in the relevant log call to
use the statically imported truncateAndMaskNonPrintable consistently, matching
the handleResponse usage and avoiding the explicit StringUtil. prefix.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 084a922f-8ddd-4cda-8622-b2fe4ce7fe75

📥 Commits

Reviewing files that changed from the base of the PR and between f683a72 and 9044a51.

📒 Files selected for processing (8)
  • core/src/main/java/com/predic8/membrane/core/interceptor/log/CorrelationIdInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/openapi/OpenAPIValidator.java
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationErrors.java
  • core/src/main/java/com/predic8/membrane/core/transport/http/HttpServerHandler.java
  • core/src/main/java/com/predic8/membrane/core/util/text/StringUtil.java
  • core/src/test/java/com/predic8/membrane/core/util/StringUtilTest.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationErrors.java

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationError.java (1)

65-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Magic number 15 for method-length duplicated across call sites.

The 15 character cap for masked/truncated HTTP methods is repeated here and in ValidationErrors.getErrorMessage (and again in OpenAPIInterceptor's logging calls). Extracting it to a shared constant (e.g., in StringUtil or a small OpenApiLogging constants holder) would prevent future drift if the limit needs to change.

♻️ Example approach
-        return String.format("%s %s %s: %s",
-                truncateAndMaskNonPrintable(ctx.getMethod(),15),
+        return String.format("%s %s %s: %s",
+                truncateAndMaskNonPrintable(ctx.getMethod(), MAX_METHOD_LOG_LENGTH),
                 truncateAndMaskNonPrintable(ctx.getPath()),
                 ctx.getJSONpointer(), message);

Define MAX_METHOD_LOG_LENGTH = 15 once (e.g. in StringUtil) and reuse it from ValidationError, ValidationErrors, and OpenAPIInterceptor.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationError.java`
around lines 65 - 68, The HTTP method truncation limit is hardcoded in multiple
places, so the cap can drift over time. Extract the shared method-length limit
used by ValidationError, ValidationErrors.getErrorMessage, and
OpenAPIInterceptor into a single constant (for example in StringUtil or a small
OpenApiLogging constants holder), then replace each literal 15 with that shared
symbol so all logging paths stay consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationError.java`:
- Around line 65-68: The HTTP method truncation limit is hardcoded in multiple
places, so the cap can drift over time. Extract the shared method-length limit
used by ValidationError, ValidationErrors.getErrorMessage, and
OpenAPIInterceptor into a single constant (for example in StringUtil or a small
OpenApiLogging constants holder), then replace each literal 15 with that shared
symbol so all logging paths stay consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bfa45e1e-79d9-4aa1-8c50-c22d98151076

📥 Commits

Reviewing files that changed from the base of the PR and between 9044a51 and fba0f77.

📒 Files selected for processing (4)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationError.java
  • core/src/main/java/com/predic8/membrane/core/openapi/validators/ValidationErrors.java
  • core/src/main/java/com/predic8/membrane/core/util/text/StringUtil.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/util/text/StringUtil.java

@predic8 predic8 requested a review from rrayst July 3, 2026 11:36
@rrayst

rrayst commented Jul 3, 2026

Copy link
Copy Markdown
Member

/ok-to-test

.status(404)
.addSubSee("not-found")
.detail("There is no API on the path %s deployed. Please check the path.".formatted(exc.getOriginalRequestUri()))
.detail("There is no API on the path %s deployed. Please check the path.".formatted(truncateAndMaskNonPrintable(exc.getOriginalRequestUri())))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

shouldn't 'escaping/making printable of the details(...) parameter' be a concern of the ProblemDetails message? Grepping the code for .detail( shows several occurences of "attacker-controlled" string parts in the parameter.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

or maybe change the signature to .detail(String messageWithPlaceholders, Object... placeholders) ?

@predic8 predic8 marked this pull request as draft July 4, 2026 13:39
@membrane-ci-server

Copy link
Copy Markdown

This pull request needs "/ok-to-test" from an authorized committer.

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.

2 participants