VYPR
Critical severity9.8NVD Advisory· Published Jul 17, 2017· Updated May 13, 2026

CVE-2017-1000362

CVE-2017-1000362

Description

The re-key admin monitor was introduced in Jenkins 1.498 and re-encrypted all secrets in JENKINS_HOME with a new key. It also created a backup directory with all old secrets, and the key used to encrypt them. These backups were world-readable and not removed afterwards. Jenkins now deletes the backup directory, if present. Upgrading from before 1.498 will no longer create a backup directory. Administrators relying on file access permissions in their manually created backups are advised to check them for the directory $JENKINS_HOME/jenkins.security.RekeySecretAdminMonitor/backups, and delete it if present.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.jenkins-ci.main:jenkins-coreMaven
>= 1.498, < 2.32.22.32.2
org.jenkins-ci.main:jenkins-coreMaven
>= 2.40, < 2.442.44

Patches

2
0be33cf7328f

Merge pull request #94 from jenkinsci-cert/SECURITY-376

https://github.com/jenkinsci/jenkinsJesse GlickJan 12, 2017via ghsa
3 files changed · +20 27
  • core/src/main/java/hudson/util/SecretRewriter.java+15 23 modified
    @@ -2,7 +2,6 @@
     
     import com.trilead.ssh2.crypto.Base64;
     import hudson.model.TaskListener;
    -import org.apache.commons.io.FileUtils;
     
     import javax.crypto.Cipher;
     import javax.crypto.SecretKey;
    @@ -33,21 +32,21 @@ public class SecretRewriter {
          */
         private int count;
     
    -    /**
    -     * If non-null the original file before rewrite gets in here.
    -     */
    -    private final File backupDirectory;
    -
         /**
          * Canonical paths of the directories we are recursing to protect
          * against symlink induced cycles.
          */
         private Set<String> callstack = new HashSet<String>();
     
    -    public SecretRewriter(File backupDirectory) throws GeneralSecurityException {
    +    public SecretRewriter() throws GeneralSecurityException {
             cipher = Secret.getCipher("AES");
             key = Secret.getLegacyKey();
    -        this.backupDirectory = backupDirectory;
    +    }
    +
    +    /** @deprecated SECURITY-376: {@code backupDirectory} is ignored */
    +    @Deprecated
    +    public SecretRewriter(File backupDirectory) throws GeneralSecurityException {
    +        this();
         }
     
         private String tryRewrite(String s) throws IOException, InvalidKeyException {
    @@ -70,12 +69,14 @@ private String tryRewrite(String s) throws IOException, InvalidKeyException {
                 return s;
         }
     
    -    /**
    -     * @param backup
    -     *      if non-null, the original file will be copied here before rewriting.
    -     *      if the rewrite doesn't happen, no copying.
    -     */
    +    /** @deprecated SECURITY-376: {@code backup} is ignored */
    +    @Deprecated
         public boolean rewrite(File f, File backup) throws InvalidKeyException, IOException {
    +        return rewrite(f);
    +    }
    +
    +    public boolean rewrite(File f) throws InvalidKeyException, IOException {
    +
             AtomicFileWriter w = new AtomicFileWriter(f, "UTF-8");
             try {
                 PrintWriter out = new PrintWriter(new BufferedWriter(w));
    @@ -117,10 +118,6 @@ public boolean rewrite(File f, File backup) throws InvalidKeyException, IOExcept
                 }
     
                 if (modified) {
    -                if (backup!=null) {
    -                    backup.getParentFile().mkdirs();
    -                    FileUtils.copyFile(f,backup);
    -                }
                     w.commit();
                 }
                 return modified;
    @@ -165,11 +162,7 @@ private int rewriteRecursive(File dir, String relative, TaskListener listener) t
                         if ((count++)%100==0)
                             listener.getLogger().println("Scanning "+child);
                         try {
    -                        File backup = null;
    -                        if (backupDirectory!=null)  backup = new File(backupDirectory,relative+'/'+ cn);
    -                        if (rewrite(child,backup)) {
    -                            if (backup!=null)
    -                                listener.getLogger().println("Copied "+child+" to "+backup+" as a backup");
    +                        if (rewrite(child)) {
                                 listener.getLogger().println("Rewritten "+child);
                                 rewritten++;
                             }
    @@ -199,7 +192,6 @@ protected boolean isIgnoredDir(File dir) {
             String n = dir.getName();
             return n.equals("workspace") || n.equals("artifacts")
                 || n.equals("plugins") // no mutable data here
    -            || n.equals("jenkins.security.RekeySecretAdminMonitor") // we don't want to rewrite backups
                 || n.equals(".") || n.equals("..");
         }
     
    
  • core/src/main/java/jenkins/security/RekeySecretAdminMonitor.java+4 1 modified
    @@ -1,6 +1,7 @@
     package jenkins.security;
     
     import hudson.Extension;
    +import hudson.Util;
     import hudson.init.InitMilestone;
     import hudson.init.Initializer;
     import hudson.model.TaskListener;
    @@ -50,6 +51,7 @@ public class RekeySecretAdminMonitor extends AsynchronousAdministrativeMonitor {
          */
         private final FileBoolean scanOnBoot = state("scanOnBoot");
     
    +    @SuppressWarnings("OverridableMethodCallInConstructor") // should have been final
         public RekeySecretAdminMonitor() throws IOException {
             // if JENKINS_HOME existed <1.497, we need to offer rewrite
             // this computation needs to be done and the value be captured,
    @@ -59,6 +61,7 @@ public RekeySecretAdminMonitor() throws IOException {
             if (j.isUpgradedFromBefore(new VersionNumber("1.496.*"))
             &&  new FileBoolean(new File(j.getRootDir(),"secret.key.not-so-secret")).isOff())
                 needed.on();
    +        Util.deleteRecursive(new File(getBaseDir(), "backups")); // SECURITY-376: no longer used
         }
     
         @Override
    @@ -133,7 +136,7 @@ protected File getLogFile() {
         protected void fix(TaskListener listener) throws Exception {
             LOGGER.info("Initiating a re-keying of secrets. See "+getLogFile());
     
    -        SecretRewriter rewriter = new SecretRewriter(new File(getBaseDir(),"backups"));
    +        SecretRewriter rewriter = new SecretRewriter();
     
             try {
                 PrintStream log = listener.getLogger();
    
  • core/src/test/groovy/hudson/util/SecretRewriterTest.groovy+1 3 modified
    @@ -70,8 +70,7 @@ class SecretRewriterTest {
          */
         @Test
         void recursionDetection() {
    -        def backup = tmp.newFolder("backup")
    -        def sw = new SecretRewriter(backup);
    +        def sw = new SecretRewriter();
             def st = StreamTaskListener.fromStdout()
     
             def o = encryptOld("Hello world")
    @@ -101,7 +100,6 @@ class SecretRewriterTest {
     
             dirs.each { p->
                 assert new File(t,"$p/foo.xml").text.trim()==answer
    -            assert new File(backup,"$p/foo.xml").text.trim()==payload
             }
     
             // t2 is only reachable by following a symlink. this should be covered, too
    
a572450f039f

[SECURITY-376] Remove backup directory for RekeySecretAdminMonitor.

https://github.com/jenkinsci/jenkinsJesse GlickDec 21, 2016via ghsa
3 files changed · +20 27
  • core/src/main/java/hudson/util/SecretRewriter.java+15 23 modified
    @@ -2,7 +2,6 @@
     
     import com.trilead.ssh2.crypto.Base64;
     import hudson.model.TaskListener;
    -import org.apache.commons.io.FileUtils;
     
     import javax.crypto.Cipher;
     import javax.crypto.SecretKey;
    @@ -33,21 +32,21 @@ public class SecretRewriter {
          */
         private int count;
     
    -    /**
    -     * If non-null the original file before rewrite gets in here.
    -     */
    -    private final File backupDirectory;
    -
         /**
          * Canonical paths of the directories we are recursing to protect
          * against symlink induced cycles.
          */
         private Set<String> callstack = new HashSet<String>();
     
    -    public SecretRewriter(File backupDirectory) throws GeneralSecurityException {
    +    public SecretRewriter() throws GeneralSecurityException {
             cipher = Secret.getCipher("AES");
             key = Secret.getLegacyKey();
    -        this.backupDirectory = backupDirectory;
    +    }
    +
    +    /** @deprecated SECURITY-376: {@code backupDirectory} is ignored */
    +    @Deprecated
    +    public SecretRewriter(File backupDirectory) throws GeneralSecurityException {
    +        this();
         }
     
         private String tryRewrite(String s) throws IOException, InvalidKeyException {
    @@ -70,12 +69,14 @@ private String tryRewrite(String s) throws IOException, InvalidKeyException {
                 return s;
         }
     
    -    /**
    -     * @param backup
    -     *      if non-null, the original file will be copied here before rewriting.
    -     *      if the rewrite doesn't happen, no copying.
    -     */
    +    /** @deprecated SECURITY-376: {@code backup} is ignored */
    +    @Deprecated
         public boolean rewrite(File f, File backup) throws InvalidKeyException, IOException {
    +        return rewrite(f);
    +    }
    +
    +    public boolean rewrite(File f) throws InvalidKeyException, IOException {
    +
             AtomicFileWriter w = new AtomicFileWriter(f, "UTF-8");
             try {
                 PrintWriter out = new PrintWriter(new BufferedWriter(w));
    @@ -117,10 +118,6 @@ public boolean rewrite(File f, File backup) throws InvalidKeyException, IOExcept
                 }
     
                 if (modified) {
    -                if (backup!=null) {
    -                    backup.getParentFile().mkdirs();
    -                    FileUtils.copyFile(f,backup);
    -                }
                     w.commit();
                 }
                 return modified;
    @@ -165,11 +162,7 @@ private int rewriteRecursive(File dir, String relative, TaskListener listener) t
                         if ((count++)%100==0)
                             listener.getLogger().println("Scanning "+child);
                         try {
    -                        File backup = null;
    -                        if (backupDirectory!=null)  backup = new File(backupDirectory,relative+'/'+ cn);
    -                        if (rewrite(child,backup)) {
    -                            if (backup!=null)
    -                                listener.getLogger().println("Copied "+child+" to "+backup+" as a backup");
    +                        if (rewrite(child)) {
                                 listener.getLogger().println("Rewritten "+child);
                                 rewritten++;
                             }
    @@ -199,7 +192,6 @@ protected boolean isIgnoredDir(File dir) {
             String n = dir.getName();
             return n.equals("workspace") || n.equals("artifacts")
                 || n.equals("plugins") // no mutable data here
    -            || n.equals("jenkins.security.RekeySecretAdminMonitor") // we don't want to rewrite backups
                 || n.equals(".") || n.equals("..");
         }
     
    
  • core/src/main/java/jenkins/security/RekeySecretAdminMonitor.java+4 1 modified
    @@ -1,6 +1,7 @@
     package jenkins.security;
     
     import hudson.Extension;
    +import hudson.Util;
     import hudson.init.InitMilestone;
     import hudson.init.Initializer;
     import hudson.model.TaskListener;
    @@ -50,6 +51,7 @@ public class RekeySecretAdminMonitor extends AsynchronousAdministrativeMonitor {
          */
         private final FileBoolean scanOnBoot = state("scanOnBoot");
     
    +    @SuppressWarnings("OverridableMethodCallInConstructor") // should have been final
         public RekeySecretAdminMonitor() throws IOException {
             // if JENKINS_HOME existed <1.497, we need to offer rewrite
             // this computation needs to be done and the value be captured,
    @@ -59,6 +61,7 @@ public RekeySecretAdminMonitor() throws IOException {
             if (j.isUpgradedFromBefore(new VersionNumber("1.496.*"))
             &&  new FileBoolean(new File(j.getRootDir(),"secret.key.not-so-secret")).isOff())
                 needed.on();
    +        Util.deleteRecursive(new File(getBaseDir(), "backups")); // SECURITY-376: no longer used
         }
     
         @Override
    @@ -133,7 +136,7 @@ protected File getLogFile() {
         protected void fix(TaskListener listener) throws Exception {
             LOGGER.info("Initiating a re-keying of secrets. See "+getLogFile());
     
    -        SecretRewriter rewriter = new SecretRewriter(new File(getBaseDir(),"backups"));
    +        SecretRewriter rewriter = new SecretRewriter();
     
             try {
                 PrintStream log = listener.getLogger();
    
  • core/src/test/groovy/hudson/util/SecretRewriterTest.groovy+1 3 modified
    @@ -70,8 +70,7 @@ class SecretRewriterTest {
          */
         @Test
         void recursionDetection() {
    -        def backup = tmp.newFolder("backup")
    -        def sw = new SecretRewriter(backup);
    +        def sw = new SecretRewriter();
             def st = StreamTaskListener.fromStdout()
     
             def o = encryptOld("Hello world")
    @@ -101,7 +100,6 @@ class SecretRewriterTest {
     
             dirs.each { p->
                 assert new File(t,"$p/foo.xml").text.trim()==answer
    -            assert new File(backup,"$p/foo.xml").text.trim()==payload
             }
     
             // t2 is only reachable by following a symlink. this should be covered, too
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.