Summary
An unauthenticated path traversal vulnerability in load_preset() allows reading any .yaml file on the server filesystem.
The parsed YAML key-value pairs (including passwords, API keys, connection strings) are returned in the API response.
Details
The vulnerable code is in modules/presets.py at lines 69-75:
def load_preset(name, verbose=False):
generate_params = default_preset()
if name not in ['None', None, '']:
path = shared.user_data_dir / 'presets' / f'{name}.yaml'
if path.exists():
with open(path, 'r') as infile:
preset = yaml.safe_load(infile)
The name parameter comes from a Gradio Dropdown.
Gradio does not server-side validate dropdown values, so an attacker can POST name="../../secret/db_config" via the API.
The path resolves to presets/../../secret/db_config.yaml, escaping the intended directory.
No os.path.basename() or sanitize_filename() is applied.
The .yaml extension is always appended, limiting reads to YAML files.
PoC
- Clone the repository and start the server.
- Send a crafted API request with a traversal payload as the preset name.
- The server opens and parses the target
.yaml file, returning all key-value pairs in the Gradio response.
I verified this by cloning the repository, running the verbatim load_preset() function with name="../secret/db_config", and confirming that YAML key-value pairs (host, password, port) from outside the presets directory are returned.
poc.zip
Impact
Any .yaml file readable by the server process can be exfiltrated.
YAML is a common format for sensitive configuration: Kubernetes manifests, Docker Compose files, CI/CD configs, application settings with database credentials.
No authentication required by default.
Remediation: apply os.path.basename(name) before path construction.
We believe this qualifies as a valid security issue.
If you agree, we'd appreciate the following credit on the CVE:
Reported by Woohyun Choi, Sunwoo Lee, and Seunghyun Yoon (Korea Institute of Energy Technology, KENTECH)
Summary
An unauthenticated path traversal vulnerability in
load_preset()allows reading any.yamlfile on the server filesystem.The parsed YAML key-value pairs (including passwords, API keys, connection strings) are returned in the API response.
Details
The vulnerable code is in
modules/presets.pyat lines 69-75:The
nameparameter comes from a Gradio Dropdown.Gradio does not server-side validate dropdown values, so an attacker can POST
name="../../secret/db_config"via the API.The path resolves to
presets/../../secret/db_config.yaml, escaping the intended directory.No
os.path.basename()orsanitize_filename()is applied.The
.yamlextension is always appended, limiting reads to YAML files.PoC
.yamlfile, returning all key-value pairs in the Gradio response.I verified this by cloning the repository, running the verbatim
load_preset()function withname="../secret/db_config", and confirming that YAML key-value pairs (host, password, port) from outside the presets directory are returned.poc.zip
Impact
Any
.yamlfile readable by the server process can be exfiltrated.YAML is a common format for sensitive configuration: Kubernetes manifests, Docker Compose files, CI/CD configs, application settings with database credentials.
No authentication required by default.
Remediation: apply
os.path.basename(name)before path construction.We believe this qualifies as a valid security issue.
If you agree, we'd appreciate the following credit on the CVE:
Reported by Woohyun Choi, Sunwoo Lee, and Seunghyun Yoon (Korea Institute of Energy Technology, KENTECH)