Avoiding shell injection when calling Git in Python
Your defense strategy is known as "enumerating badness".  As a rule, any strategy based on enumerating badness is doomed to fail.  For example, you prohibit rm -rf /, but have you considered find / -delete, which basically does the same thing?  How about some use of the dd if=/dev/zero?  What if a user legitimately wants to perform an operation on a file named normal.py or even rm.c?  Why are you silently altering the command to do something else?

If you ever need to execute an external program with user-supplied parameters, sensible practices would be to use subprocess.run() or subprocess.Popen()


with the command line as a list already split into words,
with the shell=False parameter (the best way to avoid shell injection is to avoid using the shell at all!),
with the command given using an absolute path (which is essential with shell=False),
with -- preceding the user-supplied filenames, so that filenames that start with - are treated literally.


Do not attempt to prohibit any "bad" words; you want your code to work for any legitimate filenames.  Do check that the filenames are legitimate, though — for example, not containing too many ../../../...

Better yet, use a Python module that takes care of interacting with Git so that you don't have to deal with the problem yourself.