As of this moment, in the bcannon-objcap branch in svn, you can control what built-ins there are, values in the 'sys' module's data dict, and the module cache. While none of that gives you complete security for anything, it is a big milestone for me since it means stuff is actually moving forward and this is all a key part of my security model.
But now I have to figure out how to handle exceptions raised in a created interpreter (been calling them "slave interpreters" since they are controlled by a "master interpreter", but could also call them "sandboxed interpreters" since another interpreter can restrict what it can do at any time). Temorarily I just throw Exception saying that an exception occured in the other interpreter and I just personally read the traceback in the other interpreter that is printed out since I didn't override sys.excepthook to not print anything out. Obviously this won't fly since I can't toss out what exception was raised like that.
And so I began writing tests to see how malicious I could be with code. If you look in my branch in Lib/test/security you will find the (currently) two test files I have written. First I tried to get to open() even when it had been removed from the built-ins of the sub-interpreter in the __del__() method. I figured this would be a nice, sneaky way to get another interpreter to do something for me since no one thinks about __del__() since it is implicitly called.
Amazingly, I couldn't pull it off. It seems the garbage collector does a good job of preventing stuff from happening in a __del__() method. That's good.
But then I tried to come up with an evil __str__() method on an exception that could be raised. That blew up in my face. If an exception is raised that was defined with a __str__() method in a malicious manner in the sub-interpreter (both raising a class or instance) then it will be able to gain abilities it shouldn't have. That's bad.
So, what can I do? One option is to have an InterpreterException that has an attribute that has the string name of the exception that was raised along with the message (as long as that message string was calculated in the other interpreter!). I could try to let known safe exceptions through directly, but then you do end up with an odd dichotomy of some exceptions being directly raised, others not. And if you are not careful with what is considered safe and not you could still possibly pull off a trick. The last option is to have a method on the interpreter object that flags an exception occurred, let you check it out (safely!), and possibly even let you at the original exception if you know what you are doing.
Going to see what .NET does and think on all of this some more.