Skip to main content
Offensive360

Most Common Java Vulnerabilities and How to Fix Them

Java applications are frequently targeted due to their enterprise prevalence. This guide covers the 13 most common Java vulnerability patterns with detection and remediation examples.

Offensive360 Security Research Team | | Vulnerability Research
JavaSpringOWASPSQL injectionXXEdeserializationSSRF

According to IBM’s Cost of a Data Breach Report, the average cost of a breach is $4.45 million (2023), with an average detection time of 204 days. Java applications are a primary target given their enterprise prevalence in banking, healthcare, and government systems.

This guide covers the most frequently exploited Java vulnerability patterns — with examples and fixes for each.

1. SQL Injection

SQL injection remains the most damaging web application vulnerability, allowing attackers to read, modify, or delete database contents.

// VULNERABLE: String concatenation
String sql = "SELECT * FROM users WHERE username = '" + username + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);

// SECURE: Parameterized query
String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();

Never use string concatenation to build SQL queries. Use PreparedStatement for JDBC, or the ORM’s built-in parameterization for Hibernate/JPA.

2. XML External Entity (XXE) Injection

Java’s XML parsers enable XXE by default. An attacker supplying crafted XML can read arbitrary files from the server.

// VULNERABLE: Default DocumentBuilderFactory
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(inputStream);

// SECURE: Disable external entities
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
DocumentBuilder builder = factory.newDocumentBuilder();

Apply these settings for all XML parsers: DocumentBuilderFactory, SAXParserFactory, XMLInputFactory, and any JAXB or JAXP parser.

3. Insecure Deserialization

Java deserialization can execute arbitrary code if a malicious serialized object is processed. This affects any endpoint accepting ObjectInputStream.

// VULNERABLE: Deserializes any class on the classpath
ObjectInputStream ois = new ObjectInputStream(inputStream);
Object obj = ois.readObject(); // Code execution possible

// SAFER: Use a filter to allowlist acceptable classes
ObjectInputStream ois = new ObjectInputStream(inputStream) {
    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
        if (!allowedClasses.contains(desc.getName())) {
            throw new InvalidClassException("Unauthorized: " + desc.getName());
        }
        return super.resolveClass(desc);
    }
};

Better yet, avoid Java serialization entirely for untrusted data. Use JSON with Jackson or Gson, which don’t execute arbitrary code during parsing.

4. Expression Language (EL) Injection

JSP Expression Language processors can execute arbitrary code if user input reaches them unescaped.

// VULNERABLE: User input in EL expression
String expr = "${" + userInput + "}";
ExpressionFactory ef = JspFactory.getDefaultFactory().getJspApplicationContext(servletContext).getExpressionFactory();
ValueExpression ve = ef.createValueExpression(elContext, expr, Object.class);
Object result = ve.getValue(elContext); // Code execution if userInput is malicious

Never construct EL expressions from user input. Validate and allowlist all dynamic values before including them in expressions.

5. Server-Side Request Forgery (SSRF)

SSRF allows attackers to make the server issue requests to internal services.

// VULNERABLE: Fetches any URL the user provides
String url = request.getParameter("imageUrl");
URL imageUrl = new URL(url);
InputStream stream = imageUrl.openStream(); // Can access internal IPs like 169.254.169.254

// SECURE: Validate the destination host
URL parsedUrl = new URL(url);
String host = parsedUrl.getHost();
if (!ALLOWED_DOMAINS.contains(host)) {
    throw new SecurityException("URL not allowed: " + host);
}
// Also resolve the IP and check against SSRF blocklist
InetAddress ip = InetAddress.getByName(host);
if (isPrivateIp(ip)) {
    throw new SecurityException("Access to private IP blocked");
}

6. Remote Code Execution via System Commands

// VULNERABLE: Command injection
Runtime.getRuntime().exec("ping " + userInput); // ping ; rm -rf /

// SECURE: Use array form, never shell interpolation
String[] cmd = { "ping", "-c", "1", hostName }; // hostName validated separately
Runtime.getRuntime().exec(cmd);

7. Log Injection

Attackers inject newline characters to forge log entries, potentially hiding attacks or injecting fake records.

// VULNERABLE
logger.info("User logged in: " + username);
// Malicious username: "admin\nWARN: Bank transfer complete: $10000"

// SECURE: Strip or encode control characters
String safeUsername = username.replaceAll("[\r\n\t]", "_");
logger.info("User logged in: {}", safeUsername);

Use parameterized logging (SLF4J {} syntax) and add a log sanitization step for all user-controlled values.

8. LDAP Injection

// VULNERABLE
String filter = "(uid=" + username + ")";

// SECURE: Encode LDAP special characters
String safeUsername = LdapEncoder.filterEncode(username);
String filter = "(uid=" + safeUsername + ")";

9. Header Injection

HTTP headers constructed from user input can enable XSS, open redirects, and session fixation.

// VULNERABLE: Newline in header value enables header injection
response.setHeader("Location", userSuppliedUrl);

// SECURE: Validate URL format and strip control characters
if (!userSuppliedUrl.matches("https?://[\\w./-]+")) {
    throw new SecurityException("Invalid redirect URL");
}
response.setHeader("Location", userSuppliedUrl);

10. Path Traversal

// VULNERABLE: User controls the filename
String filename = request.getParameter("file");
File file = new File("/var/app/uploads/" + filename);
// filename = "../../etc/passwd" → reads /etc/passwd

// SECURE: Resolve canonical path and verify it's within the base directory
File baseDir = new File("/var/app/uploads/").getCanonicalFile();
File requestedFile = new File(baseDir, filename).getCanonicalFile();
if (!requestedFile.toPath().startsWith(baseDir.toPath())) {
    throw new SecurityException("Path traversal detected");
}

11. Template Injection

Server-side template engines (Freemarker, Velocity, Thymeleaf) can execute code if user input reaches template expressions.

// VULNERABLE: User input inside Freemarker template
Template t = cfg.getTemplate("user_${userId}.ftl"); // userId = "1} ${7*7}"

// SECURE: Never include user input in template names or expressions directly
// Validate userId is numeric
if (!userId.matches("\\d+")) {
    throw new IllegalArgumentException("Invalid userId");
}

12. Second-Order SQL Injection

Data that appears safe when stored can be used unsafely in a later query.

// Data is stored safely...
String insertSql = "INSERT INTO users (username) VALUES (?)";
// ...but later used unsafely
String lookupSql = "SELECT * FROM audit WHERE username = '" + storedUsername + "'";

Apply parameterization everywhere SQL is constructed — not just at the entry point. Data that has been “safely stored” can still be malicious when used in a different query context.

13. Connection String Injection

Some databases allow multiple parameters separated by semicolons. An attacker can inject additional parameters.

// Attacker input: user=admin;database=master
String connStr = "Server=db;Database=app;User=" + userInput;

Always use parameterized connection strings and validate individual components before constructing URLs.

Using SAST to Find These Automatically

Offensive360’s Java scanner performs data-flow analysis to trace user input from HTTP parameters, headers, and form data through to dangerous sinks (SQL queries, XML parsers, shell commands, template engines). Each finding includes the full taint trace showing exactly how data flows from source to sink.

Written by Offensive360 Security Research Team

Find vulnerabilities before attackers do

Run Offensive360 SAST and DAST against your applications to catch security issues early.