I think you could use some sort of capability model, maybe the build system would need to have some different apis to be able to specify what certain artifacts are allowed to do, but then you could do something similar to what Fil-C does, just extended with some sort of permission system.
How Fil-C Works
I also think that something similar to DynamoRIO’s Program Shepherding could be useful:
Applying DynamoRIO to the security field resulted in a technique called program shepherding.[7] The program shepherding instrumentation monitors the origin of each program instruction and the control flow between instructions in order to prevent a security exploit from taking control of the program.
Secure Execution via Program Shepherding
I think another aspect is that you would have to clearly decide which parts are sandboxed and which aren’t and where the border between those is and then have techniques that make sure that no part that is supposed to be sandboxed is able to sneak into the non-sandboxed part. I think different capability-based or tracing techniques like the shepherding could work for that. (Or you might be able to run everything sandboxed at a much higher performance tradeoff, or with enough optimizations maybe even not that high)
Because I am not super deep into the research in that area, I am sure that there are lots of other interesting techniques that could be explored that I have never heard of.
I think it is more a matter of how much work is required to use certain techniques and implement them. Long term I would expect that we can make theses things more secure, maybe even without having to annotate too much code pieces with what they are allowed to do.