Common Java Vulnerabilities
Java powers a significant share of enterprise software, Android applications, and backend services. Its mature ecosystem includes frameworks like Spring, Hibernate, and Apache Struts—each introducing their own attack surface.
The most prevalent Java vulnerability classes include:
- Insecure deserialization (CWE-502): Java's native serialization mechanism is inherently dangerous when processing untrusted data, enabling remote code execution.
- XML External Entity (XXE) injection (CWE-611): Java's default XML parser configurations are often vulnerable to entity expansion attacks.
- SQL injection via JDBC (CWE-89): Direct use of
Statementinstead ofPreparedStatementwith user input. - Path traversal (CWE-22): File operations using unsanitized user-supplied paths, common in servlet-based file upload handlers.
- Broken access control: Missing or misconfigured Spring Security annotations, allowing unauthorized endpoint access.
- Log injection (CWE-117): Unsanitized user input in log statements, relevant after the Log4Shell (CVE-2021-44228) incident.
Java's strong type system and garbage collection prevent certain vulnerability classes (buffer overflows, use-after-free), but its enterprise patterns introduce complexity that creates security gaps.
Deserialization Risks
Java's ObjectInputStream.readObject() is one of the most dangerous APIs in any programming language. When an application deserializes untrusted data, an attacker can craft a serialized object that triggers arbitrary code execution during the deserialization process.
How the Attack Works
Java serialization restores objects by calling class-specific methods like readObject(), readResolve(), and finalize(). Attackers chain classes available on the classpath (called "gadget chains") to reach code execution:
// VULNERABLE: Never deserialize untrusted data
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(userInput)
);
Object obj = ois.readObject(); // Arbitrary code execution
Libraries like Apache Commons Collections, Spring Framework, and Hibernate contain gadget classes that attackers chain together. The ysoserial tool automates gadget chain generation for dozens of common libraries.
The Impact
Deserialization vulnerabilities have caused critical breaches:
- Apache Struts (CVE-2017-9805) led to the Equifax breach
- WebLogic Server has had multiple deserialization RCEs (CVE-2020-14882)
- Jenkins, JBoss, and numerous Java middleware products have been affected
Defenses
- Never use
ObjectInputStreamwith untrusted input - Use safe serialization formats: JSON (Jackson, Gson), Protocol Buffers, or MessagePack
- If Java serialization is required, use
ObjectInputFilter(Java 9+) to allowlist expected classes - Remove unnecessary gadget libraries from the classpath
XXE in Java XML Parsers
XML External Entity (XXE) injection is a vulnerability where XML parsers process external entity references in XML input, allowing attackers to read local files, perform server-side request forgery (SSRF), or trigger denial of service.
Java is particularly susceptible because its standard XML parsers (DocumentBuilderFactory, SAXParserFactory, XMLInputFactory) have external entities enabled by default in many configurations:
// VULNERABLE: Default parser configuration
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(userProvidedXml);
An attacker submits XML containing:
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>&xxe;</data>
The parser reads /etc/passwd and includes its contents in the parsed document.
Secure Configuration
Disable external entities and DTDs explicitly:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
Alternatively, use JSON or YAML for data interchange where XML is not strictly required.
SQL Injection in JDBC
Java's JDBC API provides two ways to execute SQL: Statement and PreparedStatement. Using Statement with string concatenation is the classic Java SQL injection vector:
// VULNERABLE: String concatenation with Statement
String query = "SELECT * FROM users WHERE id = " + userId;
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
The fix is to use PreparedStatement with parameter placeholders:
// SECURE: Parameterized query
String query = "SELECT * FROM users WHERE id = ?";
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setInt(1, userId);
ResultSet rs = pstmt.executeQuery();
ORM Considerations
Hibernate and JPA prevent most SQL injection through JPQL/HQL parameterization, but risks remain:
- Native queries:
entityManager.createNativeQuery(userInput)bypasses ORM protections - HQL concatenation:
session.createQuery("FROM User WHERE name = '" + name + "'")is vulnerable despite using an ORM - Criteria API misuse: Using
Restrictions.sqlRestriction()with unsanitized input
Spring Data JPA's derived query methods and @Query annotations with named parameters are safe by default.
Spring Security Patterns
Spring Security is the de facto standard for securing Java web applications, but misconfiguration is common:
Common Misconfigurations
- Permissive URL patterns: Using
.antMatchers("/admin/**").permitAll()instead of.authenticated()exposes admin endpoints. - Missing method-level security: Relying solely on URL-based security without
@PreAuthorizeor@Securedannotations on controller methods. - CSRF disabled without justification:
http.csrf().disable()is appropriate for stateless REST APIs with token authentication but dangerous for session-based applications. - Weak password encoding: Using
NoOpPasswordEncoderor MD5/SHA-1 instead of BCrypt, SCrypt, or Argon2.
Secure Defaults
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http)
throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.csrf(csrf -> csrf.disable()); // OK for stateless JWT API
return http.build();
}
}
Use @EnableMethodSecurity to enable @PreAuthorize annotations for fine-grained access control at the method level, not just URL patterns.
How CodeSlick Covers Java (32 Checks)
CodeSlick's Java analyzer performs 32 security checks covering the vulnerability classes most prevalent in Java applications:
- Deserialization detection: Identifies
ObjectInputStream.readObject()calls, flagging any deserialization of potentially untrusted data with Critical severity. - XXE prevention: Checks XML parser factory configurations for missing
disallow-doctype-declandexternal-general-entitiesfeatures. - SQL injection: Detects
Statementusage with string concatenation, native queries with unsanitized input, and HQL concatenation patterns. - Path traversal: Identifies file operations using user-controlled paths without canonicalization or allowlist validation.
- Hardcoded credentials: Detects passwords, API keys, and connection strings embedded in Java source code.
- Insecure cryptography: Flags use of DES, MD5, SHA-1, and ECB mode in encryption operations.
- Command injection: Identifies
Runtime.exec()andProcessBuildercalls with user-controlled arguments. - LDAP injection: Detects unsanitized input in LDAP search filters.
All findings include CWE classification, CVSS severity scoring, and OWASP Top 10:2025 mapping. CodeSlick's AI-powered fix suggestions generate secure Java code patterns specific to the vulnerability context.
Run 32 Java-specific security checks on your code in under 3 seconds.