PluginsController only requires user privileges for potentially sensitive actions #6957

Closed
opened 2025-12-22 05:02:06 +01:00 by backuprepo · 2 comments
Owner

Originally created by @felix920506 on GitHub (Apr 23, 2025).

split from #5415

Includes, but is not limited to: Listing all plugins on the server without being admin, changing plugin settings, listing plugin settings without being admin. This includes the possibility of retrieving LDAP access credentials without admin privileges. In specific conditions it can also lead to attacks that leak entire user passwords, e.g by changing the remote LDAP server to an attacker controlled server.
Potential fix: Require admin privileges for all potentially sensitive plugin endpoints, e.g all non-legacy endpoints.

Originally created by @felix920506 on GitHub (Apr 23, 2025). split from #5415 Includes, but is not limited to: Listing all plugins on the server without being admin, changing plugin settings, listing plugin settings without being admin. This includes the possibility of retrieving LDAP access credentials without admin privileges. In specific conditions it can also lead to attacks that leak entire user passwords, e.g by changing the remote LDAP server to an attacker controlled server. Potential fix: Require admin privileges for all potentially sensitive plugin endpoints, e.g all non-legacy endpoints.
backuprepo 2025-12-22 05:02:06 +01:00
Author
Owner

@Fmstrat commented on GitHub (Jul 1, 2025):

I've conducted some testing against the LDAP plugin, since this seems to be the biggest vulnerability from the original ticket as it can lead to full priviledge escalation into a full domain network beyond the Jellyfin Server. From what I can tell, the latest endpoints for the LDAP service return a blank result for any non-admin tokens.

Test script:

URL="https://my.server"
LDAP_PLUGIN="958aad66-3784-4d2a-b89a-a7b6fab6e25c"
JF_USER="non-admin"
JF_PASS="pass"

TOKEN=$(curl -s "${URL}/Users/authenticatebyname" -X POST \
    -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0' \
    -H 'Accept: application/json' \
    -H 'Accept-Language: en-US,en;q=0.8,fr;q=0.7,ja;q=0.5,de;q=0.3,es;q=0.2' \
    -H 'Accept-Encoding: gzip, deflate, br, zstd' \
    -H 'Authorization: MediaBrowser Client="Jellyfin Web", Device="Firefox", DeviceId="f9fjfag9bk49fkTsgVWJ1bnR1OyBMaW51eCB4ODZfNjQ7IHJ2OjEyOC4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94LzEyOC4wfDE3NTEzNzAxfeiaje1", Version="10.10.5"' \
    -H 'Content-Type: application/json' \
    -H "Origin: ${URL}" \
    -H 'DNT: 1' \
    -H 'Connection: keep-alive' \
    -H 'Sec-Fetch-Dest: empty' \
    -H 'Sec-Fetch-Mode: cors' \
    -H 'Sec-Fetch-Site: same-origin' \
    -H 'Priority: u=0' \
    -H 'TE: trailers' \
    --data-raw "{\"Username\":\"${JF_USER}\",\"Pw\":\"${JF_PASS}\"}" |jq -r '.AccessToken')

curl -v "${URL}/Plugins/${LDAP_PLUGIN}/Configuration" \
    -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0' \
    -H 'Accept: application/json' \
    -H 'Accept-Language: en-US,en;q=0.8,fr;q=0.7,ja;q=0.5,de;q=0.3,es;q=0.2' \
    -H 'Accept-Encoding: gzip, deflate, br, zstd' \
    -H "Authorization: MediaBrowser Client=\"Jellyfin Web\", Device=\"Firefox\", DeviceId=\"f9fjfag9bk49fkTsgVWJ1bnR1OyBMaW51eCB4ODZfNjQ7IHJ2OjEyOC4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94LzEyOC4wfDE3NTEzNzAxfeiaje1\", Version=\"10.10.5\", Token=\"${TOKEN}\"" \
    -H 'DNT: 1' \
    -H 'Connection: keep-alive' \
    -H 'Sec-Fetch-Dest: empty' \
    -H 'Sec-Fetch-Mode: cors' \
    -H 'Sec-Fetch-Site: same-origin' \
    -H 'Priority: u=4' \
    -H 'TE: trailers'

When using an admin user, the above call returns JSON, when using a non-admin user, it returns blank.

To be clear, this isn't a full test as there may be other endpoints that are an issue, I'm not entirely familiar with the Jellyfin API layer.

@Fmstrat commented on GitHub (Jul 1, 2025): I've conducted some testing against the LDAP plugin, since this seems to be the biggest vulnerability from the original ticket as it can lead to full priviledge escalation into a full domain network beyond the Jellyfin Server. From what I can tell, the latest endpoints for the LDAP service return a blank result for any non-admin tokens. Test script: ```bash URL="https://my.server" LDAP_PLUGIN="958aad66-3784-4d2a-b89a-a7b6fab6e25c" JF_USER="non-admin" JF_PASS="pass" TOKEN=$(curl -s "${URL}/Users/authenticatebyname" -X POST \ -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0' \ -H 'Accept: application/json' \ -H 'Accept-Language: en-US,en;q=0.8,fr;q=0.7,ja;q=0.5,de;q=0.3,es;q=0.2' \ -H 'Accept-Encoding: gzip, deflate, br, zstd' \ -H 'Authorization: MediaBrowser Client="Jellyfin Web", Device="Firefox", DeviceId="f9fjfag9bk49fkTsgVWJ1bnR1OyBMaW51eCB4ODZfNjQ7IHJ2OjEyOC4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94LzEyOC4wfDE3NTEzNzAxfeiaje1", Version="10.10.5"' \ -H 'Content-Type: application/json' \ -H "Origin: ${URL}" \ -H 'DNT: 1' \ -H 'Connection: keep-alive' \ -H 'Sec-Fetch-Dest: empty' \ -H 'Sec-Fetch-Mode: cors' \ -H 'Sec-Fetch-Site: same-origin' \ -H 'Priority: u=0' \ -H 'TE: trailers' \ --data-raw "{\"Username\":\"${JF_USER}\",\"Pw\":\"${JF_PASS}\"}" |jq -r '.AccessToken') curl -v "${URL}/Plugins/${LDAP_PLUGIN}/Configuration" \ -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0' \ -H 'Accept: application/json' \ -H 'Accept-Language: en-US,en;q=0.8,fr;q=0.7,ja;q=0.5,de;q=0.3,es;q=0.2' \ -H 'Accept-Encoding: gzip, deflate, br, zstd' \ -H "Authorization: MediaBrowser Client=\"Jellyfin Web\", Device=\"Firefox\", DeviceId=\"f9fjfag9bk49fkTsgVWJ1bnR1OyBMaW51eCB4ODZfNjQ7IHJ2OjEyOC4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94LzEyOC4wfDE3NTEzNzAxfeiaje1\", Version=\"10.10.5\", Token=\"${TOKEN}\"" \ -H 'DNT: 1' \ -H 'Connection: keep-alive' \ -H 'Sec-Fetch-Dest: empty' \ -H 'Sec-Fetch-Mode: cors' \ -H 'Sec-Fetch-Site: same-origin' \ -H 'Priority: u=4' \ -H 'TE: trailers' ``` When using an admin user, the above call returns JSON, when using a non-admin user, it returns blank. To be clear, this isn't a full test as there may be other endpoints that are an issue, I'm not entirely familiar with the Jellyfin API layer.
Author
Owner

@thornbill commented on GitHub (Oct 28, 2025):

This has been fixed since 10.9.0: https://github.com/jellyfin/jellyfin/pull/11436

@thornbill commented on GitHub (Oct 28, 2025): This has been fixed since 10.9.0: https://github.com/jellyfin/jellyfin/pull/11436
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: starred/jellyfin#6957
No description provided.