DEV Community

natarajan c k
natarajan c k

Posted on

Crashing with Clues: How Improper Error Handling Leaks Secrets

CTF + Real-World Vulnerability = Hands-On Learning

In one of my early Capture The Flag (CTF) challenges, I encountered a vulnerability that many developers unknowingly leave behind โ€” improper error handling.

In this blog, I'll walk you through:

  • ๐Ÿ” What improper error handling is
  • ๐Ÿงจ How I triggered it in a Java web application
  • ๐Ÿ’ฃ How it exposed internal logic
  • ๐Ÿ› ๏ธ And how I patched it securely like a professional

๐Ÿšจ What Is Improper Error Handling?

Improper error handling occurs when backend exceptions are shown directly to the user. These errors can reveal:

  • Class names and file paths
  • Programming languages and frameworks
  • Sensitive logic and stack flow
  • Even system vulnerabilities

This information might seem harmless โ€” but itโ€™s a goldmine for attackers.


๐Ÿงช The CTF Challenge Setup

I was given a Java web application built with:

  • Spring MVC
  • Apache Tomcat
  • A simple math evaluator backend

The goal was to test how the app responds to invalid input and identify any information disclosure through error messages.


๐Ÿ” Triggering the Vulnerability

I submitted a malformed input like this:
[http://localhost:8080/calculate?calculate=+]

And the application responded with this full stack trace:

HTTP Status 500 โ€“ Internal Server Error

Exception: java.util.EmptyStackException
at com.service.LoginService.evaluateExpression(LoginService.java:107)
at com.controller.LoginController.login(LoginController.java:23)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:986)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ก What Did I Learn From This?

  • Internal class structure (LoginService, LoginController)
  • Backend logic using Javaโ€™s Stack class
  • Exact file names and line numbers
  • Technology stack: Spring MVC, Java 11+, Apache Tomcat

๐Ÿ’ฅ Why This Is Dangerous

These details help an attacker:

  • Understand your application logic
  • Identify vulnerable entry points
  • Craft targeted payloads or exploits
  • Reverse-engineer backend behavior

This is a textbook example of an Improper Error Handling vulnerability โ€” and it gave away too much information.


๐Ÿ› ๏ธ Fixing the Vulnerability

๐Ÿ”ง The vulnerable code (LoginController.java)

@RequestMapping(method = RequestMethod.GET, value = "/calculate")
ResponseEntity<String> login(HttpServletRequest request, HttpServletResponse response) {
    String expression = request.getParameter("calculate");
    double result = loginService.evaluateExcreption(expression);
    return ResponseEntity.status(200).body(result + "");
}
Enter fullscreen mode Exit fullscreen mode

โœ… The fixed version with proper error handling:

@RequestMapping(method = RequestMethod.GET, value = "/calculate")
ResponseEntity<String> login(HttpServletRequest request, HttpServletResponse response) {
    String expression = request.getParameter("calculate");
    try {
        double result = loginService.evaluateExcreption(expression);
        return ResponseEntity.ok(result + "");
    } catch (Exception ex) {
        return ResponseEntity.badRequest().body("Invalid expression provided");
    }
}
Enter fullscreen mode Exit fullscreen mode

This ensures that:

  • The stack trace is hidden from the user
  • A friendly error message is shown
  • Internal logic is kept private

๐Ÿง  Backend Fix: Defensive Programming in LoginService

Hereโ€™s the vulnerable part of the expression evaluator:

else if (tokens[i] == ')') {
    while (ops.peek() != '(') {
        values.push(applyOp(ops.pop(), values.pop(), values.pop()));
    }
    ops.pop();
}
Enter fullscreen mode Exit fullscreen mode

If ops is empty, calling ops.peek() throws EmptyStackException.

โœ… Fixed version:

else if (tokens[i] == ')') {
    while (!ops.isEmpty() && ops.peek() != '(') {
        if (values.size() < 2)
            throw new IllegalArgumentException("Malformed expression");
        values.push(applyOp(ops.pop(), values.pop(), values.pop()));
    }
    if (!ops.isEmpty()) ops.pop();
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ” Final Thoughts

Improper error handling is one of the simplest but most dangerous bugs. Itโ€™s easy to overlook, but as this challenge showed me, even a small oversight can expose a big part of your system.

Whether you're building or breaking apps โ€” remember: handle errors properly.

Top comments (0)