There are a few issues here...
1. Depending upon context, *any* change to state (network I/O, console I/O, file I/O, environment variables, etc.) is a security vulnerability you can drive a truck through. For example: Foo is a very-locked down package that only appends text to a file the caller owns. It's formally verified to only change the file specified, verified to only append in all possible situtations, verified to not have cross-file-system identity problems, not subject to file renaming race conditions, yada yada yada. Safe? No. "foo('evil_command' '~/.bash.rc')".
2. A useful definition of a "capability" depends upon context. A *dynamic* context. Say Foo is intended to be used for generating log files. There's no way for a third-party library to determine whether the target is actually such a thing. It requires manual tuning which fits the operational context. Perhaps the file must be named "/var/log/${x}.log". Or maybe its "${home}/local/log/${x}.log". Great. Of course, now you've got to verify the context-specific defintions. And verify the tool that does this verification. And the verify the configuration of the tool that does the verification... Safe now? No. Context is *dynamic*. "foo('var/log/evil-hack-attempts.log' '0.0.0.0/0 tried-to-crash-us')", and your other context, the automated blacklisting, locks out the Internet.
3. This gets very complex very quickly. IMHO, configuring Selinux, in a real production environment with real personell, is akin to rolling your own cryptography. Can people learn to do it? Of course. But the same argument applies to writing cryptographic functions. You. Will. Make. Huge. Mistakes.
To be clear, this does not mean that capabilities are useless. It's obviously critical that they exist. However, they ain't magic. You can't "solve security with capabilities." There is a point where throwing more of them at the problem makes things *worse*.