Problem
The version parameter accepted by upgrade(version=...) is interpolated twice into the download URL with no validation:
update_file = f"WLED_{version}_{architecture}{ethernet}.bin{gzip}"
download_url = (
f"https://github.com/{repo}/releases/download/v{version}/{update_file}"
)
A value such as version="0.14.0/../../attacker/wled-mal/releases/download/v9.9.9/payload" is normalized by yarl/aiohttp into a path that points at a different release in a different repository. The same hole exists for the repo argument, which is appended raw and defaults to wled/WLED. Any downstream application that takes version/repo from user input (Home Assistant integrations, web dashboards, etc.) inherits this URL-injection primitive.
Why This Matters
Allows an attacker who controls the version (or repo) input — for instance via a web UI that passes user input straight to this library — to force download of firmware from an arbitrary GitHub repository, which is then flashed onto the target device.
Suggested Fix
Validate version against a strict semantic-version pattern (^v?\d+\.\d+\.\d+(?:[-+.][A-Za-z0-9.]+)?$) and repo against ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ before use. Raise WLEDUpgradeError on mismatch:
import re
if not re.match(r"^\d+\.\d+\.\d+([-+.][A-Za-z0-9.]+)?$", str(version)):
raise WLEDUpgradeError(f"Invalid version: {version!r}")
if not re.match(r"^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$", repo):
raise WLEDUpgradeError(f"Invalid repo: {repo!r}")
Details
|
|
| Severity |
🟡 Medium |
| Category |
request_handling |
| Location |
src/wled/wled.py:702-716 |
| Effort |
⚡ Quick fix |
🤖 Created by Kōan from audit session
Problem
The
versionparameter accepted byupgrade(version=...)is interpolated twice into the download URL with no validation:A value such as
version="0.14.0/../../attacker/wled-mal/releases/download/v9.9.9/payload"is normalized by yarl/aiohttp into a path that points at a different release in a different repository. The same hole exists for therepoargument, which is appended raw and defaults towled/WLED. Any downstream application that takesversion/repofrom user input (Home Assistant integrations, web dashboards, etc.) inherits this URL-injection primitive.Why This Matters
Allows an attacker who controls the
version(orrepo) input — for instance via a web UI that passes user input straight to this library — to force download of firmware from an arbitrary GitHub repository, which is then flashed onto the target device.Suggested Fix
Validate
versionagainst a strict semantic-version pattern (^v?\d+\.\d+\.\d+(?:[-+.][A-Za-z0-9.]+)?$) andrepoagainst^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$before use. RaiseWLEDUpgradeErroron mismatch:Details
src/wled/wled.py:702-716🤖 Created by Kōan from audit session