Skip to content

fix(security): don't grant reviewer authz shortcut on CREATE#30026

Open
sonika-shah wants to merge 1 commit into
mainfrom
fix/reviewer-create-authz-bypass
Open

fix(security): don't grant reviewer authz shortcut on CREATE#30026
sonika-shah wants to merge 1 commit into
mainfrom
fix/reviewer-create-authz-bypass

Conversation

@sonika-shah

@sonika-shah sonika-shah commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Fixes #29837

Problem

DefaultAuthorizer.authorize() short-circuits policy evaluation when the caller is a reviewer of the resource:

if (subjectContext.isAdmin()) return;
if (isReviewer(resourceContext, subjectContext)) return;   // <-- fires before RBAC
PolicyEvaluator.hasPermission(subjectContext, resourceContext, operationContext);

For CREATE operations the ResourceContextInterface is a CreateResourceContext, whose getEntity() returns the unsaved, caller-supplied request body. isReviewer() reads entity.getReviewers() from that in-flight entity, so a user can add themselves to the reviewers field of a create request, make isReviewer() return true, and skip RBAC entirely — creating entities (e.g. Data Products) they have no Create permission for.

Because the REST API and the MCP tool share this authorization path, both are affected. The UI's own gating masks it, but the server does not enforce it.

Scope is broader than Data Products: any reviewer-supporting entity (Glossary, GlossaryTerm, DataProduct, Metric, Tag, DataContract, …) created via the standard path is exposed.

Reproduction (before this change)

Principal: a non-admin with only DataConsumer role → effective Create on dataProduct = notAllow.

Request Result
POST /dataProducts (no reviewers) 403 operations [Create] not allowed
POST /dataProducts + reviewers:[{self}] 201 Created ← bypass

Fix

Gate the reviewer shortcut so it only applies to already persisted entities, never a CreateResourceContext:

  1. DefaultAuthorizer.isReviewer() — the hard-coded shortcut (the reported vector).
  2. RuleEvaluator.isReviewer() — the SpEL condition available to custom policies, which reads the same in-flight entity. No shipped policy uses it, but guarding it too closes the same bug class as defense-in-depth.

Reviewer-based authorization continues to work for Edit/View/approval operations on existing entities. Verified the legitimate paths are unaffected: glossary-term approval is an UPDATE on a persisted term (checkUpdatedByReviewer), and inherited parent reviewers are not present on the entity at authorize-time (prepareInternal never populates reviewers; storage runs in repository.create() after authorize).

Tests

  • DefaultAuthorizerTest.authorizeDoesNotTreatSelfAssignedReviewerAsReviewerOnCreate — policy evaluation still runs when a user self-assigns as reviewer during CREATE.
  • RuleEvaluatorTest.test_isReviewer — extended so a self-assigned reviewer on a CreateResourceContext returns false.

Both fail without the corresponding guard and pass with it. Full security/policy unit suites green: DefaultAuthorizerTest (14), RuleEvaluatorTest (24), SubjectContextTest (11), ExpressionValidatorTest (35).

Greptile Summary

This PR fixes the reviewer authorization shortcut for create requests. The main changes are:

  • Blocks reviewer shortcut evaluation for CreateResourceContext in DefaultAuthorizer.
  • Applies the same create-time reviewer guard in RuleEvaluator.isReviewer().
  • Adds tests for self-assigned reviewers during create authorization and policy expression evaluation.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
openmetadata-service/src/main/java/org/openmetadata/service/security/DefaultAuthorizer.java Adds a create-context guard before reviewer shortcut authorization.
openmetadata-service/src/main/java/org/openmetadata/service/security/policyevaluator/RuleEvaluator.java Prevents isReviewer() from treating create-request reviewers as persisted reviewers.
openmetadata-service/src/test/java/org/openmetadata/service/security/DefaultAuthorizerTest.java Adds coverage that create requests with self-assigned reviewers still call policy evaluation.
openmetadata-service/src/test/java/org/openmetadata/service/security/policyevaluator/RuleEvaluatorTest.java Adds coverage that isReviewer() is false for self-assigned reviewers on create contexts.

Reviews (2): Last reviewed commit: "fix(security): don't grant reviewer auth..." | Re-trigger Greptile

Context used (3)

  • Context used - CLAUDE.md (source)
  • Context used - openmetadata-ui-core-components/CLAUDE.md (source)
  • Context used - AGENTS.md (source)

Copilot AI review requested due to automatic review settings July 14, 2026 07:49

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

✅ PR checks passed

The linked issue has a description and all required Shipping project fields set. Thanks!

@github-actions github-actions Bot added backend safe to test Add this label to run secure Github workflows on PRs labels Jul 14, 2026
@sonika-shah sonika-shah force-pushed the fix/reviewer-create-authz-bypass branch from b6a4ea8 to 43591c8 Compare July 14, 2026 07:50
Copilot AI review requested due to automatic review settings July 14, 2026 07:50

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings July 14, 2026 07:51
@sonika-shah sonika-shah force-pushed the fix/reviewer-create-authz-bypass branch from 43591c8 to ad14e4f Compare July 14, 2026 07:51

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings July 14, 2026 07:53
@sonika-shah sonika-shah force-pushed the fix/reviewer-create-authz-bypass branch from ad14e4f to 2ecd574 Compare July 14, 2026 07:53

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

DefaultAuthorizer.authorize() short-circuits policy evaluation when the
caller is a reviewer of the resource. For CREATE operations the
ResourceContext is a CreateResourceContext whose entity is the unsaved,
caller-supplied request body. A user could therefore add themselves to
the reviewers field of a create request to make isReviewer() return true
and bypass RBAC, creating entities (e.g. Data Products) they have no
Create permission for. This affects both the REST API and the MCP tool,
which share the authorization path.

Gate the reviewer shortcut so it only applies to already persisted
entities, never to a CreateResourceContext. Reviewer-based authorization
continues to work for Edit/View/approval operations on existing entities.

Adds a regression test asserting policy evaluation still runs when a user
self-assigns as a reviewer during CREATE.
@sonika-shah sonika-shah force-pushed the fix/reviewer-create-authz-bypass branch from 2ecd574 to f75227c Compare July 14, 2026 08:23
Copilot AI review requested due to automatic review settings July 14, 2026 08:23

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@gitar-bot

gitar-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

Closes a privilege escalation vulnerability where callers could bypass RBAC during entity creation by self-assigning as reviewers. The authorization shortcut is now gated to exclude unpersisted entities, ensuring policies are correctly evaluated for all CREATE requests.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonika-shah sonika-shah added the To release Will cherry-pick this PR into the release branch label Jul 14, 2026
@sonika-shah sonika-shah enabled auto-merge (squash) July 14, 2026 09:17
@sonarqubecloud

Copy link
Copy Markdown

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

Labels

backend safe to test Add this label to run secure Github workflows on PRs To release Will cherry-pick this PR into the release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Authorization Bypass: Self-Assigned Reviewer Can Bypass Create Permission

3 participants