scala.lang.security.audit.io-source-ssrf.io-source-ssrf

Author
unknown
Download Count*
License
A parameter being passed directly into fromURL
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: io-source-ssrf
patterns:
- pattern-either:
- pattern: Source.fromURL($URL,...)
- pattern: Source.fromURI($URL,...)
- pattern-inside: |
import scala.io.$SOURCE
...
- pattern-either:
- pattern-inside: |
def $FUNC(..., $URL: $T, ...) = $A {
...
}
- pattern-inside: |
def $FUNC(..., $URL: $T, ...) = {
...
}
message: A parameter being passed directly into `fromURL` 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://www.scala-lang.org/api/current/scala/io/Source$.html#fromURL(url:java.net.URL)(implicitcodec:scala.io.Codec):scala.io.BufferedSource
category: security
technology:
- scala
confidence: MEDIUM
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
io-source-ssrf.scala
package controllers
import javax.inject._
import play.api._
import play.api.mvc._
import scala.io.{Codec, Source}
object Smth {
def call1(request_url: String) = {
// ruleid: io-source-ssrf
val html = Source.fromURI(request_url)
val data = html.mkString
data
}
def call2() = {
// ok: io-source-ssrf
val html = Source.fromURI("https://www.google.com")
val data = html.mkString
data
}
}
object FooBar {
def call1(request_url: String, codec: Codec) = {
// ruleid: io-source-ssrf
val res = Source.fromURL(request_url)(codec).mkString
res
}
def call2() = {
// ok: io-source-ssrf
val res = Source.fromURL("https://www.google.com")(codec).mkString
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] =>
val codec = whatIsCodec()
// ruleid: io-source-ssrf
val res = Source.fromURL(request_url, codec).mkString
Ok(res)
}
def req2() = Action.async { implicit request: Request[AnyContent] =>
// ok: io-source-ssrf
val res = Source.fromURL("https://www.google.com").mkString
Ok(res)
}
}
Short Link: https://sg.run/Qbz4