This leaves a lot of room for abuse. Basically any static initializer and any constructor which has string parameters can be executed:
This is a common vulnerability of <something> (e. g. JSON) to Java parsers, that allow the untrusted data block to specify the classnames.
JDBC drivers are supposed to register themselves in the static initializer. Classes that use native methods are supposed to load the native library in the static init block. Furthermore there is a singleton anti-pattern of creating the instance in the static block. So it is possible to use up memory, that cannot be GCed. And of course someone might have written code that does other strange things in the static init block.
There are many classes which have side effects in their constructor. For example instantiating a FileOutputStream with a filename as parameter will empty that file, assuming that java process has write permission.
Those examples came to my mind while reading the posting. I am sure there are a lot more.
Furthere more you should consider whether showing the Stacktraces to the attacker is really necessary. It is often a good idea to hand out as little information as possible in unexpected situations. In your situation for example, it does makes a differences if a FileInputStream throws an IOException or a ClassCastException. This information might make it easier to exploit another vulnerability.
At the very minimum you must check TrustedInterface.class.isAssinableFrom(loadedClass)
before invoking the constructor or use loadedClass.asSubclass(TrustedInterface.class)
. But I strongly recommend to use a whitelist of classnames.
parameter: java.io.FileInputStream
This will throw an exception if the init-string does not exist on the filesystem, which will make it possible to determine the location of arbitrary files.