GuardAPI Logo
GuardAPI

Fix SQL Injection (Legacy & Modern) in Javalin

SQLi in Javalin is a classic 'dev-shot-self-in-foot' scenario. Because Javalin is unopinionated and lightweight, developers often revert to raw JDBC string splicing to 'save time.' If you aren't parameterizing your queries, you're handing the keys to your database to any script kiddie with a single quote. Whether you're using legacy JDBC or modern fluent APIs, the rule remains: Never trust user-supplied input from ctx.pathParam() or ctx.queryParam().

The Vulnerable Pattern

app.get("/users/{id}", ctx -> {
    String id = ctx.pathParam("id");
    Connection conn = dataSource.getConnection();
    Statement stmt = conn.createStatement();
    // CRITICAL: String concatenation creates an injectable sink
    String sql = "SELECT * FROM accounts WHERE id = '" + id + "'";
    ResultSet rs = stmt.executeQuery(sql);
    // Payload example: /users/1' OR '1'='1
});

The Secure Implementation

The vulnerability exists because the SQL engine cannot distinguish between the developer's intended query logic and the malicious data injected via string concatenation. By using 'PreparedStatements' or modern wrappers like JDBI/JOOQ, the query structure is pre-compiled on the database server. User input is then sent as a separate parameter block. The database engine treats the input as a literal value (a string, integer, etc.) rather than executable SQL commands, effectively neutralizing payloads like ' OR 1=1 --. In the modern stack, JDBI's named parameters (e.g., :id) are the gold standard for preventing injection while maintaining readable code.

// Legacy approach: PreparedStatements
app.get("/users/{id}", ctx -> {
    String id = ctx.pathParam("id");
    try (Connection conn = dataSource.getConnection();
         PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM accounts WHERE id = ?")) {
        pstmt.setString(1, id); // Input is treated strictly as data, not code
        ResultSet rs = pstmt.executeQuery();
        // ... process results
    }
});

// Modern approach: JDBI (Fluent API) app.get(“/v2/users/{id}”, ctx -> { String id = ctx.pathParam(“id”); User user = jdbi.withHandle(handle -> handle.createQuery(“SELECT * FROM accounts WHERE id = :id”) .bind(“id”, id) // Named parameter binding .mapToBean(User.class) .first() ); ctx.json(user); });

System Alert • ID: 7422
Target: Javalin API
Potential Vulnerability

Your Javalin API might be exposed to SQL Injection (Legacy & Modern)

74% of Javalin apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.

RUN FREE SECURITY DIAGNOSTIC
GuardLabs Engine: ONLINE

Free Tier • No Credit Card • Instant Report

Verified by Ghost Labs Security Team

This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.