Preventing Python code from importing certain modules?

Viewed 22959

I'm writing an application where users can enter a python script and execute it in a sandbox. I need a way to prevent the exec'ed code from importing certain modules, so malicious code won't be as much of a problem. Is there a way to do this in Python?

6 Answers

You can register a custom MetaPathFinder as the first element of sys.meta_path. This finder can maintain a list of forbidden modules and only return None if the import is acceptable, in order to delegate to other finders; otherwise, it can raise an ImportError to indicate that the import is illegal.

from importlib.abc import MetaPathFinder
import sys


class ForbiddenModules(MetaPathFinder):
    def __init__(self, modules):
        super().__init__()
        self.modules = modules

    def find_spec(self, fullname, path, target=None):
        if fullname in self.modules:
            raise ImportError(fullname)


sys.meta_path.insert(0, ForbiddenModules({'typing'}))

import math  # works
import typing  # raises ImportError

However, at interpreter startup already a bunch of modules are automatically imported. You can check this by using the -v flag, e.g. python -vc "" (it's a long list, so I won't copy it here).

So you also need to remove those modules from sys.modules: sys.modules.clear().

Also note that the list of forbidden modules must include sys itself, because otherwise user code could simply remove the custom finder via sys.meta_path.pop(0) and then continue with importing forbidden modules. This implies that any module which depends on sys (i.e. imports sys) will be forbidden, too.

So this is the full code:

from importlib.abc import MetaPathFinder
import sys


class ForbiddenModules(MetaPathFinder):
    def __init__(self, modules):
        super().__init__()
        self.modules = modules

    def find_spec(self, fullname, path, target=None):
        if fullname in self.modules:
            raise ImportError(fullname)


sys.meta_path.insert(0, ForbiddenModules({'sys', ...}))
sys.modules.clear()
del MetaPathFinder, ForbiddenModules, sys
Related