Area: Files, photos, gallery, ansi (audit p5) · Surface: POST /photos/item/{id}/comment (PhotoGalleryController@addComment) · Dimension: security · Severity: major
OWASP A01:2021 Broken Access Control. Any authenticated user can write comment rows onto photos in albums set to 'only me' or 'friends' (the owner/their friends will see attacker-injected comments on private content), and can create orphan comment rows against item_ids that don't exist or were deleted. This enables harassment/spam against private galleries and pollutes the comments table.
Evidence
platform/src/Controllers/PhotoGalleryController.php:712-731 — addComment() inserts straight into photo_comments with no item-existence check and no album visibility check:
```php
public function addComment(string $id): void
{
$user = $this->requireAuth();
$this->validateCsrf();
$body = trim((string) ($_POST['body'] ?? ''));
if ($body === '') $this->json(['ok' => false, 'error' => 'empty'], 400);
$this->db->execute(
'INSERT INTO photo_comments (item_id, user_id, body) VALUES (:i, :u, :b)',
['i' => (int) $id, 'u' => (int) $user['id'], 'b' => $body]
);
...
}
```
No PhotoAlbumItem::findById, no PhotoAlbum::viewableBy. Compare to reportItem() (same file, line 1042-1058) and tagItem() (line 774-809) which both load the item+album and gate on viewableBy. CSRF is present (validateCsrf, line 715), so this is purely an authorization gap, not CSRF.
Suggested fix. Load the item and parent album, 404 if missing, and require PhotoAlbum::viewableBy($album, (int)$user['id']) before INSERT — the same gate already used by reportItem() and tagItem() in this controller.
Filed by the automated tenant-app audit and adversarially evidence-verified. Status: verified. Open — not yet actioned.
Patrick Bass
@mobieus