VYPR
Moderate severityNVD Advisory· Published Feb 19, 2025· Updated Feb 19, 2025

OpenFGA Authorization Bypass

CVE-2025-25196

Description

OpenFGA is a high-performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar. OpenFGA < v1.8.4 (Helm chart < openfga-0.2.22, docker < v.1.8.4) are vulnerable to authorization bypass when certain Check and ListObject calls are executed. Users on OpenFGA v1.8.4 or previous, specifically under the following conditions are affected by this authorization bypass vulnerability: 1. Calling Check API or ListObjects with a model that has a relation directly assignable to both public access AND userset with the same type. 2. A type bound public access tuple is assigned to an object. 3. userset tuple is not assigned to the same object. and 4. Check request's user field is a userset that has the same type as the type bound public access tuple's user type. Users are advised to upgrade to v1.8.5 which is backwards compatible. There are no known workarounds for this vulnerability.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/openfga/openfgaGo
< 1.8.51.8.5

Affected products

1

Patches

1
0aee4f47e0c6

Merge commit from fork

https://github.com/openfga/openfgaAdrian TamFeb 19, 2025via ghsa
8 files changed · +411 2
  • CHANGELOG.md+1 0 modified
    @@ -27,6 +27,7 @@ Try to keep listed changes to a concise bulleted list of simple explanations of
     - Fixed incorrect invalidation by cache controller on cache iterator. [#2190](https://github.com/openfga/openfga/pull/2190), [#2216](https://github.com/openfga/openfga/pull/2216)
     - Fixed incorrect types in configuration JSON schema [#2217](https://github.com/openfga/openfga/pull/2217), [#2228](https://github.com/openfga/openfga/pull/2228).
     - Fixed `BatchCheck` API to validate presence of the `tuple_key` property of a `BatchCheckItem` [#2242](https://github.com/openfga/openfga/issues/2242)
    +- Fixed incorrect check and list objects evaluation when model has a relation directly assignable to both public access AND userset with the same type and type bound public access tuple is assigned to the object.
     
     ## [1.8.4] - 2025-01-13
     [Full changelog](https://github.com/openfga/openfga/compare/v1.8.3...v1.8.4)
    
  • internal/graph/check.go+5 0 modified
    @@ -1111,6 +1111,11 @@ func shouldCheckPublicAssignable(ctx context.Context, reqTupleKey *openfgav1.Tup
     	objectType := tuple.GetType(reqTupleKey.GetObject())
     	relation := reqTupleKey.GetRelation()
     
    +	// if the user tuple is userset, by definition it cannot be a wildcard
    +	if tuple.IsObjectRelation(reqTupleKey.GetUser()) {
    +		return false
    +	}
    +
     	isPubliclyAssignable, _ := typesys.IsPubliclyAssignable(
     		typesystem.DirectRelationReference(objectType, relation), // target
     		tuple.GetType(reqTupleKey.GetUser()),
    
  • internal/graph/check_test.go+48 0 modified
    @@ -4274,6 +4274,54 @@ func TestShouldCheckPubliclyAssigned(t *testing.T) {
     			reqTupleKey: tuple.NewTupleKey("group:1", "other_member", "group:2#member"),
     			expected:    false,
     		},
    +		{
    +			name: "mixed_public_userset_tuple_user",
    +			model: parser.MustTransformDSLToProto(`
    +	model
    +		schema 1.1
    +	type user
    +	type group
    +		relations
    +			define member: [user, user:*]
    +	type folder
    +		relations
    +			define viewer: [group, group:*, group#member]
    +	`),
    +			reqTupleKey: tuple.NewTupleKey("folder:1", "viewer", "group:1"),
    +			expected:    true,
    +		},
    +		{
    +			name: "mixed_public_userset_tuple_wilduser",
    +			model: parser.MustTransformDSLToProto(`
    +	model
    +		schema 1.1
    +	type user
    +	type group
    +		relations
    +			define member: [user, user:*]
    +	type folder
    +		relations
    +			define viewer: [group, group:*, group#member]
    +	`),
    +			reqTupleKey: tuple.NewTupleKey("folder:1", "viewer", "group:*"),
    +			expected:    true,
    +		},
    +		{
    +			name: "mixed_public_userset_tuple_userset",
    +			model: parser.MustTransformDSLToProto(`
    +	model
    +		schema 1.1
    +	type user
    +	type group
    +		relations
    +			define member: [user, user:*]
    +	type folder
    +		relations
    +			define viewer: [group, group:*, group#member]
    +	`),
    +			reqTupleKey: tuple.NewTupleKey("folder:1", "viewer", "group:1#member"),
    +			expected:    false,
    +		},
     	}
     	for _, tt := range tests {
     		t.Run(tt.name, func(t *testing.T) {
    
  • pkg/server/commands/reverseexpand/reverse_expand.go+14 1 modified
    @@ -423,6 +423,19 @@ func (c *ReverseExpandQuery) reverseExpandDirect(
     	return err
     }
     
    +func (c *ReverseExpandQuery) shouldCheckPublicAssignable(targetReference *openfgav1.RelationReference, userRef IsUserRef) (bool, error) {
    +	_, userIsUserset := userRef.(*UserRefObjectRelation)
    +	if userIsUserset {
    +		// if the user is an userset, by definition it is not public assignable
    +		return false, nil
    +	}
    +	publiclyAssignable, err := c.typesystem.IsPubliclyAssignable(targetReference, userRef.GetObjectType())
    +	if err != nil {
    +		return false, err
    +	}
    +	return publiclyAssignable, nil
    +}
    +
     func (c *ReverseExpandQuery) readTuplesAndExecute(
     	ctx context.Context,
     	req *ReverseExpandRequest,
    @@ -445,7 +458,7 @@ func (c *ReverseExpandQuery) readTuplesAndExecute(
     		relationFilter = req.edge.TargetReference.GetRelation()
     		targetUserObjectType := req.User.GetObjectType()
     
    -		publiclyAssignable, err := c.typesystem.IsPubliclyAssignable(req.edge.TargetReference, targetUserObjectType)
    +		publiclyAssignable, err := c.shouldCheckPublicAssignable(req.edge.TargetReference, req.User)
     		if err != nil {
     			return err
     		}
    
  • pkg/server/commands/reverseexpand/reverse_expand_test.go+91 0 modified
    @@ -820,3 +820,94 @@ func TestReverseExpandHonorsConsistency(t *testing.T) {
     		}
     	}
     }
    +
    +func TestShouldCheckPublicAssignable(t *testing.T) {
    +	tests := []struct {
    +		name            string
    +		model           string
    +		targetReference *openfgav1.RelationReference
    +		userRef         IsUserRef
    +		expectedResult  bool
    +		expectedError   bool
    +	}{
    +		{
    +			name: "model_non_public",
    +			model: `
    +				model
    +					schema 1.1
    +				type user
    +				type group
    +					relations
    +						define member: [user]
    +				type document
    +					relations
    +						define viewer: [user, group#member]
    +`,
    +			targetReference: typesystem.DirectRelationReference("document", "viewer"),
    +			userRef: &UserRefObject{
    +				Object: &openfgav1.Object{Type: "user", Id: "bob"},
    +			},
    +			expectedResult: false,
    +		},
    +		{
    +			name: "model_public",
    +			model: `
    +				model
    +					schema 1.1
    +				type user
    +				type group
    +					relations
    +						define member: [user]
    +				type document
    +					relations
    +						define viewer: [user, user:*, group#member]
    +`,
    +			targetReference: typesystem.DirectRelationReference("document", "viewer"),
    +			userRef: &UserRefObject{
    +				Object: &openfgav1.Object{Type: "user", Id: "bob"},
    +			},
    +			expectedResult: true,
    +		},
    +		{
    +			name: "model_public_but_request_userset",
    +			model: `
    +				model
    +					schema 1.1
    +				type user
    +				type group
    +					relations
    +						define member: [user]
    +				type document
    +					relations
    +						define viewer: [user, user:*, group#member]
    +`,
    +			targetReference: typesystem.DirectRelationReference("document", "viewer"),
    +			userRef: &UserRefObjectRelation{
    +				ObjectRelation: &openfgav1.ObjectRelation{
    +					Object:   "group",
    +					Relation: "member",
    +				},
    +			},
    +			expectedResult: false,
    +		},
    +	}
    +	for _, test := range tests {
    +		t.Run(test.name, func(t *testing.T) {
    +			mockController := gomock.NewController(t)
    +			defer mockController.Finish()
    +
    +			typeSystem, err := typesystem.New(testutils.MustTransformDSLToProtoWithID(test.model))
    +			require.NoError(t, err)
    +
    +			mockDatastore := mocks.NewMockOpenFGADatastore(mockController)
    +			dut := NewReverseExpandQuery(mockDatastore, typeSystem)
    +			publiclyAssignable, err := dut.shouldCheckPublicAssignable(test.targetReference, test.userRef)
    +			if test.expectedError {
    +				require.Error(t, err)
    +			} else {
    +				require.NoError(t, err)
    +				require.Equal(t, test.expectedResult, publiclyAssignable)
    +			}
    +		})
    +	}
    +}
    
  • tests/check/check.go+4 1 modified
    @@ -1146,6 +1146,8 @@ type usersets-user
         define ttu_and_direct_userset: [ttus#and_comp_from_direct_parent]
         define tuple_cycle2: [ttus#tuple_cycle2]
         define tuple_cycle3: [directs-user#compute_tuple_cycle3]
    +    define userset_mix_public: [directs-user#direct, directs-user:*, user, user:*]
    +    define or_userset_mix_public: [user, user:*] or userset_mix_public
     type ttus
       relations
         define direct_parent: [directs-user]
    @@ -1190,7 +1192,8 @@ type complexity3
         define compute_userset_ttu_userset: userset_ttu_userset
         define or_compute_complex3: compute_ttu_userset_ttu or compute_userset_ttu_userset
         define and_nested_complex3: [ttus#and_ttu] and compute_ttu_userset_ttu 
    -    define cycle_nested: [ttus#tuple_cycle3]   
    +    define cycle_nested: [ttus#tuple_cycle3]
    +    define or_userset_mix_public_complex3: or_userset_mix_public from userset_parent
     type complexity4
       relations
         define userset_ttu_userset_ttu: [complexity3#ttu_userset_ttu]
    
  • tests/check/check_userset.go+153 0 modified
    @@ -1462,4 +1462,157 @@ var usersetCompleteTestingModelTest = []*stage{
     			},
     		},
     	},
    +	{
    +		Name: "userset_mix_public",
    +		Tuples: []*openfgav1.TupleKey{
    +			{Object: "usersets-user:userset_mix_public_1", Relation: "userset_mix_public", User: "directs-user:userset_mix_public_1#direct"},
    +			{Object: "directs-user:userset_mix_public_1", Relation: "direct", User: "user:userset_mix_public_1"},
    +
    +			{Object: "usersets-user:userset_mix_public_user_public", Relation: "userset_mix_public", User: "user:*"},
    +
    +			{Object: "usersets-user:userset_mix_public_user_specific", Relation: "userset_mix_public", User: "user:specific"},
    +			{Object: "usersets-user:userset_mix_directs_user_public", Relation: "userset_mix_public", User: "directs-user:*"},
    +		},
    +		CheckAssertions: []*checktest.Assertion{
    +			{
    +				Name:        "valid_userset_assignment",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:userset_mix_public_1", Relation: "userset_mix_public", User: "directs-user:userset_mix_public_1#direct"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "valid_user",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:userset_mix_public_1", Relation: "userset_mix_public", User: "user:userset_mix_public_1"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "invalid_userset_assignment",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:userset_mix_public_1", Relation: "userset_mix_public", User: "directs-user:userset_mix_public_invalid#direct"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "invalid_user",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:userset_mix_public_1", Relation: "userset_mix_public", User: "user:userset_mix_public_invalid"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "user_public",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:userset_mix_public_user_public", Relation: "userset_mix_public", User: "user:any"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "user_specific",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:userset_mix_public_user_specific", Relation: "userset_mix_public", User: "user:specific"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "user_specific_other",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:userset_mix_public_user_specific", Relation: "userset_mix_public", User: "user:other"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "direct_user_public",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:userset_mix_directs_user_public", Relation: "userset_mix_public", User: "directs-user:any"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "direct_user_public_userset_1",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:userset_mix_directs_user_public", Relation: "userset_mix_public", User: "directs-user:any#direct"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "direct_user_public_userset_2",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:userset_mix_directs_user_public", Relation: "userset_mix_public", User: "directs-user:any#direct_wild"},
    +				Expectation: false,
    +			},
    +		},
    +	},
    +	{
    +		Name: "or_userset_mix_public",
    +		Tuples: []*openfgav1.TupleKey{
    +			{Object: "usersets-user:or_userset_mix_public_1", Relation: "userset_mix_public", User: "directs-user:or_userset_mix_public_1#direct"},
    +			{Object: "directs-user:or_userset_mix_public_1", Relation: "direct", User: "user:or_userset_mix_public_1"},
    +
    +			{Object: "usersets-user:or_userset_mix_public_user_public", Relation: "userset_mix_public", User: "user:*"},
    +
    +			{Object: "usersets-user:or_userset_mix_public_user_specific", Relation: "userset_mix_public", User: "user:or_specific"},
    +
    +			{Object: "usersets-user:or_userset_mix_public_2", Relation: "or_userset_mix_public", User: "user:*"},
    +
    +			{Object: "usersets-user:or_userset_mix_public_3", Relation: "or_userset_mix_public", User: "user:or_userset_mix_public_3"},
    +
    +			{Object: "usersets-user:or_userset_mix_directs_user_public", Relation: "userset_mix_public", User: "directs-user:*"},
    +		},
    +		CheckAssertions: []*checktest.Assertion{
    +			{
    +				Name:        "valid_userset_assignment",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_1", Relation: "or_userset_mix_public", User: "directs-user:or_userset_mix_public_1#direct"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "valid_user",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_1", Relation: "or_userset_mix_public", User: "user:or_userset_mix_public_1"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "invalid_userset_assignment",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_1", Relation: "or_userset_mix_public", User: "directs-user:or_userset_mix_public_invalid#direct"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "invalid_user",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_1", Relation: "or_userset_mix_public", User: "user:or_userset_mix_public_invalid"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "user_public",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_user_public", Relation: "or_userset_mix_public", User: "user:or_any"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "user_specific",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_user_specific", Relation: "or_userset_mix_public", User: "user:or_specific"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "user_specific_other",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_user_specific", Relation: "or_userset_mix_public", User: "user:or_other"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "public_user_direct_assign",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_2", Relation: "or_userset_mix_public", User: "user:any"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "specific_user_direct_assign",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_3", Relation: "or_userset_mix_public", User: "user:or_userset_mix_public_3"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "user_direct_assign_invalid_user",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_3", Relation: "or_userset_mix_public", User: "user:or_userset_mix_public_3_invalid"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "user_direct_assign_invalid_object",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_public_3_invalid", Relation: "or_userset_mix_public", User: "user:or_userset_mix_public_3"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "direct_user_public",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_directs_user_public", Relation: "or_userset_mix_public", User: "directs-user:any"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "direct_user_public_userset_1",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_directs_user_public", Relation: "or_userset_mix_public", User: "directs-user:any#direct"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "direct_user_public_userset_2",
    +				Tuple:       &openfgav1.TupleKey{Object: "usersets-user:or_userset_mix_directs_user_public", Relation: "or_userset_mix_public", User: "directs-user:any#direct_wild"},
    +				Expectation: false,
    +			},
    +		},
    +	},
     }
    
  • tests/check/complexity_three.go+95 0 modified
    @@ -824,4 +824,99 @@ var complexityThreeTestingModelTest = []*stage{
     			},
     		},
     	},
    +	{
    +		Name: "complex3_or_userset_mix_public",
    +		Tuples: []*openfgav1.TupleKey{
    +			{Object: "usersets-user:complex3_or_userset_mix_public_1", Relation: "userset_mix_public", User: "directs-user:complex3_or_userset_mix_public_1#direct"},
    +			{Object: "directs-user:complex3_or_userset_mix_public_1", Relation: "direct", User: "user:complex3_or_userset_mix_public_1"},
    +			{Object: "complexity3:complex3_or_userset_mix_public_1", Relation: "userset_parent", User: "usersets-user:complex3_or_userset_mix_public_1"},
    +
    +			{Object: "usersets-user:complex3_or_userset_mix_public_user_public", Relation: "userset_mix_public", User: "user:*"},
    +			{Object: "complexity3:complex3_or_userset_mix_public_user_public", Relation: "userset_parent", User: "usersets-user:complex3_or_userset_mix_public_user_public"},
    +
    +			{Object: "usersets-user:complex3_or_userset_mix_public_user_specific", Relation: "userset_mix_public", User: "user:or_specific"},
    +			{Object: "complexity3:complex3_or_userset_mix_public_user_specific", Relation: "userset_parent", User: "usersets-user:complex3_or_userset_mix_public_user_specific"},
    +
    +			{Object: "usersets-user:complex3_or_userset_mix_public_2", Relation: "or_userset_mix_public", User: "user:*"},
    +			{Object: "complexity3:complex3_or_userset_mix_public_2", Relation: "userset_parent", User: "usersets-user:complex3_or_userset_mix_public_2"},
    +
    +			{Object: "usersets-user:complex3_or_userset_mix_public_3", Relation: "or_userset_mix_public", User: "user:complex3_or_userset_mix_public_3"},
    +			{Object: "complexity3:complex3_or_userset_mix_public_3", Relation: "userset_parent", User: "usersets-user:complex3_or_userset_mix_public_3"},
    +
    +			{Object: "usersets-user:complex3_or_userset_mix_directs_user_public", Relation: "userset_mix_public", User: "directs-user:*"},
    +			{Object: "complexity3:complex3_or_userset_mix_directs_user_public", Relation: "userset_parent", User: "usersets-user:complex3_or_userset_mix_directs_user_public"},
    +		},
    +		CheckAssertions: []*checktest.Assertion{
    +			{
    +				Name:        "valid_userset_assignment",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_1", Relation: "or_userset_mix_public_complex3", User: "directs-user:complex3_or_userset_mix_public_1#direct"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "valid_user",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_1", Relation: "or_userset_mix_public_complex3", User: "user:complex3_or_userset_mix_public_1"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "invalid_userset_assignment",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_1", Relation: "or_userset_mix_public_complex3", User: "directs-user:complex3_or_userset_mix_public_invalid#direct"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "invalid_user",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_1", Relation: "or_userset_mix_public_complex3", User: "user:complex3_or_userset_mix_public_invalid"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "user_public",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_user_public", Relation: "or_userset_mix_public_complex3", User: "user:or_any"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "user_specific",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_user_specific", Relation: "or_userset_mix_public_complex3", User: "user:or_specific"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "user_specific_other",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_user_specific", Relation: "or_userset_mix_public_complex3", User: "user:or_other"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "public_user_direct_assign",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_2", Relation: "or_userset_mix_public_complex3", User: "user:any"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "specific_user_direct_assign",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_3", Relation: "or_userset_mix_public_complex3", User: "user:complex3_or_userset_mix_public_3"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "user_direct_assign_invalid_user",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_3", Relation: "or_userset_mix_public_complex3", User: "user:complex3_or_userset_mix_public_3_invalid"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "user_direct_assign_invalid_object",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_public_3_invalid", Relation: "or_userset_mix_public_complex3", User: "user:complex3_or_userset_mix_public_3"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "direct_user_public",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_directs_user_public", Relation: "or_userset_mix_public_complex3", User: "directs-user:any"},
    +				Expectation: true,
    +			},
    +			{
    +				Name:        "direct_user_public_userset_1",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_directs_user_public", Relation: "or_userset_mix_public_complex3", User: "directs-user:any#direct"},
    +				Expectation: false,
    +			},
    +			{
    +				Name:        "direct_user_public_userset_2",
    +				Tuple:       &openfgav1.TupleKey{Object: "complexity3:complex3_or_userset_mix_directs_user_public", Relation: "or_userset_mix_public_complex3", User: "directs-user:any#direct_wild"},
    +				Expectation: false,
    +			},
    +		},
    +	},
     }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.