-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Hi Team,
Hope you're doing well!
Just adding this here as a question to check if anyone has any inputs or recommendations.
Description of issue
CWE-918 (SSRF) finding alert when input parameters are eventually appended to a URL used to make outbound calls to external systems in the source code.
However, the implementation includes multiple layers of mitigation, which I believe should prevent SSRF:
- The input string is validated via regex (alphanumeric + length check).
- A sanitization method strips any non-alphanumeric characters.-
- The base URL is sourced from a secure Spring Boot config (application.properties) using the @value annotation.
- I’ve implemented an allow-list validation, ensuring the final URI starts with one of the expected base URLs.
- Despite these controls, CodeQL still flags the usage as SSRF in the RestTemplate.exchange() call.
Please refer to the code snippet below for reference:
Code samples or links to source code
Controller(source)
@RequestMapping(path = "{inputKey:^[a-zA-Z0-9]{8}$|^[a-zA-Z0-9]{10}$}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses({ @ApiResponse(responseCode = "404", description = "Resource Not Found"),
@ApiResponse(responseCode = "200", description = "OK") })
public ResourceResponse getURLsByIdentifier(
@Parameter(description = "Enter inputKey.", name = "inputKey", required = true) @PathVariable("inputKey") String inputKey) {
### Source inputKey
return resourceService.getResourceUrls(sanitizeAlphanumeric(inputKey));
}
private String sanitizeAlphanumeric(String input) {
if (input == null) return "";
return input.replaceAll("[^a-zA-Z0-9]", "");
}
Service Layer (Sink)
//validated URL is being formed
URI configURI = UriComponentsBuilder.
fromUriString(baseUrl) //baseURl is pickup from Spring config using @Value annotation
.path(inputKey) // pased from controller
.queryParam("config", "true")
.build()
.toUri();
HttpEntity<String> entity = new HttpEntity<>(getHeaders());
### Sink configURI
ResponseEntity<Map<String, Object>> response = restTemplate.exchange(configURI, HttpMethod.GET, entity,
new ParameterizedTypeReference<>() {}); // Vunerbility reported here
//have implemented a URL validation mechanism by maintaining a map of all allowed base URLs and verifying
// whether the constructed configURI starts with one of the expected base URLs. However, this approach also did not help resolve the issue.
I’ve also verified that:
baseUrl is always from a known set of safe endpoints.
A custom check ensures the final URI starts with one of the allow-listed base URLs before making the request.
Appreciate any insights or suggestions. Happy to share more details if needed. Thanks in advance!