CWE-470, Use of Externally-Controlled Input to Select Classes or Code, is better known as unsafe reflection. The application takes a string from a request, a file or a message, and uses it to decide which class to instantiate or which method to call. If the input is not tightly limited, the caller picks the code path instead of the developer.
It hits anything that has reflection or dynamic dispatch. MITRE lists Java, PHP and interpreted languages. Plugin loaders, command routers, "action" parameters and generic deserializers are the usual places it hides.
How it happens
A developer wants one endpoint to serve many handlers. Instead of writing a switch, they read a name from the request and load the class with that name.
// Vulnerable: the caller chooses any class on the classpath
String type = request.getParameter("handler");
Class<?> c = Class.forName(type);
Handler h = (Handler) c.getDeclaredConstructor().newInstance();
h.run(request);
Even if the cast later fails, the constructor of the chosen class has already run. Classes with side effects in constructors or static initializers become a toolbox for the attacker.
MITRE notes that this gets much worse if the attacker can also put files in a location on the classpath, or add entries to the classpath. Then reflection can load brand new malicious behavior into the product, not just reuse what is already there.
The same pattern appears in PHP when a request value is used to build a class name, a function name or an include path.
Two observed examples in the record. CVE-2018-1000613 describes a cryptography API that uses unsafe reflection when deserializing a private key. CVE-2004-2331 describes a database system where attackers bypass sandbox restrictions through the Reflection API.
What an attacker gains
MITRE lists three outcomes.
- Execution of code that is not directly reachable, or calling real code at the wrong time or place, which can alter execution logic and bypass authentication or access control checks.
- Denial of service, by invoking the wrong code with arguments that violate its API, so the product exits or hangs.
- Information disclosure, by triggering a runtime error whose message leaks sensitive data.
How to find it
Static analysis is the main tool named by MITRE. A data flow model can follow a request value into Class.forName, getMethod or an equivalent call and flag the path when no validation sits in between.
You can also grep. Search for every use of reflection APIs and ask one question at each hit: can any part of this string come from outside the process? Config files and message queues count as outside.
How to fix it
MITRE gives three steps, in order of strength.
- Refactor to avoid reflection where you can. A plain interface and a normal constructor call is almost always enough.
- Never let user controlled input select and load classes or code.
- If you must select by name, apply strict validation with an allowlist, or use indirect selection so the user only picks a label and your code maps it to a class.
// Fixed: indirect selection through a fixed map
private static final Map<String, Supplier<Handler>> HANDLERS = Map.of(
"report", ReportHandler::new,
"export", ExportHandler::new
);
Supplier<Handler> s = HANDLERS.get(request.getParameter("handler"));
if (s == null) {
response.sendError(400);
return;
}
s.get().run(request);
The user can only reach the two handlers you listed. Unknown values fail closed.
Also keep upload directories off the classpath, since the classpath link is what turns a bug into a takeover.
Try it yourself
Run a code scan and watch how a tainted string reaching a reflection call is reported.
Click through it at your own pace, or open it full screen.
Reflection bugs also live in libraries you did not write. Reachability analysis tells you whether your code actually calls the vulnerable function, which helps you sort a long advisory list. You can start with the free in-browser dependency scan at gold.safeguard.sh/scan. No login, the file stays on your machine, up to 100 dependencies.
Quick check
Is a cast after Class.forName enough to make this safe?
No. The constructor and static initializer of the chosen class run before your cast can fail. Validate the name before loading anything.
What is indirect selection?
The user supplies a short label such as "report". Your code looks the label up in a fixed table and uses the class stored there. The user never supplies a class name.