java.spring.security.injection.tainted-url-host.tainted-url-host
semgrep
Author
unknown
Download Count*
License
User data flows into the host portion of this manually-constructed URL. This could allow an attacker to send data to their own server, potentially exposing sensitive data such as cookies or authorization information sent with this request. They could also probe internal servers or other resources that the server runnig this code can access. (This is called server-side request forgery, or SSRF.) Do not allow arbitrary hosts. Instead, create an allowlist for approved hosts hardcode the correct host, or ensure that the user data can only affect the path or parameters.
Run Locally
Run in CI
Defintion
rules:
- id: tainted-url-host
languages:
- java
severity: ERROR
message: User data flows into the host portion of this manually-constructed URL.
This could allow an attacker to send data to their own server, potentially
exposing sensitive data such as cookies or authorization information sent
with this request. They could also probe internal servers or other
resources that the server runnig this code can access. (This is called
server-side request forgery, or SSRF.) Do not allow arbitrary hosts.
Instead, create an allowlist for approved hosts hardcode the correct host,
or ensure that the user data can only affect the path or parameters.
options:
interfile: true
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
category: security
technology:
- java
- spring
cwe2022-top25: true
cwe2021-top25: true
subcategory:
- vuln
impact: MEDIUM
likelihood: MEDIUM
confidence: MEDIUM
interfile: true
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
vulnerability_class:
- Server-Side Request Forgery (SSRF)
mode: taint
pattern-sources:
- patterns:
- pattern-either:
- pattern-inside: |
$METHODNAME(..., @$REQ(...) $TYPE $SOURCE,...) {
...
}
- pattern-inside: |
$METHODNAME(..., @$REQ $TYPE $SOURCE,...) {
...
}
- metavariable-regex:
metavariable: $TYPE
regex: ^(?!(Integer|Long|Float|Double|Char|Boolean|int|long|float|double|char|boolean))
- metavariable-regex:
metavariable: $REQ
regex: (RequestBody|PathVariable|RequestParam|RequestHeader|CookieValue|ModelAttribute)
- focus-metavariable: $SOURCE
pattern-sinks:
- pattern-either:
- pattern: new URL($ONEARG)
- patterns:
- pattern-either:
- pattern: |
"$URLSTR" + ...
- pattern: |
"$URLSTR".concat(...)
- patterns:
- pattern-inside: |
StringBuilder $SB = new StringBuilder("$URLSTR");
...
- pattern: $SB.append(...)
- patterns:
- pattern-inside: |
$VAR = "$URLSTR";
...
- pattern: $VAR += ...
- patterns:
- pattern: String.format("$URLSTR", ...)
- pattern-not: String.format("$URLSTR", "...", ...)
- patterns:
- pattern-inside: |
String $VAR = "$URLSTR";
...
- pattern: String.format($VAR, ...)
- metavariable-regex:
metavariable: $URLSTR
regex: http(s?)://%(v|s|q).*
Examples
tainted-url-host.java
package org.sasanlabs.service.vulnerability.ssrf;
import com.nimbusds.jose.util.StandardCharset;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.sasanlabs.internal.utility.LevelConstants;
import org.sasanlabs.internal.utility.annotations.AttackVector;
import org.sasanlabs.internal.utility.annotations.VulnerableAppRequestMapping;
import org.sasanlabs.internal.utility.annotations.VulnerableAppRestController;
import org.sasanlabs.service.vulnerability.bean.GenericVulnerabilityResponseBean;
import org.sasanlabs.vulnerability.types.VulnerabilityType;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.RequestParam;
@VulnerableAppRestController(descriptionLabel = "SSRF_VULNERABILITY", value = "SSRFVulnerability")
public class SSRFVulnerability {
private static final String IMAGE_URL = "imageurl";
private static final transient Logger LOGGER = LogManager.getLogger(SSRFVulnerability.class);
@AttackVector(
vulnerabilityExposed = VulnerabilityType.SIMPLE_SSRF,
description = "IMAGE_URL_PASSED_TO_REQUEST")
@VulnerableAppRequestMapping(value = LevelConstants.LEVEL_1, htmlTemplate = "LEVEL_1/SSRF")
public ResponseEntity<GenericVulnerabilityResponseBean<byte[]>> getVulnerablePayloadLevel1(
@RequestParam(IMAGE_URL) String urlImage) {
try {
// ruleid: tainted-url-host
URL u = new URL(urlImage);
URLConnection urlConnection = u.openConnection();
byte[] bytes;
try (InputStream in = urlConnection.getInputStream()) {
bytes = StreamUtils.copyToByteArray(urlConnection.getInputStream());
}
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(bytes, true), HttpStatus.OK);
} catch (Exception e) {
LOGGER.error(
"Following exception occurred while opening the connection to {}", urlImage, e);
}
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
("Failed to fetch image from URL " + urlImage)
.getBytes(StandardCharset.UTF_8),
false),
HttpStatus.BAD_REQUEST);
}
}
@RestController
@RequestMapping("/user03")
public class User03Controller {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/get")
public UserDTO get(@RequestParam("id") Integer id) {
// ok: tainted-url-host
String url = String.format("http://%s/user/get?id=%d", "demo-provider", id);
return restTemplate.getForObject(url, UserDTO.class);
}
@PostMapping("/add")
public Integer add(UserAddDTO addDTO) {
// 请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 请求体
String body = JSON.toJSONString(addDTO);
// 创建 HttpEntity 对象
HttpEntity<String> entity = new HttpEntity<>(body, headers);
// 执行请求
// ok: tainted-url-host
String url = String.format("http://%s/user/add", "demo-provider");
return restTemplate.postForObject(url, entity, Integer.class);
}
}
Short Link: https://sg.run/vkYn