Skip to content

Mask exception request parameters case-insensitively#15810

Open
jamesfredley wants to merge 2 commits into
8.0.xfrom
fix/exception-masking-case-insensitive
Open

Mask exception request parameters case-insensitively#15810
jamesfredley wants to merge 2 commits into
8.0.xfrom
fix/exception-masking-case-insensitive

Conversation

@jamesfredley

@jamesfredley jamesfredley commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

The Problem

GrailsExceptionResolver can include request parameter names and values in exception log messages when request-parameter logging is enabled. Grails exposes grails.exceptionresolver.params.exclude so an app can mask sensitive parameters (passwords, tokens, etc.) out of those logs.

That masking used an exact, case-sensitive List.contains() check. So an app that excluded password or token would still log the values of parameters named Password, PASSWORD, or TOKEN - the exact fields you were trying to hide - simply because of the casing the incoming request happened to use.

This is a hardening issue rather than an insecure default (request-parameter logging is not the production default), but once logging is turned on, masking should not depend on request casing.

The Fix

  • Case-insensitive matching for excluded parameter names via equalsIgnoreCase, so Password/TOKEN are masked when password/token are excluded.
  • Still exact-name, not substring - an excluded token does not accidentally mask an unrelated apiToken.
  • Null-safe throughout - missing parameter names, a missing exclude list, and null entries inside the exclude list are all handled (a misconfigured list can't interrupt request logging).
  • Docs + metadata updated to describe the case-insensitive behavior, and the metadata corrected to document the actual runtime mask token, ***.

Files

  • GrailsExceptionResolver.java - case-insensitive, null-safe exclusion helper.
  • GrailsExceptionResolverSpec.groovy - coverage for case variants, substrings, and null-entry configs.
  • maskingRequestParametersFromStacktraceLogs.adoc - documents the matching behavior.
  • spring-configuration-metadata.json - documents the *** mask.

Review feedback

Copilot raised two points, both addressed: null exclude-list entries are skipped before comparison, and the metadata now states the real *** mask emitted by GrailsExceptionResolver#getRequestLogMessage.

Testing

  • :grails-web-mvc:test --tests "...GrailsExceptionResolverSpec", :grails-web-mvc:check, :grails-web-core:check, and :grails-doc:assemble pass.

Match excluded request parameter names without regard to case when Grails
logs exception request parameters, and document the matching behavior in
the logging guide and configuration metadata.

Assisted-by: Hephaestus:openai/gpt-5.5
Copilot AI review requested due to automatic review settings July 1, 2026 23:17

Copilot AI 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.

Pull request overview

Updates Grails’ exception request-parameter masking so excluded parameter names are matched case-insensitively while still requiring exact-name matches (so substrings like apiToken are not masked by an excluded token).

Changes:

  • Updated GrailsExceptionResolver#getRequestLogMessage to treat excluded parameter names case-insensitively via a helper method.
  • Added a regression test covering case-insensitive matching and ensuring no substring-based masking occurs.
  • Updated docs and Spring configuration metadata to document case-insensitive matching behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
grails-web-mvc/src/test/groovy/org/grails/web/errors/GrailsExceptionResolverSpec.groovy Adds coverage for case-insensitive excluded parameter masking and exact-name-only behavior.
grails-web-mvc/src/main/groovy/org/grails/web/errors/GrailsExceptionResolver.java Implements case-insensitive excluded-parameter detection for request log messages.
grails-web-core/src/main/resources/META-INF/spring-configuration-metadata.json Documents the updated matching behavior for the exclusion list.
grails-doc/src/en/guide/conf/config/logging/maskingRequestParametersFromStacktraceLogs.adoc Notes case-insensitive matching in user-facing logging documentation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread grails-web-core/src/main/resources/META-INF/spring-configuration-metadata.json Outdated
@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.4902%. Comparing base (b86be15) to head (a52f949).
⚠️ Report is 2 commits behind head on 8.0.x.

Files with missing lines Patch % Lines
...org/grails/web/errors/GrailsExceptionResolver.java 75.0000% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##                8.0.x     #15810        +/-   ##
==================================================
+ Coverage     49.4820%   49.4902%   +0.0082%     
- Complexity      16698      16703         +5     
==================================================
  Files            1947       1947                
  Lines           92474      92481         +7     
  Branches        16152      16154         +2     
==================================================
+ Hits            45758      45769        +11     
+ Misses          39610      39602         -8     
- Partials         7106       7110         +4     
Files with missing lines Coverage Δ
...org/grails/web/errors/GrailsExceptionResolver.java 48.9130% <75.0000%> (+7.6701%) ⬆️

... and 4 files with indirect coverage changes

🚀 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.

Ignore null entries while checking excluded request parameters so misconfigured lists do not interrupt request logging. Correct configuration metadata to document the actual mask emitted at runtime.

Assisted-by: opencode:gpt-5.5
@jamesfredley

Copy link
Copy Markdown
Contributor Author

Addressed the Copilot feedback in follow-up commit a52f949. The null exclude-list entry case is now handled explicitly, the metadata mask text matches the runtime output, both review threads have replies and are marked resolved, and the focused resolver test plus web-core resource processing passed locally.

@testlens-app

testlens-app Bot commented Jul 2, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: a52f949
▶️ Tests: 41795 executed
⚪️ Checks: 44/44 completed


Learn more about TestLens at testlens.app.

@jamesfredley

Copy link
Copy Markdown
Contributor Author

Pre-release review pass (2026-07-02, dual-reviewer: GPT-5.5 oracle + Codex CLI): APPROVE - no blocking findings.

Reviewed the full diff plus local context: the new isExcludedRequestParameter(...) helper switches exclusion matching to equalsIgnoreCase (locale-safe, avoids the Turkish-I pitfall of toLowerCase()), keeps exact-name semantics (no substring over-masking of e.g. apiToken when only token is excluded), and handles nulls. Test coverage validates mixed-case masking and that unrelated parameters stay visible; docs and config metadata were updated (including the corrected *** mask token). CI green.

return false;
}
for (String excludedParameterName : excludedParameterNames) {
if (excludedParameterName != null && parameterName.equalsIgnoreCase(excludedParameterName)) {

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.

The null check is unnecessary, equalsIgnoreCase already returns null when the argument is null

@jdaugherty jdaugherty 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.

This change should be made against 7.0.x , not 8.0.x

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants