It has security issues just when you run the function with arguments taken from users. For example:
import os
def do_clear(command): # Notice command is sent as argument from outside world and hence this makes it vulnerable
os.system(command)
If the method is called with for example
do_clear('rm -f */*')
Then it is possible that it deletes all the files of current directory. But if the 'clear' command is to be directly used, you do not have to worry about the security issue, as only 'clear' is run in all conditions. So the following function is secure enough.
def do_clear(): # Notice command is not sent as argument from outside world
os.system('cls' if os.name == 'nt' else 'clear') # This is not risky as os.system takes clear/cls command always.
Answer from Nabin on Stack OverflowIt has security issues just when you run the function with arguments taken from users. For example:
import os
def do_clear(command): # Notice command is sent as argument from outside world and hence this makes it vulnerable
os.system(command)
If the method is called with for example
do_clear('rm -f */*')
Then it is possible that it deletes all the files of current directory. But if the 'clear' command is to be directly used, you do not have to worry about the security issue, as only 'clear' is run in all conditions. So the following function is secure enough.
def do_clear(): # Notice command is not sent as argument from outside world
os.system('cls' if os.name == 'nt' else 'clear') # This is not risky as os.system takes clear/cls command always.
From os.system
The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function. See the Replacing Older Functions with the subprocess Module section in the subprocess documentation for some helpful recipes.
I recommend a test with one of the subprocess passing as parameter shell=False and see if that work on codacy. subprocess.run(['clear']) worked in my local Python interpreter, you would have to test it on codacy.
If Python 2.x, you can try:
subprocess.call(['clear'])
python - Replace os.system with os.popen for security purposes - Stack Overflow
angular - Is using os.system('curl ...') in Python truly unsafe, compared to native libraries? - Stack Overflow
Potential Security Risks of using Python at Work
file access - How does the code example in the python os module documentation create a security hole? - Stack Overflow
Videos
The objection is entirely legitimate.
Let's say that your command looks like:
def post_result(result_string):
os.system('curl http://example.com/report-result/%s' % (result_string,))
Now, what happens if you're told to report a result that contains ; rm -rf ~? The shell invoked by os.system() runs curl http://example.com/report-result/, and then it runs a second command of rm -rf ~.
Several naive attempts at fixes don't work.
Consider, for example:
# Adding double quotes should work, right?
# WRONG: ''; rm -rf ~'' doesn't work here, but $(rm -rf ~) still does.
os.system('curl http://example.com/report-result/"%s"' % (result_string,))
# ...so, how about single quotes?
# STILL WRONG: $(rm -rf ~) doesn't work on its own, but result_string="'$(rm -rf ~)'" does.
os.system("curl http://example.com/report-result/'%s'" % (result_string,))
Even if you avoid direct shell injection vulnerabilities, using a shell exposes you to other kinds of bugs.
At startup time, a shell does a number of operations based on filesystem contents and environment variables. If an untrusted user can manipulate your program into setting environment variables of their choice before calling os.system(), they can cause a file named in ENV to have its commands executed; can shadow commands with exported functions, or can cause other mischief. See ShellShock for a well-publicized historical example.
And that's before considering other things that can happen to your data. If you're passing a filename to a shell, but unknown to you it contains whitespace and glob characters, that filename can be split into / replaced with other names.
The official Python documentation warns against shell use.
Quoting a warning from the Python subprocess module documentation, which is also relevant here:
Warning: Executing shell commands that incorporate unsanitized input from an untrusted source makes a program vulnerable to shell injection, a serious security flaw which can result in arbitrary command execution. For this reason, the use of
shell=Trueis strongly discouraged in cases where the command string is constructed from external input:>>> from subprocess import call >>> filename = input("What file would you like to display?\n") What file would you like to display? non_existent; rm -rf / # >>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...
shell=Falsedisables all shell based features, but does not suffer from this vulnerability; see the Note in thePopenconstructor documentation for helpful hints in gettingshell=Falseto work.When using
shell=True,pipes.quote()can be used to properly escape whitespace and shell metacharacters in strings that are going to be used to construct shell commands.
os.system() has all the same faults as subprocess.Popen(..., shell=True) -- even more faults, since subprocess.Popen() provides a way to pass data out-of-band from code, and so can be used safely.
Native Python libraries don't call shells for work that the Python runtime can do.
Python has a socket library in its standard library interface, which directly invokes operating system and libc calls to create network connections and interact with them. There is no shell involved in these syscalls; arguments are C structs, C strings, etc; so they aren't prone to shell injection vulnerabilities in the same way that os.system() is.
Some Python libraries, like libcurl, may be slightly less native insofar as they use their own C libraries rather than only calling out to the operating system through functions included in the Python runtime itself; even then, though, these OS-level syscalls are at a much lower level than any shell.
This answer is entirely correct.
But I'd also like to point out to other cases in which you might think that security doesn't matter. E.g. the command you are running is hard-coded or you have 100% control or trust over what is supplied to it.
Even it that case using os.system() is wrong.
In fact:
- You have to rely on external tools that might not be present or, even worse, you might have a command with that name, but it doesn't do what you expect it to do. Maybe because it has a different version or maybe because it's a different implementation of that command (e.g. GNUtar != BSDtar). Manging python dependencies will be much more easy and reliable.
- It is more difficult to handle errors. You only have a return code which is not always enough to understand what is going on. And I hope that your solution to this problem isn't to parse the command output.
- Environment variables can modify the way a program works unexpectedly. Many programs use environment variables as an alternative to command line or configuration options. If your python script relies on specific behavior from the command, an unexpected variable in the user's environment can break it.
- If at some point in the future you will need to let the user customize a bit your script behavior you will need to rewrite it from scratch without
os.system()or you might have security problems.
So I wanted to install Python, download Selenium library on it, and combine it with Webdriver to access web-driven accounting software to automate some stuff; mainly downloading reports from the accounting software since there are tones of reports to download every month, which the software does not have automation function for. I don't want to deal with any data.
Senior director and I went to IT for the request to download Python and they declined; they said there is a security risk.
Does anyone know what potential security risks they are referring to? I don't have cs background so I'm not very sure. And is there a way to mitigate those risks?