Fix SSRF (Server Side Request Forgery) in Javalin
Server-Side Request Forgery (SSRF) in Javalin applications occurs when an endpoint accepts a user-provided URL and processes it server-side without strict validation. This allows an attacker to coerce the server into making requests to internal resources, metadata services (169.254.169.254), or loopback addresses, effectively bypassing network perimeters.
The Vulnerable Pattern
app.get("/proxy") { ctx ->
val targetUrl = ctx.queryParam("url") ?: return@get ctx.status(400)
val client = HttpClient.newHttpClient()
val request = HttpRequest.newBuilder()
.uri(URI.create(targetUrl))
.build()
val response = client.send(request, HttpResponse.BodyHandlers.ofString())
ctx.result(response.body())
}
The Secure Implementation
The fix employs a multi-layered defense: First, it enforces the HTTPS protocol to prevent protocol smuggling (gopher, file, etc.). Second, it implements a strict domain allowlist. Third, and most critically, it resolves the domain to an IP address and verifies it is not a loopback (127.0.0.1) or private/site-local IP (RFC 1918), which mitigates bypasses where a malicious domain points to an internal resource. Using a short timeout also prevents 'Slowloris' style resource exhaustion during the request.
val ALLOWED_DOMAINS = setOf("api.trusted-partner.com", "cdn.internal.com")app.get(“/proxy”) { ctx -> val urlString = ctx.queryParam(“url”) ?: throw BadRequestResponse() val uri = try { URI(urlString) } catch (e: Exception) { throw BadRequestResponse(“Invalid URI”) }
// 1. Protocol Enforcement if (uri.scheme != "https") throw ForbiddenResponse("Insecure protocol") // 2. Strict Allowlist if (uri.host !in ALLOWED_DOMAINS) throw ForbiddenResponse("Untrusted target") // 3. DNS Resolution & IP Validation (Prevent DNS Rebinding/Internal Access) val address = InetAddress.getByName(uri.host) if (address.isLoopbackAddress || address.isSiteLocalAddress || address.isAnyLocalAddress) { throw ForbiddenResponse("Internal network access denied") } val client = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(2)) .build() val request = HttpRequest.newBuilder().uri(uri).build() val response = client.send(request, HttpResponse.BodyHandlers.ofString()) ctx.result(response.body())
}
Your Javalin API
might be exposed to SSRF (Server Side Request Forgery)
74% of Javalin apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
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.