CVE-2026-39957 Overview
CVE-2026-39957 is an Authorization Bypass vulnerability in Lychee, a free, open-source photo-management tool. A SQL operator-precedence bug in the SharingController::listAll() method causes the orWhereNotNull('user_group_id') clause to escape the ownership filter applied by the when() block. This flaw allows any authenticated non-admin user with upload permission who owns at least one album to retrieve all user-group-based sharing permissions across the entire instance, including private albums owned by other users. The vulnerability has been fixed in version 7.5.4.
Critical Impact
Authenticated users can access sharing permissions for private albums they do not own, potentially exposing sensitive information about user groups and album access configurations across the entire Lychee instance.
Affected Products
- Lychee versions prior to 7.5.4
Discovery Timeline
- 2026-04-09 - CVE CVE-2026-39957 published to NVD
- 2026-04-09 - Last updated in NVD database
Technical Details for CVE-2026-39957
Vulnerability Analysis
This vulnerability stems from improper SQL query construction within the SharingController::listAll() method in Lychee's photo management application. The core issue is a SQL operator-precedence bug (CWE-863: Incorrect Authorization) where the logical OR operation in the query escapes the intended ownership filter boundaries.
When the orWhereNotNull(APC::USER_GROUP_ID) clause is executed without proper grouping, it creates a logical condition that bypasses the ownership check entirely. The query was intended to retrieve sharing permissions only for albums owned by the authenticated user, but the improper precedence allows the OR condition to match any record with a non-null user_group_id, regardless of album ownership.
The attack requires the user to be authenticated with upload permissions and own at least one album, but these are relatively common privileges in multi-user Lychee deployments, making exploitation accessible to many legitimate users.
Root Cause
The root cause is a missing query grouping that caused SQL logical operator precedence to be evaluated incorrectly. The original code used separate whereNotNull() and orWhereNotNull() calls without wrapping them in a closure, allowing the OR condition to apply globally rather than within the ownership-filtered context. This is a common pattern mistake in ORM query builders where developers assume linear query chaining maintains logical grouping, but SQL's precedence rules cause OR clauses to escape the intended filter scope.
Attack Vector
An attacker with a standard authenticated user account (having upload permission and owning at least one album) can exploit this vulnerability through normal API interactions with the sharing controller endpoint. By requesting the list of sharing permissions, the malformed query returns all user-group-based sharing entries across the entire instance rather than just those belonging to the attacker's albums.
The following code shows the security patch that addresses this vulnerability:
fn ($q) => $q->whereIn('base_album_id', BaseAlbumImpl::select('id')
->where('owner_id', '=', Auth::id()))
);
- $query = $query->whereNotNull(APC::USER_ID);
- $query = $query->orWhereNotNull(APC::USER_GROUP_ID);
+ $query = $query->where(fn ($q) => $q->whereNotNull(APC::USER_ID)
+ ->orWhereNotNull(APC::USER_GROUP_ID));
$query = $query->orderBy('base_album_id', 'asc');
return AccessPermissionResource::collect($query->get());
Source: GitHub Commit Update
The fix wraps the whereNotNull() and orWhereNotNull() clauses within a closure passed to where(), ensuring proper SQL grouping so the OR condition is evaluated within the ownership filter context.
Detection Methods for CVE-2026-39957
Indicators of Compromise
- Unusual API requests to sharing permission endpoints from non-admin users
- Access logs showing bulk retrieval of sharing data by users who own few albums
- Database query logs revealing unfiltered access to AccessPermission records
Detection Strategies
- Monitor application logs for requests to SharingController::listAll() returning unexpectedly large result sets
- Implement anomaly detection on API responses that return sharing permissions for albums not owned by the requesting user
- Review audit trails for users accessing sharing information for albums outside their ownership scope
Monitoring Recommendations
- Enable detailed logging for the sharing controller endpoints to track permission enumeration attempts
- Configure alerts for users accessing sharing permissions that exceed their typical access patterns
- Perform periodic audits of database queries to identify improper authorization filter bypasses
How to Mitigate CVE-2026-39957
Immediate Actions Required
- Upgrade Lychee to version 7.5.4 or later immediately
- Review access logs for potential exploitation of this vulnerability prior to patching
- Audit sharing permissions to identify if any sensitive album configurations may have been exposed
Patch Information
The vulnerability is addressed in Lychee version 7.5.4. The fix is available in commit 76a3f0513eca6458bf7f8c337c1ad65e59b22bcb. Organizations should update through their standard package management workflow or by pulling the latest release from the LycheeOrg GitHub repository. Additional details are available in the GitHub Security Advisory GHSA-4v4c-g2jv-4g25 and Pull Request #4264.
Workarounds
- Restrict upload permissions to trusted users only until the patch can be applied
- Temporarily disable or limit access to the sharing management endpoints at the web server or firewall level
- If feasible, temporarily restrict user registration or new account creation to minimize exposure
# Configuration example
# Temporarily restrict access to sharing endpoints via nginx
# Add to your Lychee server block until patching is complete
location ~ /api/v2/sharing {
# Allow only admin IP addresses
allow 192.168.1.0/24;
deny all;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

