Steven's Knowledge

Security

The Python conveniences that are remote-code-execution holes -- pickle, yaml.load, eval/exec, and subprocess shell injection

Security

Several Python conveniences become remote-code-execution vulnerabilities the moment they touch untrusted input. A senior engineer treats pickle, yaml.load, eval/exec, and shell=True as red flags in review -- and knows the safe alternative for each.

Secure Deserialization and Code Execution

Several Python conveniences are remote-code-execution vulnerabilities if fed untrusted input. A senior engineer treats these as red flags in review.

import pickle, yaml, json

# pickle executes arbitrary code on load. NEVER unpickle untrusted data --
# a crafted payload runs os.system on deserialize. Use JSON for data exchange.
pickle.loads(untrusted_bytes)         # RCE: full code execution

# yaml.load is equally dangerous with the default loader. Always:
yaml.safe_load(untrusted_yaml)        # safe -- only builds basic types
yaml.load(untrusted_yaml)             # DANGER -- can instantiate arbitrary objects

# eval / exec on any string influenced by input is code injection:
eval(user_input)                      # never. There is almost always a real parser.
ast.literal_eval(user_input)          # safe: only literals (dict/list/str/num)

The same rule applies to shells. subprocess with shell=True and an interpolated string is command injection:

import subprocess
subprocess.run(f"ls {path}", shell=True)            # INJECTION if path is hostile
subprocess.run(["ls", path])                        # safe: no shell, args are a list

Defaults to internalise: json over pickle for any external boundary; yaml.safe_load always; ast.literal_eval instead of eval; argument lists instead of shell=True; and validate at the boundary with Pydantic rather than trusting structure.

On this page