CVE-2025-64131
Description
Jenkins SAML Plugin 4.583.vc68232f7018a_ and earlier does not implement a replay cache, allowing attackers able to obtain information about the SAML authentication flow between a user's web browser and Jenkins to replay those requests, authenticating to Jenkins as that user.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Jenkins SAML Plugin prior to 4.583.585.v22ccc1139f55 lacks a replay cache, enabling attackers to replay SAML authentication requests and impersonate users.
Vulnerability
Description
The Jenkins SAML Plugin versions 4.583.vc68232f7018a_ and earlier fail to implement a replay cache for SAML authentication responses [1][3]. This means that once a valid SAML assertion is used to authenticate a user, the plugin does not track whether that assertion has already been consumed. An attacker who can obtain a copy of the SAML authentication flow (e.g., by sniffing network traffic or accessing browser history) can resubmit the same assertion to the Jenkins server [1][2].
Exploitation
Prerequisites
To exploit this vulnerability, an attacker must first gain access to the SAML authentication data exchanged between a legitimate user's browser and the Jenkins instance. This could be achieved through man-in-the-middle attacks, compromised network segments, or by extracting cached browser data [1][2]. No additional authentication is required beyond possessing a valid SAML assertion; the attacker simply replays the captured request to the Jenkins SAML endpoint.
Impact
Successful replay of a SAML assertion allows the attacker to authenticate to Jenkins as the original user, inheriting all of that user's permissions and roles [1][3]. This can lead to unauthorized access to Jenkins jobs, configurations, credentials, and other sensitive resources, potentially enabling further compromise of the CI/CD pipeline.
Mitigation
The vulnerability is fixed in SAML Plugin version 4.583.585.v22ccc1139f55, which introduces a replay cache that rejects previously used SAML assertions [1][4]. Users should upgrade to this version or later immediately. No workarounds are documented; the only remediation is to apply the plugin update [2].
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.jenkins-ci.plugins:samlMaven | < 4.583.585.v22ccc1139f55 | 4.583.585.v22ccc1139f55 |
Affected products
2- Range: <=4.583.vc68232f7018a_
- Jenkins Project/Jenkins SAML Pluginv5Range: 0
Patches
16170b1013daf[SECURITY-3613]
5 files changed · +161 −1
src/main/java/org/jenkinsci/plugins/saml/JenkinsReplayCacheProvider.java+16 −0 added@@ -0,0 +1,16 @@ +package org.jenkinsci.plugins.saml; + +import hudson.ExtensionPoint; +import org.pac4j.saml.replay.ReplayCacheProvider; + +/** + * {@link ReplayCacheProvider} being an interface suggests that there can be different providers, so this abstraction + * will allow to switch to another provider implementation if needed. + */ +public interface JenkinsReplayCacheProvider extends ExtensionPoint { + + /** + * Returns the {@link ReplayCacheProvider} to be used by {@link JenkinsSAML2Client} + */ + ReplayCacheProvider getProvider(); +}
src/main/java/org/jenkinsci/plugins/saml/JenkinsSAML2Client.java+43 −0 added@@ -0,0 +1,43 @@ +package org.jenkinsci.plugins.saml; + +import hudson.ExtensionList; +import java.util.logging.Logger; +import org.pac4j.saml.client.SAML2Client; +import org.pac4j.saml.config.SAML2Configuration; +import org.pac4j.saml.replay.InMemoryReplayCacheProvider; +import org.pac4j.saml.replay.ReplayCacheProvider; + +/** + * This override of the base {@link SAML2Client} is needed to fix SECURITY-3613, by setting + * up a replay cache which is static to all client instances. + */ +public class JenkinsSAML2Client extends SAML2Client { + + private static final Logger LOGGER = Logger.getLogger(JenkinsSAML2Client.class.getName()); + + static final ReplayCacheProvider REPLAY_CACHE = getProvider(); + + public JenkinsSAML2Client(SAML2Configuration config) { + super(config); + } + + @Override + protected void initSAMLReplayCache(boolean forceReinit) { + replayCache = REPLAY_CACHE; + } + + private static ReplayCacheProvider getProvider() { + var providers = ExtensionList.lookup(JenkinsReplayCacheProvider.class); + if (providers.isEmpty()) { + // Default if no extension is registered + return new InMemoryReplayCacheProvider(); + } + if (providers.size() > 1) { + LOGGER.fine(() -> String.format( + "There is more than one JenkinsReplayCacheProvider extension registered. " + + "Picking [%s] as it's first one in the extensions list.", + providers.get(0).getClass().getName())); + } + return providers.get(0).getProvider(); + } +}
src/main/java/org/jenkinsci/plugins/saml/OpenSAMLWrapper.java+1 −1 modified@@ -168,7 +168,7 @@ protected SAML2Client createSAML2Client() { config.setServiceProviderMetadataResource(new SamlFileResource(SamlSecurityRealm.getSPMetadataFilePath())); // Apply all configured property executions to the configuration propertyExecutions.forEach(property -> property.customizeConfiguration(config)); - SAML2Client saml2Client = new SAML2Client(config); + SAML2Client saml2Client = new JenkinsSAML2Client(config); saml2Client.setCallbackUrl(samlPluginConfig.getConsumerServiceUrl()); saml2Client.setCallbackUrlResolver(new NoParameterCallbackUrlResolver()); saml2Client.setStateGenerator(new RefererStateGenerator());
src/test/java/org/jenkinsci/plugins/saml/JenkinsReplayCacheProviderDefaultTest.java+43 −0 added@@ -0,0 +1,43 @@ +package org.jenkinsci.plugins.saml; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; + +import org.junit.jupiter.api.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; +import org.pac4j.saml.config.SAML2Configuration; +import org.pac4j.saml.replay.InMemoryReplayCacheProvider; + +/** + * Test to verify that the default InMemoryReplayCacheProvider is used + * when no JenkinsReplayCacheProvider extension is registered. + * This test validates the default behavior in the SECURITY-3613 fix. + */ +@WithJenkins +class JenkinsReplayCacheProviderDefaultTest { + + @Test + void testDefaultReplayCacheProviderIsUsed(JenkinsRule jenkinsRule) { + SAML2Configuration config = new SAML2Configuration(); + JenkinsSAML2Client client = new JenkinsSAML2Client(config); + client.setCallbackUrl("http://localhost"); + setKeyStore(config); + client.init(); + assertThat( + "Default InMemoryReplayCacheProvider should be used when no extension is registered", + JenkinsSAML2Client.REPLAY_CACHE, + instanceOf(InMemoryReplayCacheProvider.class)); + } + + static void setKeyStore(SAML2Configuration config) { + BundleKeyStore keyStore = new BundleKeyStore(); + if (!keyStore.isValid()) { + keyStore.init(); + } + config.setKeystorePath(keyStore.getKeystorePath()); + config.setKeystorePassword(keyStore.getKsPassword()); + config.setPrivateKeyPassword(keyStore.getKsPkPassword()); + config.setKeyStoreAlias(keyStore.getKsPkAlias()); + } +}
src/test/java/org/jenkinsci/plugins/saml/JenkinsReplayCacheProviderTest.java+58 −0 added@@ -0,0 +1,58 @@ +package org.jenkinsci.plugins.saml; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.TestExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; +import org.pac4j.saml.config.SAML2Configuration; +import org.pac4j.saml.replay.InMemoryReplayCacheProvider; +import org.pac4j.saml.replay.ReplayCacheProvider; + +/** + * Test for the JenkinsReplayCacheProvider extension point functionality. + * This test validates SECURITY-3613 fix by ensuring custom replay cache providers + * are properly loaded and used by JenkinsSAML2Client. + */ +@WithJenkins +class JenkinsReplayCacheProviderTest { + + @Test + void testCustomReplayCacheProviderIsUsed(JenkinsRule jenkinsRule) { + SAML2Configuration config = new SAML2Configuration(); + JenkinsSAML2Client client = new JenkinsSAML2Client(config); + client.setCallbackUrl("http://localhost"); + BundleKeyStore keyStore = new BundleKeyStore(); + JenkinsReplayCacheProviderDefaultTest.setKeyStore(config); + client.init(); + assertThat( + "Custom replay cache provider should be used", + JenkinsSAML2Client.REPLAY_CACHE, + instanceOf(TestReplayCacheProvider.class)); + assertTrue( + TestReplayCacheProvider.wasProviderCalled, + "Test replay cache provider getProvider() method should have been called"); + } + + @TestExtension + public static class TestJenkinsReplayCacheProvider implements JenkinsReplayCacheProvider { + + @Override + public ReplayCacheProvider getProvider() { + return new TestReplayCacheProvider(); + } + } + + public static class TestReplayCacheProvider extends InMemoryReplayCacheProvider { + + static boolean wasProviderCalled = false; + + public TestReplayCacheProvider() { + super(); + wasProviderCalled = true; + } + } +}
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-j7r7-7qmf-xq87ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-64131ghsaADVISORY
- www.jenkins.io/security/advisory/2025-10-29/ghsavendor-advisoryWEB
- www.openwall.com/lists/oss-security/2025/10/29/2ghsaWEB
- github.com/jenkinsci/saml-plugin/commit/6170b1013daf52770de29a66aeb57893aae1d7d6ghsaWEB
News mentions
1- Jenkins Security Advisory 2025-10-29Jenkins Security Advisories · Oct 29, 2025