Skip to content

fix(core): Fix malicious escaping of dimensions.#3599

Merged
c-r33d merged 3 commits into
DSPX-2190-enrich-casbinfrom
worktree-kas-uri-sanitization
Jun 12, 2026
Merged

fix(core): Fix malicious escaping of dimensions.#3599
c-r33d merged 3 commits into
DSPX-2190-enrich-casbinfrom
worktree-kas-uri-sanitization

Conversation

@c-r33d

@c-r33d c-r33d commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes KAS URI dimension injection in authz v2 by escaping dimension values before Casbin matching, then decoding them during dimension parsing. This prevents harmful values containing dimension parser tokens from being interpreted as additional authorization dimensions.

Changes

  • Escape only dimension grammar conflicts during serialization:
    • % as %25
    • & as %26
    • literal * as %2A
  • Decode escaped request and policy dimension values with percent-decoding before comparison.
  • Keep values readable where possible: =, +, URI schemes, paths, and query keys remain unchanged.
  • Add unit coverage for:
    • URI values containing & and =
    • literal +, spaces, %, and *
    • serialize/parse round trips
    • dimensionMatch behavior with escaped policy dimensions and wildcard values
  • Update authz-v2 cukes to verify a kas-a scoped client cannot access KAS keys whose URI injects a trailing kas_uri=https://kas-a.example.com.

Security Impact

Previously, a malicious KAS URI like:

https://kas-b.example.com?foo=bar&kas_uri=https://kas-a.example.com

could be serialized into dimensions in a way that allowed the trailing kas_uri pair to overwrite the original value during parsing. The fix keeps the full URL as one dimension value, so policy matching compares against the actual KAS URI.

Policy Authoring Note

Raw policy dimensions remain readable. Authors only need percent-encoding for values containing characters that conflict with the dimension grammar, especially literal & inside a value:

kas_uri=https://kas.example.com?foo=bar%26baz=qux

Raw * remains the wildcard policy value; use %2A for a literal *.

💡 Follow-up Recommendation: Structured Policy Dimensions

🚧 Recommendation: Consider moving policy dimensions to a structured representation before matching, such as map[string][]string per RPC/path. This would avoid delimiter ambiguity in raw Casbin dimension strings and reduce the need for authors to percent-encode parser tokens.

@c-r33d c-r33d requested a review from a team as a code owner June 12, 2026 13:15
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds URL-encoding and URL-decoding to Casbin v2 dimension serialization, parsing, and matching to prevent dimension injection attacks. Core functions now escape values during serialization and unescape them during comparison. Unit tests validate encoding safety and round-trip correctness. A BDD scenario confirms the authorization system rejects keys with injected dimension characters.

Changes

Casbin v2 dimension URL encoding for injection prevention

Layer / File(s) Summary
URL-encoding in dimension serialization and matching
service/internal/auth/authz/casbin/casbin.go
serializeDimensions URL-escapes each dimension value to build safe key=value&... strings; dimensionMatch URL-unescapes non-wildcard policy dimensions before comparison; parseDimensions URL-unescapes request dimension values. The net/url import is added.
Unit tests for URL-encoding safety
service/internal/auth/authz/casbin/casbin_test.go
TestSerializeDimensions_InjectionPrevention validates that special characters like & and = are percent-encoded to prevent injection. TestParseDimensions_RoundTrip confirms round-trip survival of special characters. TestDimensionMatch_WithURIValues validates dimension matching with URI values, including query string handling and wildcard policies.
BDD integration test for injection rejection
tests-bdd/features/authz-v2.feature
New scenario "KAS URI with injected dimension characters is rejected" creates keys with crafted kas_uri values containing query/path injection patterns and asserts both are denied access, confirming the security control.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐇 A rabbit hops through dimensions with care,
Escaping the chars that were hiding there—
No sneaky injections shall pass through the gate,
With URL encoding, we seal our own fate!
Safety in strings, one percent at a time

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(core): Fix malicious escaping of dimensions' directly relates to the main change: implementing URL-encoding/decoding of dimension values to prevent dimensional injection attacks via special characters.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 worktree-kas-uri-sanitization

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 and usage tips.

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

The following issues were found:

  • ❌ 1 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 176 package(s) with unknown licenses.
  • ⚠️ 11 packages with OpenSSF Scorecard issues.

View full job summary

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a security vulnerability in the authorization system where malicious KAS URI values could be manipulated to inject additional authorization dimensions. By applying URL-encoding to dimension values during serialization and decoding them during parsing, the system now ensures that complex URI strings are treated as single, atomic values, preventing unauthorized policy matching.

Highlights

  • Security Fix: Implemented URL-encoding for serialized dimension values to prevent malicious injection of characters like '&' and '=' that could lead to unauthorized dimension parsing.
  • Data Integrity: Added URL-decoding during the dimension parsing phase to ensure that serialized values are correctly restored to their original state.
  • Test Coverage: Introduced comprehensive unit tests for serialization/parsing round-trips and injection prevention, alongside new BDD scenarios to verify security boundaries.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.


When query strings hide a dark snare, / We encode them with diligent care. / No injection can pass, / In our Casbin, alas, / The logic is now tight and fair.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces URL-encoding and decoding for dimension values during serialization and parsing to prevent injection vulnerabilities from special characters like '&' and '='. It also adds comprehensive unit and BDD tests to verify this behavior. The review feedback highlights a matching discrepancy where policy dimensions in dimensionMatch are not unescaped before comparison, making it impossible to match policies containing escaped characters, and suggests unescaping the policy values prior to comparison.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread service/internal/auth/authz/casbin/casbin_test.go
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 175.699786ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 95.720693ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 408.894169ms
Throughput 244.56 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 43.321054467s
Average Latency 432.22253ms
Throughput 115.42 requests/second

Signed-off-by: Chris Reed <creed@virtru.com>
@c-r33d

c-r33d commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 182.412997ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 106.990903ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 414.41538ms
Throughput 241.30 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 45.1688091s
Average Latency 450.108597ms
Throughput 110.70 requests/second

}
policyWildcard := policyVal == "*"
if !policyWildcard {
unescapedVal, err := url.QueryUnescape(policyVal)

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.

claude comment -- this turns "+" into a space, not sure if thats a case we need to account for, if so we could use url.PathUnescape instead

@c-r33d c-r33d Jun 12, 2026

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.

I actually decided to change the method for how we are doing the escaping instead. Before, I was expecting customers to have to url escape their FQNs but that would be unreadable. I was serializing all values to prevent malicious actors from taking advantage of the policy dimension parsing (&). Instead now I just require that the following special characters are escaped if used in the dimension value literally: [&, *, %].

elizabethhealy
elizabethhealy previously approved these changes Jun 12, 2026

@elizabethhealy elizabethhealy left a comment

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.

lgtm, if the above comment isnt a case we need to handle

Signed-off-by: Chris Reed <creed@virtru.com>
@policy-bot-opentdf policy-bot-opentdf Bot dismissed elizabethhealy’s stale review June 12, 2026 15:01

Invalidated by push of 02e2ee4

@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 179.214428ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 90.121922ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 688.095578ms
Throughput 145.33 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 44.331169877s
Average Latency 441.235228ms
Throughput 112.79 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • examples
  • otdfctl
  • sdk
  • service
  • lib/fixtures
  • tests-bdd

See the workflow run for details.

@c-r33d c-r33d merged commit 236e0ca into DSPX-2190-enrich-casbin Jun 12, 2026
35 of 36 checks passed
@c-r33d c-r33d deleted the worktree-kas-uri-sanitization branch June 12, 2026 15:23
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.

2 participants