Forums Bug Reports Thread

SID library Play button leaks CSRF token into inline onclick in cacheable markup

Patrick Bass · Jun 6 · 11 · 1 Locked
[Minor] [Normal Priority] [Bug Fixed] [Always Reproduces]
🚀 OP Jun 6, 2026 9:48pm

Area: Files/photos (re-run) (audit p5r) · Surface: /sid-library (SidLibraryController@index → sid-library/index.php) · Dimension: law6-config-exposure · Severity: minor

Two problems on one line. (1) The page renders the CSRF token directly into static HTML inline-onclick attributes; the rest of the codebase relies on app.min.js auto-injecting X-CSRF-TOKEN on non-GET XHR/fetch (per Controllers CLAUDE.md), so hand-passing the token here is both redundant and risky if this page is ever cached/proxied (token in body). (2) Inline onclick handlers don't carry the script nonce and are the legacy pattern the codebase is trying to move off (cf. the same file's data-sid-decade/data-sid-autosubmit delegated handlers just above it). The adjacent decade chips already use delegated addEventListener; the Play button should too.

Evidence

platform/templates/sid-library/index.php:188-190 — `<button type="button" class="btn btn--primary btn--xs" onclick="SidPlayer.play(<?= (int) $f['id'] ?>, '<?= $e($csrfToken ?? '') ?>')" title="Play in browser">`. The CSRF token is interpolated into an inline onclick attribute, repeated for every row.

Suggested fix. Drop the token argument and let app.min.js inject the CSRF header; switch the button to `data-sid-play data-id` and bind a delegated click handler in the existing nonce'd <script> block, matching the decade-chip pattern already in this file.

Filed by the automated tenant-app audit and adversarially evidence-verified. Status: verified. Open — not yet actioned.


Patrick Bass
@mobieus

🚀 Jun 7, 2026 5:53am

Resolved — fixed and deployed. Commit 839ae393122a, shipped dev-first then to all tenants on 2026-06-06.

Replaced the Play button's inline onclick="SidPlayer.play(id, csrfToken)" with data-sid-play data-id attributes, and added a delegated click handler in the existing nonce'd <script> block that calls SidPlayer.play(id) with no token (app.min.js injects the CSRF header). Matches the data-attribute/delegated pattern already used by the decade chips; lint clean.

Status: fixed. Thread closed and locked.


Patrick Bass
@mobieus

Log in or register to reply to this thread.