Skip to content
GHSA Qwh6 X463 Ccf4

GHSA Qwh6 X463 Ccf4

github.com • September 28, 2026

A station user with only View Station Page can call GET /api/station/{station_id}/vue/profile and receive the station’s Icecast/Shoutcast admin , source , and relay passwords in the JSON response.

Those credentials are treated as Broadcasting -sensitive in the Vue UI ( FrontendPanel.vue gates display on StationPermissions.Broadcasting ). The API route does not: the /vue group requires only StationPermissions::View , and ProfileAction always serializes the three password fields.

This is authenticated station-scoped privilege escalation / sensitive info disclosure — not unauthenticated, and not “admin can admin.” Confirmed end-to-end: a View-only session receives the passwords; the leaked admin_pw authenticates to Icecast admin ( /admin/stats → HTTP 200).

Tested: commit 3f9d6ff626745d9aa20a7158eec7a8583ed635e0 (rolling), Docker

Components: backend/config/routes/api_station_vue.php ( GET /vue/profile under View-only group) backend/src/Controller/Api/Stations/Vue/ProfileAction.php (unconditional password fields) Contrast (correct UI gate): frontend/components/Stations/Profile/FrontendPanel.vue

backend/config/routes/api_station_vue.php ( GET /vue/profile under View-only group)

backend/src/Controller/Api/Stations/Vue/ProfileAction.php (unconditional password fields)

Contrast (correct UI gate): frontend/components/Stations/Profile/FrontendPanel.vue

Authenticated account (session cookie or API key) with StationPermissions::View on a station

Without Broadcasting (or equivalent) on that station

Station frontend configured (Icecast/Shoutcast passwords present in frontend_config )

On multi-user / multi-role installs, a View-only staff account, guest observer, or View-scoped API key can obtain live broadcast frontend secrets that the product’s own UI treats as Broadcasting-only. With the leaked Icecast admin_pw , the attacker authenticates to the Icecast admin interface (listener/stats/admin actions such as kicking clients) without holding Broadcasting in AzuraCast.

Single-admin installs are lower practical risk; the API still violates the permission model.

Attacker holds station View only (no Broadcasting).

Attacker requests GET /api/station/{id}/vue/profile (browser session + CSRF, or API key).

Response includes frontendAdminPassword , frontendSourcePassword , frontendRelayPassword .

Attacker uses admin_pw against Icecast admin (e.g. /admin/stats ).

Environment: AzuraCast Docker, web on , Icecast on port 8000 , commit 3f9d6ff .

As Super Admin, create a role with only “View Station Page” for the target station. Create a user with that role (no Broadcasting, no Profile, no global admin).

As Super Admin, create a role with only “View Station Page” for the target station. Create a user with that role (no Broadcasting, no Profile, no global admin).

Log in as that View-only user in a browser (e.g. through Burp). Open the station management / Profile page so the Vue client loads profile props.

Log in as that View-only user in a browser (e.g. through Burp). Open the station management / Profile page so the Vue client loads profile props.

In Burp HTTP history (or Repeater), inspect:

In Burp HTTP history (or Repeater), inspect:

No X-API-Key required when using a normal login session.

Observe HTTP 200 with plaintext fields (values redacted here):

Confirm the same View-only principal is denied Broadcasting surfaces:

Confirm UI contrast: as the same user, the Profile Broadcasting credentials panel is not rendered ( FrontendPanel.vue v-if on Broadcasting). Secrets are still present in the API response from step 4.

Confirm UI contrast: as the same user, the Profile Broadcasting credentials panel is not rendered ( FrontendPanel.vue v-if on Broadcasting). Secrets are still present in the API response from step 4.

Impact check : authenticate to Icecast with the leaked admin password:

Impact check : authenticate to Icecast with the leaked admin password:

Wrong credentials → HTTP 401 / empty body.

Expected: Password fields omitted (or request denied) unless the caller has Broadcasting. Actual: View is enough; passwords always returned.

Route group applies only View; /profile adds no Broadcasting middleware (unlike /files / /podcasts ):

Controller always returns frontend passwords:

UI-only gate (does not protect the API):

Preferred: In ProfileAction (or a response mapper), omit frontendAdminPassword , frontendSourcePassword , and frontendRelayPassword unless the ACL grants StationPermissions::Broadcasting .

Do not rely on the Vue v-if alone for secrets; keep it as defense-in-depth.

Avoid gating the entire /vue/profile response on Broadcasting if View still needs non-secret profile fields strip secrets server-side instead.

Extracted Entities