Is there a better way?
You can make two different environments.
The original environment contains the original "require" function.
The untrusted environment is a proxy for the original environment, but it replaces the original "require" with your own function.
You start a script in the untrusted environment, so when the script invokes "require", all your restrictions are being held.
When the original "require" is eventually invoked, it always loads a module in the original environment, so all nested invocations of "require" will be unrestricted.
P.S. Can "io.open() + file:read() + load()" be a workaround? ;-)