CVE-2019-10460
Description
Jenkins Bitbucket OAuth Plugin 0.9 and earlier stored credentials unencrypted in the global config.xml configuration file on the Jenkins master where they could be viewed by users with access to the master file system.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Jenkins Bitbucket OAuth Plugin 0.9 and earlier stored the OAuth client secret in plain text in the global config.xml, exposing it to users with filesystem access.
Vulnerability
Description
Jenkins Bitbucket OAuth Plugin versions 0.9 and earlier stored the OAuth client secret in plain text in the global config.xml configuration file on the Jenkins controller. This sensitive credential was persisted without any encryption, contrary to security best practices for handling secrets [1][3].
Exploitation
An attacker who gains access to the Jenkins controller file system (for example, through another vulnerability, misconfiguration, or direct system access) could read the cleartext client secret from the global configuration file. No special Jenkins permissions beyond file system access are required; users with only read access to the controller's file system could view the stored credential [1][2].
Impact
With the exposed OAuth client secret, an attacker could potentially impersonate the Bitbucket OAuth integration, leading to unauthorized access to resources that rely on OAuth authentication. This could compromise the integrity and confidentiality of systems integrated with Jenkins through Bitbucket OAuth [1].
Mitigation
Thesecurity advisory was published on October 23, 2019 [1]. The plugin version 0.10, available from the Jenkins update center, fixes the issue by encrypting the stored client secret using Jenkins' Secret class, as shown in the corresponding commit [4]. Users should update to version 0.10 or later [1][2].
AI Insight generated on May 22, 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:bitbucket-oauthMaven | < 0.10 | 0.10 |
Affected products
3<=0.9+ 1 more
- (no CPE)range: <=0.9
- (no CPE)range: 0.9 and earlier
Patches
1f55d222db910[SECURITY-1546] fix client secret is saved in plain text
2 files changed · +39 −13
src/main/java/org/jenkinsci/plugins/BitbucketSecurityRealm.java+38 −12 modified@@ -4,7 +4,6 @@ import java.util.logging.Level; import java.util.logging.Logger; -import jenkins.security.SecurityListener; import org.acegisecurity.Authentication; import org.acegisecurity.AuthenticationException; import org.acegisecurity.AuthenticationManager; @@ -40,21 +39,26 @@ import hudson.security.GroupDetails; import hudson.security.SecurityRealm; import hudson.security.UserMayOrMayNotExistException; +import hudson.util.Secret; import jenkins.model.Jenkins; +import jenkins.security.SecurityListener; public class BitbucketSecurityRealm extends SecurityRealm { private static final String REFERER_ATTRIBUTE = BitbucketSecurityRealm.class.getName() + ".referer"; private static final Logger LOGGER = Logger.getLogger(BitbucketSecurityRealm.class.getName()); private String clientID; + @Deprecated private String clientSecret; + private Secret secretClientSecret; @DataBoundConstructor - public BitbucketSecurityRealm(String clientID, String clientSecret) { + public BitbucketSecurityRealm(String clientID, String clientSecret, Secret secretClientSecret) { super(); this.clientID = Util.fixEmptyAndTrim(clientID); this.clientSecret = Util.fixEmptyAndTrim(clientSecret); + this.secretClientSecret = secretClientSecret; } public BitbucketSecurityRealm() { @@ -70,8 +74,7 @@ public String getClientID() { } /** - * @param clientID - * the clientID to set + * @param clientID the clientID to set */ public void setClientID(String clientID) { this.clientID = clientID; @@ -80,18 +83,37 @@ public void setClientID(String clientID) { /** * @return the clientSecret */ + @Deprecated public String getClientSecret() { return clientSecret; } /** - * @param clientSecret - * the clientSecret to set + * @param clientSecret the clientSecret to set */ + @Deprecated public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } + /** + * @return the secretClientSecret + */ + public Secret getSecretClientSecret() { + // for backward compatibility + if (StringUtils.isNotEmpty(clientSecret)) { + return Secret.fromString(clientSecret); + } + return secretClientSecret; + } + + /** + * @param secretClientSecret the secretClientSecret to set + */ + public void setSecretClientSecret(Secret secretClientSecret) { + this.secretClientSecret = secretClientSecret; + } + public HttpResponse doCommenceLogin(StaplerRequest request, @Header("Referer") final String referer) throws IOException { @@ -107,7 +129,7 @@ public HttpResponse doCommenceLogin(StaplerRequest request, @Header("Referer") f } String callback = rootUrl + "/securityRealm/finishLogin"; - BitbucketApiService bitbucketApiService = new BitbucketApiService(clientID, clientSecret, callback); + BitbucketApiService bitbucketApiService = new BitbucketApiService(clientID, getSecretClientSecret().getPlainText(), callback); return new HttpRedirect(bitbucketApiService.createAuthorizationCodeURL(null)); } @@ -120,11 +142,13 @@ public HttpResponse doFinishLogin(StaplerRequest request) throws IOException { return HttpResponses.redirectToContextRoot(); } - Token accessToken = new BitbucketApiService(clientID, clientSecret).getTokenByAuthorizationCode(code, null); + String rawClientSecret = getSecretClientSecret().getPlainText(); + + Token accessToken = new BitbucketApiService(clientID, rawClientSecret).getTokenByAuthorizationCode(code, null); if (!accessToken.isEmpty()) { - BitbucketAuthenticationToken auth = new BitbucketAuthenticationToken(accessToken, clientID, clientSecret); + BitbucketAuthenticationToken auth = new BitbucketAuthenticationToken(accessToken, clientID, rawClientSecret); SecurityContextHolder.getContext().setAuthentication(auth); User u = User.current(); @@ -177,7 +201,7 @@ public UserDetails loadUserByUsername(String username) { if (!(token instanceof BitbucketAuthenticationToken)) { throw new UserMayOrMayNotExistException("Unexpected authentication type: " + token); } - result = new BitbucketApiService(clientID, clientSecret).getUserByUsername(username); + result = new BitbucketApiService(clientID, getSecretClientSecret().getPlainText()).getUserByUsername(username); if (result == null) { throw new UsernameNotFoundException("User does not exist for login: " + username); } @@ -217,8 +241,8 @@ public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingC writer.setValue(realm.getClientID()); writer.endNode(); - writer.startNode("clientSecret"); - writer.setValue(realm.getClientSecret()); + writer.startNode("secretClientSecret"); + writer.setValue(realm.getSecretClientSecret().getEncryptedValue()); writer.endNode(); } @@ -268,6 +292,8 @@ private void setValue(BitbucketSecurityRealm realm, String node, String value) { realm.setClientID(value); } else if (node.equalsIgnoreCase("clientsecret")) { realm.setClientSecret(value); + } else if (node.equalsIgnoreCase("secretclientsecret")) { + realm.setSecretClientSecret(Secret.fromString(value)); } else { throw new ConversionException("invalid node value = " + node); }
src/main/resources/org/jenkinsci/plugins/BitbucketSecurityRealm/config.jelly+1 −1 modified@@ -5,7 +5,7 @@ <f:textbox /> </f:entry> - <f:entry title="Client Secret" field="clientSecret" help="/plugin/bitbucket-oauth/help/realm/client-secret-help.html"> + <f:entry title="Client Secret" field="secretClientSecret" help="/plugin/bitbucket-oauth/help/realm/client-secret-help.html"> <f:password /> </f:entry> </f:section>
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-84h6-jf8x-ff2jghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2019-10460ghsaADVISORY
- www.openwall.com/lists/oss-security/2019/10/23/2ghsamailing-listx_refsource_MLISTWEB
- github.com/jenkinsci/bitbucket-oauth-plugin/commit/f55d222db910220ca8cd8631fb746c98b9e12870ghsaWEB
- jenkins.io/security/advisory/2019-10-23/ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.