☕ Java Vulnerability Examples and Fixes
Use this page when: reviewing Java or Spring services, servlet-era code, XML-heavy integrations, or enterprise APIs that mix legacy libraries with modern platform expectations.
How to read these examples
- Vulnerable snippet shows the unsafe habit.
- Safer pattern shows the direction you want in production code.
- Why it matters ties the defect to attacker value and business impact.
- Review cue is phrased so it can become a pull-request comment or checklist item.
Example 1 — SQL injection with Statement
Vulnerable snippet
String email = request.getParameter("email");
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(
"SELECT id, role FROM users WHERE email = '" + email + "'"
);
Safer pattern
String email = request.getParameter("email");
PreparedStatement ps = conn.prepareStatement(
"SELECT id, role FROM users WHERE email = ?"
);
ps.setString(1, email);
ResultSet rs = ps.executeQuery();
Why it matters
- Plain string concatenation puts attacker-controlled content into the SQL grammar itself.
Business impact
- Sensitive data exposure, account takeover via auth queries, and broader blast radius if DB roles are too wide.
Review cue
- Default to
PreparedStatementor framework-level parameter binding; ban dynamic SQL for plain value insertion.
Example 2 — XXE in XML parser configuration
Vulnerable snippet
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(inputStream);
Safer pattern
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.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(inputStream);
Why it matters
- Default XML parsing can resolve external entities and expose files, services, or network paths you never intended to trust.
Business impact
- File disclosure, SSRF, parser-based denial of service, or internal network reachability.
Review cue
- Every XML parser must be hardened deliberately; never assume safe defaults in older libraries or frameworks.
Example 3 — Unsafe deserialization of untrusted data
Vulnerable snippet
byte[] bytes = Base64.getDecoder().decode(request.getParameter("state"));
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
Object state = ois.readObject();
Safer pattern
StateDto state = objectMapper.readValue(request.getParameter("state"), StateDto.class);
validateStateDto(state);
Why it matters
- Native Java deserialization has a long history of gadget-based exploitation and logic abuse when fed untrusted bytes.
Business impact
- Remote code execution, denial of service, and deep compromise of app servers or worker tiers.
Review cue
- Avoid native object deserialization for untrusted data; prefer constrained formats and explicit DTO validation.
Example 4 — Path traversal in report download
Vulnerable snippet
String name = request.getParameter("name");
Path path = Paths.get("/srv/reports", name);
return Files.readString(path);
Safer pattern
String name = request.getParameter("name");
Path base = Paths.get("/srv/reports").toRealPath();
Path path = base.resolve(name).normalize();
if (!path.startsWith(base)) {
throw new AccessDeniedException("invalid path");
}
return Files.readString(path);
Why it matters
- User-supplied file names can escape the intended directory unless the final normalized path is checked.
Business impact
- Disclosure of secrets, app config, source code, and operational documents.
Review cue
- Resolve, normalize, and verify
startsWith(base)before touching the file system.
Example 5 — Broken access control in controller or service layer
Vulnerable snippet
@GetMapping("/orders/{id}")
public Order getOrder(@PathVariable Long id) {
return orderRepository.findById(id).orElseThrow();
}
Safer pattern
@GetMapping("/orders/{id}")
public Order getOrder(@AuthenticationPrincipal AppUser user,
@PathVariable Long id) {
return orderRepository.findByIdAndOwnerUserId(id, user.getId())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
Why it matters
- Looking up records by ID alone turns every predictable identifier into a possible cross-user access path.
Business impact
- Cross-account data exposure, unauthorized order actions, and high-severity incident response burden.
Review cue
- The repository or service call should encode ownership or tenant scope, not just the controller path.
Related pages
- Spring / ASP.NET / Go Security Review Guide
- API Authentication and Authorization
- SSRF, File Fetch, and Parser Abuse Review Guide
Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.