SC002: NoInsecureFunctions
Overview
| Property | Value |
|---|---|
| ID | SC002 |
| Name | NoInsecureFunctions |
| Group | security |
| Severity | WARNING |
Description
Uses AST analysis to detect potentially dangerous function calls that can lead to code injection, arbitrary code execution, or insecure deserialization vulnerabilities.
What it checks
The check scans all Python files for:
eval() and exec()
These built-in functions execute arbitrary Python code and are dangerous when used with untrusted input:
# Dangerous: allows code injection
result = eval(user_input)
exec(user_provided_code)pickle.load() and pickle.loads()
Pickle deserialization can execute arbitrary code during unpickling:
# Dangerous: arbitrary code execution during load
import pickle
data = pickle.load(untrusted_file)subprocess with shell=True
Shell execution can lead to command injection:
# Dangerous: shell injection possible
subprocess.run(f"ls {user_input}", shell=True)Result states
- PASSED: No insecure function calls found
- FAILED: One or more insecure function calls detected (with line numbers)
How to fix
Replace eval() with safer alternatives
# Bad: eval() for math
result = eval("2 + 2")
# Good: use ast.literal_eval() for safe literal evaluation
import ast
result = ast.literal_eval("{'key': 'value'}")
# Good: use operator module for simple math
import operator
ops = {'+': operator.add, '-': operator.sub}
result = ops['+'](2, 2)Replace pickle with JSON
# Bad: pickle (insecure)
import pickle
data = pickle.load(f)
# Good: JSON (safe for data serialization)
import json
data = json.load(f)Avoid shell=True in subprocess
# Bad: shell=True with user input
subprocess.run(f"ls {directory}", shell=True)
# Good: pass arguments as list
subprocess.run(["ls", directory])
# Good: use shlex for complex cases
import shlex
subprocess.run(shlex.split(f"ls {shlex.quote(directory)}"))Why WARNING severity?
This check is a WARNING because:
- These functions have legitimate use cases in controlled environments
- Not all uses are necessarily insecure
- Some codebases may need them for specific functionality
However, each occurrence should be carefully reviewed.
Configuration
Skip this check
[tool.pycmdcheck]
skip = ["SC002"]CLI
pycmdcheck --skip SC002