VNX-426: Untrusted Search Path
Reports Python code that finds modules, libraries or commands through the current working directory: sys.path and site.addsitedir entries that are empty, '.', relative or os.getcwd(); PATH-like variables given an empty or relative element; commands run by a cwd-relative path without cwd=; bare command names run after os.setuid(0); and ctypes loads of relative paths or bare DLL names.
| Field | Value |
|---|---|
| Rule ID | VNX-426 |
| Severity | High |
| SARIF level | error |
| Kind | sast |
| Languages | Python |
| CWE | CWE-426 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:H/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H |
| Tags | untrusted-search-path cwe-426 |
| Source | internal/sast/rules/vnx-426.rego |
Overview
VNX-426 maps to CWE-426: Untrusted Search Path. When a program looks for code in a place it does not control, whoever controls that place decides what runs. For most programs that place is the current working directory, which is wherever the program happened to be started.
Reported in Python:
sys.path.insert/append/extend(andsys.path[:0] =) with"",".","..", a relative literal,os.getcwd(),os.curdir,Path.cwd()oros.path.abspathof a relative literal.os.environ[...] =,os.putenvor anenvdict item settingPATH,PYTHONPATH,LD_LIBRARY_PATH,LD_PRELOAD,DYLD_LIBRARY_PATHorDYLD_INSERT_LIBRARIESto a value with an empty element (a leading, trailing or doubled separator),"."or a relative directory.subprocessrun/call/check_call/check_output/Popen,os.system,os.popen,os.exec*andos.spawn*running./tool,../bin/xorbin/xwithout acwd=argument.- A command run by bare name in a file that makes the process root (
os.setuid(0),os.seteuid(0),os.setresuid(0, ...)). ctypesCDLL/WinDLL/OleDLL/PyDLL/LoadLibraryof a relative path or of a bare.dllname that is not a Windows KnownDLL.
What Gets Flagged
sys.path.insert(0, "") # FLAGGED
os.environ["PATH"] = "." + os.pathsep + os.environ["PATH"] # FLAGGED
subprocess.run(["./bin/deploy", target], check=True) # FLAGGED
lib = ctypes.CDLL("./libfast.so") # FLAGGED
What Is Not Flagged
- Paths anchored to the program (
os.path.dirname(__file__)),sys.prefixor an absolute directory. - Commands run by bare name in an unprivileged program (normal
PATHuse), and calls that passcwd=. - Bare sonames (
"libc.so.6"), KnownDLLs ("kernel32") andctypes.util.find_library. - Sphinx
docs/conf.py, test files, comments and string literals.
C and C++ search-path elements (LoadLibrary, dlopen, setenv("PATH", ...)) are VNX-427.
Remediation
Anchor every lookup to a location the program controls:
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
subprocess.run([os.path.join(HERE, "bin", "deploy"), target], check=True)
lib = ctypes.CDLL(os.path.join(HERE, "libfast.so"))
A privileged program should reset PATH to a fixed value and call commands by absolute path.
References
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-426
// nosec vnx-426
Or record an ignore rule: vulnetix ignore add --rule vnx-426 --reason "...". See Suppressing findings.