Question presented to candidate: "Your Python service needs to call an external tool, say an image converter, on a file a user uploaded. How do you run it with subprocess, and what can go wrong if you do it carelessly?"
What a strong answer should cover:
- Use
subprocess.run()with the command as a list of arguments; the defaultshell=Falsestarts the program directly, so user text stays one argument and cannot add commands. - Why
shell=Truewith string building is command injection (name; rm -rf ~), andshlex.quote/shlex.joinfor the rare case a shell is unavoidable. - Robustness flags:
check=True(raiseCalledProcessErroron a non-zero exit),capture_output=Trueandtext=True(str instead of bytes),timeout=(the child is killed andTimeoutExpiredraised), plusFileNotFoundErrorwhen the program is missing. - Control what the child sees:
input=,cwd=,env=(merge withos.environrather than replacing it),shutil.whichto find the program. Popenfor streaming output or building pipelines without a shell, withcommunicate()to avoid pipe deadlocks;asyncio.create_subprocess_execin async code.- Least privilege: an allow-list of programs and options, and
--before user-supplied file names so they cannot be read as options.
Clarifying questions expected:
- Which parts of the command come from the user, and does the tool accept options that could be abused?
- Do we need the output as a stream, or only at the end?
Code / implementation expected: Yes โ a subprocess.run([...], check=True, capture_output=True, text=True, timeout=...) call with its error handling.