fix(authz): make Cedar URI entity IDs collision-free - #6239
Open
SashaMIT wants to merge 1 commit into
Open
Conversation
authorizeResourceRead sanitized resource URIs into Cedar entity IDs by rewriting reserved characters to "_". The mapping is many-to-one: "file:///etc/passwd" and "file://_etc/passwd" both became "file____etc_passwd", and "mcp://srv/config:admin" and "mcp://srv/config/admin" both became "mcp___srv_config_admin". A policy grant on one entity ID therefore authorized every URI in the collision class. Entities are built programmatically via cedar.NewEntityUID, which accepts any string, so no rewriting is needed. Use the exact URI as the entity ID and drop the sanitizer. Attribute-based policies (resource.name / resource.uri) already matched on the exact URI and are unaffected. Policies that referenced sanitized IDs must be updated to name the exact URI. Added TestAuthorizeResourceReadEntityIDsCollisionFree: a grant on an exact URI authorizes that URI and denies the URI that used to collide with it. Signed-off-by: Sasha Mitchell <sash.t.mitchell@gmail.com>
SashaMIT
requested review from
ChrisJBurns,
JAORMX,
jhrozek,
rdimitrov and
tgrunnagle
as code owners
August 7, 2026 20:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A permission granted to one resource URI can silently apply to a different, colliding URI.
Problem
authorizeResourceReadturned resource URIs into Cedar entity IDs with a lossy sanitizer that rewrote:,/,\,?,&,=,#, space, and.to_. The mapping is many-to-one, so distinct URIs collide onto one entity ID:file:///etc/passwdandfile://_etc/passwdboth becameResource::"file____etc_passwd"mcp://srv/config:adminandmcp://srv/config/adminboth becameResource::"mcp___srv_config_admin"A policy granting
Resource::"file____etc_passwd"therefore authorized reads of every URI in the collision class. The confused-deputy condition: an MCP server that serves both a permitted URI and a colliding sensitive URI (or one that lets users create resource URIs) gets the grant applied to a resource the policy author never named.Severity framing, honestly stated: exploitation needs a policy author who grants by entity ID, plus a colliding pair where one side is permitted and the other is sensitive and server-distinguished. Attribute-based policies (
resource.name == ...,resource.uri == ...) match on the exact URI and are unaffected.Fix
Entities are built programmatically with
cedar.NewEntityUID, which accepts any string, so no character rewriting is needed at all. The exact URI is now the entity ID and the sanitizer is removed. Policy authors can name the real URI (for exampleResource::"file:///etc/passwd") instead of computing a mangled form.Note for existing policies: a policy that references a sanitized ID (only possible for URIs containing the rewritten characters) must be updated to name the exact URI. Policies using plain IDs or attribute matching are unchanged.
Tests
Replaced
TestSanitizeURIForCedarwithTestAuthorizeResourceReadEntityIDsCollisionFree: for both collision pairs above, a grant on the exact URI authorizes that URI and denies the formerly colliding URI. Thepkg/authz/...andpkg/vmcp/coresuites pass.Made with Cursor