RSTR-INJ-002 — Python subprocess(shell=True) / os.system

Summary

Calling subprocess.run (or .call / .Popen) with shell=True — or using os.system — runs the argument through /bin/sh. Any attacker-controlled substring is then interpreted as shell syntax, so ;, &&, $(...), backticks, redirections, and globbing all work against you.

Severity

High.

Languages

Python.

What rastray flags

import subprocess, os

subprocess.run(f'ls {path}', shell=True)         # ← flagged
subprocess.Popen(cmd, shell=True)                # ← flagged
os.system('curl ' + url)                          # ← flagged

What rastray deliberately does not flag

  • subprocess.run(['ls', path]) — argv form, no shell.
  • subprocess.run('ls', shell=False) — explicit opt-out.

How to fix it

Pass an argv list and leave shell=False (the default):

import subprocess

subprocess.run(['ls', path], check=True)
subprocess.run(['curl', '--fail', url], check=True)

If you genuinely need shell features (pipes, here-docs), build the command from constants and quote any variable parts with shlex.quote:

import shlex, subprocess

cmd = f'tar czf - {shlex.quote(path)} | gpg --encrypt -r {shlex.quote(recipient)}'
subprocess.run(cmd, shell=True, check=True)

Still — the argv form is almost always better; reach for the shell only when the pipeline structure cannot be expressed without it.

References