scala.lang.security.audit.dispatch-ssrf.dispatch-ssrf

Author
unknown
Download Count*
License
A parameter being passed directly into url
most likely lead to SSRF. This could allow an attacker to send data to their own server, potentially exposing sensitive data sent with this request. They could also probe internal servers or other resources that the server runnig this code can access. Do not allow arbitrary hosts. Instead, create an allowlist for approved hosts hardcode the correct host.
Run Locally
Run in CI
Defintion
rules:
- id: dispatch-ssrf
patterns:
- pattern: url($URL)
- pattern-inside: |
import dispatch._
...
- pattern-either:
- pattern-inside: |
def $FUNC(..., $URL: $T, ...) = $A {
...
}
- pattern-inside: |
def $FUNC(..., $URL: $T, ...) = {
...
}
message: A parameter being passed directly into `url` most likely lead to SSRF.
This could allow an attacker to send data to their own server, potentially
exposing sensitive data sent with this request. They could also probe
internal servers or other resources that the server runnig this code can
access. Do not allow arbitrary hosts. Instead, create an allowlist for
approved hosts hardcode the correct host.
metadata:
cwe:
- "CWE-918: Server-Side Request Forgery (SSRF)"
owasp:
- A10:2021 - Server-Side Request Forgery (SSRF)
references:
- https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html
- https://dispatchhttp.org/Dispatch.html
category: security
technology:
- scala
- dispatch
confidence: LOW
cwe2022-top25: true
cwe2021-top25: true
subcategory:
- audit
likelihood: LOW
impact: HIGH
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
languages:
- scala
severity: WARNING
Examples
dispatch-ssrf.scala
package controllers
import javax.inject._
import play.api._
import play.api.mvc._
import dispatch._
import Defaults._
object Smth {
def call1(request_url: String): Future[Unit] = {
// ruleid: dispatch-ssrf
val req = url(request_url)
val data = Http.default(req OK as.String)
data
}
def call2(): Future[Unit] = {
// ok: dispatch-ssrf
val req = url("https://www.google.com")
val data = Http.default(req OK as.String)
data
}
}
object FooBar {
def call1(request_url: String): Future[Unit] = {
// ruleid: dispatch-ssrf
val request = url(request_url).POST.setHeader("Content-Type", "application/json")
val res = Http(request OK as.String)
res
}
def call2(): Future[Unit] = {
// ok: dispatch-ssrf
val request = url("https://www.google.com").POST.setHeader("Content-Type", "application/json")
val res = Http(request OK as.String)
res
}
}
@Singleton
class HomeController @Inject()(
val controllerComponents: ControllerComponents,
implicit val ec: ExecutionContext
) extends BaseController {
def req1(request_url: String) = Action.async { implicit request: Request[AnyContent] =>
// ruleid: dispatch-ssrf
val request = url(request_url).POST.setHeader("Content-Type", "application/json")
val res = Http(request OK as.String)
Ok("ok")
}
def req2() = Action.async { implicit request: Request[AnyContent] =>
// ok: dispatch-ssrf
val request = url("https://www.google.com").POST.setHeader("Content-Type", "application/json")
val res = Http(request OK as.String)
Ok("ok")
}
}
Short Link: https://sg.run/gR6J