Skip to content

Commit 37d584a

Browse files
committed
Refactored subtitle post-processing to use shlex.split for safer subprocess invocation (fixing CWE-78) and replaced _escape with _double_quotes for cleaner variable substitution logic.
1 parent e3bfaac commit 37d584a

2 files changed

Lines changed: 26 additions & 26 deletions

File tree

bazarr/subtitles/post_processing.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import logging
66
import subprocess
7+
import shlex
78

89
from locale import getpreferredencoding
910

@@ -15,8 +16,9 @@ def postprocessing(command, path):
1516
from ctypes import windll
1617
code_page = windll.kernel32.GetConsoleOutputCP()
1718
encoding = f"cp{code_page}"
18-
19-
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
19+
20+
args = shlex.split(command) # parse into argv list
21+
process = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE,
2022
stderr=subprocess.PIPE, encoding=encoding)
2123
# wait for the process to terminate
2224
out, err = process.communicate()

bazarr/utilities/post_processing.py

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,36 @@
88
from app.config import settings
99

1010

11-
# Wraps the input string within quotes & escapes the string
12-
def _escape(in_str):
13-
raw_map = {8: r'\\b', 7: r'\\a', 12: r'\\f', 10: r'\\n', 13: r'\\r', 9: r'\\t', 11: r'\\v', 34: r'\"', 92: r'\\'}
14-
raw_str = r''.join(raw_map.get(ord(i), i) for i in in_str)
15-
return f"\"{raw_str}\""
11+
# Wraps the input string within double quotes
12+
def _double_quotes(in_str):
13+
return f"\"{in_str}\""
1614

1715

1816
def pp_replace(pp_command, episode, subtitles, language, language_code2, language_code3, episode_language,
1917
episode_language_code2, episode_language_code3, score, subtitle_id, provider, uploader,
2018
release_info, series_id, episode_id):
21-
pp_command = re.sub(r'[\'"]?{{directory}}[\'"]?', _escape(os.path.dirname(episode)), pp_command)
22-
pp_command = re.sub(r'[\'"]?{{episode}}[\'"]?', _escape(episode), pp_command)
23-
pp_command = re.sub(r'[\'"]?{{episode_name}}[\'"]?', _escape(os.path.splitext(os.path.basename(episode))[0]),
19+
pp_command = re.sub(r'[\'"]?{{directory}}[\'"]?', _double_quotes(os.path.dirname(episode)), pp_command)
20+
pp_command = re.sub(r'[\'"]?{{episode}}[\'"]?', _double_quotes(episode), pp_command)
21+
pp_command = re.sub(r'[\'"]?{{episode_name}}[\'"]?', _double_quotes(os.path.splitext(os.path.basename(episode))[0]),
2422
pp_command)
25-
pp_command = re.sub(r'[\'"]?{{subtitles}}[\'"]?', _escape(str(subtitles)), pp_command)
26-
pp_command = re.sub(r'[\'"]?{{subtitles_language}}[\'"]?', _escape(str(language)), pp_command)
27-
pp_command = re.sub(r'[\'"]?{{subtitles_language_code2}}[\'"]?', _escape(str(language_code2)), pp_command)
28-
pp_command = re.sub(r'[\'"]?{{subtitles_language_code3}}[\'"]?', _escape(str(language_code3)), pp_command)
23+
pp_command = re.sub(r'[\'"]?{{subtitles}}[\'"]?', _double_quotes(str(subtitles)), pp_command)
24+
pp_command = re.sub(r'[\'"]?{{subtitles_language}}[\'"]?', _double_quotes(str(language)), pp_command)
25+
pp_command = re.sub(r'[\'"]?{{subtitles_language_code2}}[\'"]?', _double_quotes(str(language_code2)), pp_command)
26+
pp_command = re.sub(r'[\'"]?{{subtitles_language_code3}}[\'"]?', _double_quotes(str(language_code3)), pp_command)
2927
pp_command = re.sub(r'[\'"]?{{subtitles_language_code2_dot}}[\'"]?',
30-
_escape(str(language_code2).replace(':', '.')), pp_command)
28+
_double_quotes(str(language_code2).replace(':', '.')), pp_command)
3129
pp_command = re.sub(r'[\'"]?{{subtitles_language_code3_dot}}[\'"]?',
32-
_escape(str(language_code3).replace(':', '.')), pp_command)
33-
pp_command = re.sub(r'[\'"]?{{episode_language}}[\'"]?', _escape(str(episode_language)), pp_command)
34-
pp_command = re.sub(r'[\'"]?{{episode_language_code2}}[\'"]?', _escape(str(episode_language_code2)), pp_command)
35-
pp_command = re.sub(r'[\'"]?{{episode_language_code3}}[\'"]?', _escape(str(episode_language_code3)), pp_command)
36-
pp_command = re.sub(r'[\'"]?{{score}}[\'"]?', _escape(str(score)), pp_command)
37-
pp_command = re.sub(r'[\'"]?{{subtitle_id}}[\'"]?', _escape(str(subtitle_id)), pp_command)
38-
pp_command = re.sub(r'[\'"]?{{provider}}[\'"]?', _escape(str(provider)), pp_command)
39-
pp_command = re.sub(r'[\'"]?{{uploader}}[\'"]?', _escape(str(uploader)), pp_command)
40-
pp_command = re.sub(r'[\'"]?{{release_info}}[\'"]?', _escape(str(release_info)), pp_command)
41-
pp_command = re.sub(r'[\'"]?{{series_id}}[\'"]?', _escape(str(series_id)), pp_command)
42-
pp_command = re.sub(r'[\'"]?{{episode_id}}[\'"]?', _escape(str(episode_id)), pp_command)
30+
_double_quotes(str(language_code3).replace(':', '.')), pp_command)
31+
pp_command = re.sub(r'[\'"]?{{episode_language}}[\'"]?', _double_quotes(str(episode_language)), pp_command)
32+
pp_command = re.sub(r'[\'"]?{{episode_language_code2}}[\'"]?', _double_quotes(str(episode_language_code2)), pp_command)
33+
pp_command = re.sub(r'[\'"]?{{episode_language_code3}}[\'"]?', _double_quotes(str(episode_language_code3)), pp_command)
34+
pp_command = re.sub(r'[\'"]?{{score}}[\'"]?', _double_quotes(str(score)), pp_command)
35+
pp_command = re.sub(r'[\'"]?{{subtitle_id}}[\'"]?', _double_quotes(str(subtitle_id)), pp_command)
36+
pp_command = re.sub(r'[\'"]?{{provider}}[\'"]?', _double_quotes(str(provider)), pp_command)
37+
pp_command = re.sub(r'[\'"]?{{uploader}}[\'"]?', _double_quotes(str(uploader)), pp_command)
38+
pp_command = re.sub(r'[\'"]?{{release_info}}[\'"]?', _double_quotes(str(release_info)), pp_command)
39+
pp_command = re.sub(r'[\'"]?{{series_id}}[\'"]?', _double_quotes(str(series_id)), pp_command)
40+
pp_command = re.sub(r'[\'"]?{{episode_id}}[\'"]?', _double_quotes(str(episode_id)), pp_command)
4341
return pp_command
4442

4543

0 commit comments

Comments
 (0)