CVE-2025-49011
Executive Summary
CVE-2025-49011 is a logic flaw in SpiceDB, an open-source fine-grained authorization database. The vulnerability affects schemas that use caveats on relations accessed via arrows. When resolving a CheckPermission request that involves multiple caveated branches, the evaluation logic can incorrectly return a negative (deny) response when a positive (allow) response is expected. This leads to false negatives in authorization decisions, potentially denying legitimate access.
The vulnerability has a CVSS score of 3.7 (Low), primarily due to its low impact on availability and the specific conditions required for exploitation. No public proof-of-concept (PoC) code or exploit is available. The fix is included in SpiceDB version 1.44.2.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
SpiceDB is a Go-based project. The vulnerability is in the core authorization logic, not in a dependency. However, organizations using SpiceDB as a dependency in their own Go projects should update their go.mod to reference version 1.44.2 or later. The official Docker image authzed/spicedb should be updated to the patched version.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) - The vulnerability can be triggered remotely via CheckPermission API calls.
- Attack Complexity (AC): Low (L) - No special conditions are required beyond having a schema with caveated arrows.
- Privileges Required (PR): None (N) - An unauthenticated attacker can send requests.
- User Interaction (UI): None (N) - No user action is needed.
- Scope (S): Unchanged (U) - The vulnerability does not affect other components.
- Confidentiality (C): None (N) - No data is exposed.
- Integrity (I): None (N) - No data is modified.
- Availability (A): Low (L) - The vulnerability can cause denial of legitimate access, but not a full system crash.
Threat Level: Low. The vulnerability requires a specific schema configuration (caveats on arrowed relations) and only results in false negatives for authorization checks. It does not allow privilege escalation or data exfiltration.
Deep Dive & Mechanics
SpiceDB uses a relationship-based access control (ReBAC) model. A schema defines object types, relations, and permissions. Arrows (->) are used to traverse relations. Caveats are conditions that can be attached to relations to further refine access.
The vulnerability lies in the evaluation of CheckPermission requests when multiple branches of a permission tree involve caveated relations accessed via arrows. The resolver incorrectly handles the combination of caveat results, leading to a false negative.
Technical Root Cause: When a permission is defined as a union (OR) of multiple expressions, and some of those expressions involve caveated arrows, the resolver may prematurely short-circuit or incorrectly combine the results. Specifically, if one branch evaluates to a caveated "allow" (meaning the caveat must be satisfied) and another branch evaluates to a definitive "deny", the resolver might incorrectly return "deny" instead of evaluating the caveated branch.
Example Schema (Vulnerable):
definition user {}
definition document {
relation viewer: user
relation owner: user
permission view = viewer->view_perm & viewer_caveat
permission edit = owner->edit_perm & owner_caveat
permission access = view + edit
}
In this example, view and edit are permissions that use arrows (->) to traverse to another object's permission (view_perm, edit_perm) and apply a caveat (viewer_caveat, owner_caveat). The access permission is a union of view and edit. If a user is not an owner (so edit is false) but is a viewer with a caveat that should be satisfied, the resolver might incorrectly return "deny" for access.
Vulnerable vs. Patched Code
The fix in version 1.44.2 addresses the logic in the permission resolver. The specific code change is in the dispatch package, likely in the Check or Resolve functions.
Vulnerable Code (Conceptual):
func resolvePermission(ctx context.Context, req *CheckRequest) (*CheckResponse, error) {
// ... for each branch in a union ...
for _, branch := range branches {
result, err := resolveBranch(ctx, branch)
if err != nil {
return nil, err
}
if result == ALLOW {
return &CheckResponse{Allowed: true}, nil
}
// If result is CAVEATED_ALLOW, we should continue to check other branches
// but the vulnerable code might treat it as DENY in some cases
if result == CAVEATED_ALLOW {
// BUG: Incorrectly returns DENY or ignores the caveated result
return &CheckResponse{Allowed: false}, nil
}
}
return &CheckResponse{Allowed: false}, nil
}
Patched Code (Conceptual):
func resolvePermission(ctx context.Context, req *CheckRequest) (*CheckResponse, error) {
caveatedAllowed := false
for _, branch := range branches {
result, err := resolveBranch(ctx, branch)
if err != nil {
return nil, err
}
if result == ALLOW {
return &CheckResponse{Allowed: true}, nil
}
if result == CAVEATED_ALLOW {
caveatedAllowed = true
}
}
if caveatedAllowed {
// Need to evaluate the caveat to determine final result
return evaluateCaveat(ctx, req)
}
return &CheckResponse{Allowed: false}, nil
}
Exploitation & Lab Setup
Red Team
No public exploit code is available. To demonstrate the vulnerability, set up a SpiceDB instance with a schema that uses caveats on arrowed relations.
Lab Setup:
- Deploy SpiceDB v1.44.1 (vulnerable) using Docker:
docker run -d --name spicedb-vuln -p 50051:50051 authzed/spicedb:v1.44.1 serve --grpc-preshared-key "testkey" - Create a schema with caveated arrows (e.g., the example in the Deep Dive section).
- Write relationships that create a scenario where a user should be allowed but is denied.
- Send a CheckPermission request for the user and observe the false negative.
Exploitation Steps:
- No specific exploit script is available. The attack is purely logical and requires crafting specific schema and relationship data.
Blue Team
Detection:
- Monitor SpiceDB logs for unexpected "deny" responses to CheckPermission requests.
- Look for patterns where a user is denied access but should be allowed based on the schema.
- Use the detection rules below to identify potential exploitation attempts.
Mitigation:
- Immediately upgrade to SpiceDB v1.44.2 or later.
- As a workaround, avoid using caveats on relations accessed via arrows in the schema.
Indicators of Compromise (IOCs)
- Log Entry:
CheckPermission denied for user X on resource Ywhere the schema and relationships indicate the user should be allowed. - Anomalous Behavior: Repeated CheckPermission requests for the same user/resource pair returning inconsistent results.
- Schema Pattern: Schemas that use caveats on arrowed relations (e.g.,
permission foo = bar->baz & some_caveat).
Detection Engineering
YARA Rule
rule CVE_2025_49011_SpiceDB_Caveat_Arrow_Logic_Flaw {
meta:
description = "Detects SpiceDB log entries indicating potential exploitation of CVE-2025-49011"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-49011"
strings:
$log_pattern = /CheckPermission denied for user \S+ on resource \S+/
$schema_pattern = /permission \w+ = \w+->\w+ & \w+/
condition:
$log_pattern or $schema_pattern
}
Sigma Rule
title: SpiceDB CVE-2025-49011 Exploitation Attempt
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects potential exploitation of CVE-2025-49011 in SpiceDB logs
author: Valters IT
date: 2025-04-10
logsource:
product: spicedb
service: authorization
detection:
selection:
message|contains: "CheckPermission denied"
condition: selection
falsepositives:
- Legitimate denied access
level: low
Suricata Rule
alert tcp any any -> any 50051 (msg:"SpiceDB CVE-2025-49011 Potential Exploitation"; content:"CheckPermission"; content:"denied"; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade SpiceDB to version 1.44.2 or later.
- If upgrade is not possible, remove caveats from any relation that is accessed via an arrow in the schema.
Long-Term Actions:
- Review all schemas for the use of caveats on arrowed relations.
- Implement monitoring for unexpected authorization denials.
- Regularly update SpiceDB to the latest version.
Workaround:
- Do not use caveats on relations that are accessed via arrows. For example, change:
to:permission view = viewer->view_perm & viewer_caveat
(if the caveat can be applied directly to the relation instead of the arrowed permission).permission view = viewer & viewer_caveat
Valters IT
Senior DevSecOps & Cyber Threat Intelligence Analyst