Before creating a report, please read through this document.
As documented at https://spring.io/security-policy, this repository is used to report security advisories to any Spring Project. In particular, read What is a Valid CVE? before filing a report to confirm your issue qualifies.
A valid CVE is a security vulnerability directly caused by Spring’s own code, where Spring itself allows untrusted input to be processed in an insecure way. Issues stemming from developer misuse, vulnerabilities in Spring’s dependencies, or transitive dependency versions do not qualify. The sections below provide concrete examples of both qualifying and non-qualifying issues.
Real accepted Spring security advisories are published at https://spring.io/security/. These serve as examples of valid CVEs; we link there rather than duplicate the content here.
The following controller is a CVE in the application, not in Spring.
@RestController
class HasCveCommandController {
/**
* CVE: passes the untrusted {@code command} HTTP parameter directly to
* {@link ProcessBuilder}, allowing an attacker to execute arbitrary commands
* on the server. This is a vulnerability in the application, not in Spring.
*/
@GetMapping("/cve")
String cve(@RequestParam String command) throws Exception {
Process process = new ProcessBuilder(command).start();
return new String(process.getInputStream().readAllBytes());
}
}Spring’s role is to route the HTTP request and bind parameters — it has no knowledge of, or responsibility for, what the developer does with those values.
The developer is responsible for validating or sanitizing untrusted input before passing it to any sensitive API such as ProcessBuilder, Runtime.exec, or similar.
If such a controller is exploited to execute arbitrary commands, the CVE belongs to the application, not to Spring MVC.
The Spring team’s stance is that, in order for deserialization to be considered a vulnerability in Spring, Spring must pass data from an untrusted source (that is, HTTP parameters) into a method that performs deserialization in a way that produces a CVE. The reason for this stance is that deserialization of arbitrary types is necessary but cannot be made secure.
Spring provides necessary tools for developers, but it is the responsibility of the developer to use them securely.
This is no different than any other library or the JDK itself.
If a developer passes untrusted data from an HTTP request to ProcessBuilder, then it is not a CVE in the JDK but in the application that used ProcessBuilder incorrectly.
If a developer uses untrusted data to create an SQL query by using String concatenation, it is not a CVE in the SQL driver but in the application for not using prepared SQL statements.
Similarly, if a developer passes untrusted data into a deserialization method, it is the developer that needs to ensure it is safe to do so.
Vulnerabilities in Spring’s dependencies should be reported to the respective project and not to the Spring team.
The Spring team does its best to keep its dependencies up to date regardless of whether a dependency contains a vulnerability. However, we do not consider it a vulnerability in Spring when Spring defines a vulnerable dependency version, because developers can override these versions and because releasing for any transitive dependency would become unmanageable for the Spring portfolio.
It is up to the developer of the dependency to release a compatible version with the security fix. If this is made available, the Spring project will be updated to that dependency version prior to releasing the next version of the Spring project.
Typically, there is not a special release for updating dependency versions. Instead, the Spring team encourages developers to override the version until the next Spring release.
Reports about issues in Spring project versions that have reached end of life are not considered valid CVEs. You can find the supported versions on spring.io. For example, Spring Boot’s supported versions can be found at https://spring.io/projects/spring-boot#support.
Collaboration should use a temporary private fork of this repository.
This section outlines how to collaborate on a security advisory and is divided into the following subsections. Each subsection describes the goal to achieve and provides example scripts as one way to accomplish it — you are free to use any approach that achieves the same result.
-
A Hypothetical CVE Report — introduces the hypothetical CVE used as a running example throughout this section
-
Clone Temporary Private Fork — clone the temporary private fork locally so subsequent steps can work against it
-
Sharing the Sample — push a minimal reproducer to an orphan branch on the private fork so the team can review it
-
Using the Sample — check out the reporter’s sample locally to run and reproduce the issue
-
Producing a Fix — commit a fix and share it on the private fork for team review
Throughout this documentation, we will use an example report related to a hypothetical CVE in Spring Framework related to path validation.
For the example report we will assume that the CVE is in https://github.com/spring-projects/spring-framework and the branch of 7.0.x.
The goal of this step is to clone the temporary private fork locally so subsequent steps can work against it.
The example script below clones the temporary private fork, but you are free to clone it any way you want.
# -o uses a uniquely named remote (instead of origin) to avoid accidentally pushing to the wrong repository.
git clone \
-o ghsa-path-validation \
git@github.com:spring-projects/security-advisories-ghsa-3rf2-292v-g6wr.git \
~/code/ghsa-path-validation
cd $_|
Note
|
If you want to update the instructions throughout this documentation, you can update the corresponding AsciiDoc document attribute ( |
Before you report a security advisory, you should already have a minimal reproducer (a sample).
As the reporter, the goal is to push your sample to an orphan branch named sample on the private temporary fork so the team can review it without publishing to the public repository or a public issue.
The following example scripts show one way to achieve that goal:
Review each block before you run it and align the defaults in A Hypothetical CVE Report with your environment.
The goal is to create an orphan branch named sample on the private temporary fork clone.
Clone Temporary Private Fork must be completed first so the clone of the private temporary fork exists. The example script below creates the branch and adds an empty initial commit so the ref exists for subsequent steps.
# Ensure in the clone directory
cd ~/code/ghsa-path-validation
# git switch requires Git 2.23+ (--orphan removes tracked files from the working tree).
git switch --orphan sample
# Empty commit so refs/heads/sample exists (otherwise checkout/switch sample fails later or in a new shell).
git commit --allow-empty -m "Start sample branch"The goal is to have the sample committed on branch sample.
The example script below copies the sample directory and commits it.
# Ensure in the clone directory
cd ~/code/ghsa-path-validation
# rsync copies the sample without bringing over `.git` (or any nested `.git` directories).
rsync -a --exclude=.git ~/code/sample-cve/ .
git add -A
git commit -m "Add sample"The goal is to have branch sample pushed to the advisory remote so reviewers can access it.
The example script below pushes the branch and prints the GitHub URL.
# Ensure in the clone directory
cd ~/code/ghsa-path-validation
git push -u ghsa-path-validation sampleYou can now view the sample at https://github.com/spring-projects/security-advisories-ghsa-3rf2-292v-g6wr/tree/sample.
As a team member, the goal is to have the reporter’s sample checked out locally so you can run and reproduce the issue. You need access to the private temporary fork (for example as a collaborator on the draft advisory).
The example script below is one way to achieve that: it switches to branch sample in the fork clone.
Clone Temporary Private Fork must be completed first so the clone exists.
# Ensure in the clone directory
cd ~/code/ghsa-path-validation
git switch sampleThe goal of this section is to produce a fix and share it on the private temporary fork for review.
The following example scripts show one way to achieve that goal:
Review each block before you run it and align the defaults in A Hypothetical CVE Report with your environment.
The goal is to have a local branch tracking the affected branch (e.g. 7.0.x) of the public repository (e.g. spring-projects/spring-framework) so you can apply a fix.
The example script below adds the public repository as a remote and creates a local branch from it.
# Ensure in the clone directory
cd ~/code/ghsa-path-validation
# HTTPS URL and a dedicated remote alias reduce the chance of pushing to the wrong GitHub repository.
git remote add spring-framework https://github.com/spring-projects/spring-framework.git
git fetch spring-framework
git switch -c 7.0.x spring-framework/7.0.xThe goal is to have a fix committed on the branch (e.g. 7.0.x).
Edit the codebase, run tests or the reporter’s reproducer to verify, then stage and commit — the example script below shows the commit step.
# Ensure in the clone directory
cd ~/code/ghsa-path-validation
# Edit sources as needed, then stage and commit.
git add -A
git commit -m "Fix CVE"The goal is to have the fix branch pushed to the advisory remote so the team can review it on the private fork. The example script below pushes the branch and prints the GitHub URL.
# Ensure in the clone directory
cd ~/code/ghsa-path-validation
git push -u ghsa-path-validation 7.0.xYou can now view the fix at https://github.com/spring-projects/security-advisories-ghsa-3rf2-292v-g6wr/tree/7.0.x.
After Pushing the Fix, notify the reporter and provide instructions for how to review the fix.
If possible, you should consider updating the sample branch to demonstrate the fix.
For example, you might update the sample branch to:
-
Align the version of the vulnerable dependency with the fix
-
If necessary, add a local Maven repository URL (e.g. Maven Local)
-
Provide the user with instructions for how to publish the fix locally (e.g. run
./mvn install) on the fix branch (e.g.7.0.x) of the private fork