Moderate severityNVD Advisory· Published Nov 4, 2020· Updated Aug 4, 2024
CVE-2020-2305
CVE-2020-2305
Description
Jenkins Mercurial Plugin 2.11 and earlier does not configure its XML parser to prevent XML external entity (XXE) attacks.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.jenkins-ci.plugins:mercurialMaven | >= 2.11, < 2.12 | 2.12 |
org.jenkins-ci.plugins:mercurialMaven | >= 2.10, < 2.10.1 | 2.10.1 |
org.jenkins-ci.plugins:mercurialMaven | >= 2.9, < 2.9.1 | 2.9.1 |
org.jenkins-ci.plugins:mercurialMaven | < 2.8.1 | 2.8.1 |
Affected products
1- Range: unspecified
Patches
184af58b08f80[SECURITY-2115]
3 files changed · +85 −70
pom.xml+2 −2 modified@@ -17,7 +17,7 @@ <properties> <revision>2.12</revision> <changelist>-SNAPSHOT</changelist> - <jenkins.version>2.176.4</jenkins.version> + <jenkins.version>2.190.3</jenkins.version> <java.level>8</java.level> <no-test-jar>false</no-test-jar> <reuseForks>false</reuseForks> <!-- long story --> @@ -78,7 +78,7 @@ <dependencies> <dependency> <groupId>io.jenkins.tools.bom</groupId> - <artifactId>bom-2.176.x</artifactId> + <artifactId>bom-2.190.x</artifactId> <version>13</version> <scope>import</scope> <type>pom</type>
src/main/java/hudson/plugins/mercurial/MercurialChangeLogParser.java+65 −24 modified@@ -4,15 +4,17 @@ import hudson.model.Run; import hudson.scm.ChangeLogParser; import hudson.scm.RepositoryBrowser; -import hudson.util.Digester2; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.Set; +import jenkins.util.xml.XMLUtils; -import org.apache.commons.digester.Digester; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** @@ -30,35 +32,74 @@ public MercurialChangeLogParser(Set<String> modules) { @Override public MercurialChangeSetList parse(Run build, RepositoryBrowser<?> browser, File changelogFile) throws IOException, SAXException { - Digester digester = new Digester2(); - ArrayList<MercurialChangeSet> r = new ArrayList<MercurialChangeSet>(); - digester.push(r); - - digester.addObjectCreate("*/changeset", MercurialChangeSet.class); - digester.addSetProperties("*/changeset"); - digester.addSetProperties("*/changeset", "author", "user"); - digester.addBeanPropertySetter("*/changeset/msg"); - // Before JENKINS-55319: - digester.addBeanPropertySetter("*/changeset/added"); - digester.addBeanPropertySetter("*/changeset/deleted"); - digester.addBeanPropertySetter("*/changeset/files"); - // After JENKINS-55319: - digester.addCallMethod("*/changeset/file", "addFile", 1); - digester.addCallParam("*/changeset/file", 0); - digester.addCallMethod("*/changeset/addedFile", "addAddedFile", 1); - digester.addCallParam("*/changeset/addedFile", 0); - digester.addCallMethod("*/changeset/deletedFile", "addDeletedFile", 1); - digester.addCallParam("*/changeset/deletedFile", 0); - digester.addBeanPropertySetter("*/changeset/parents"); - digester.addSetNext("*/changeset", "add"); + ArrayList<MercurialChangeSet> r = new ArrayList<>(); + Element changesetsE; try { - digester.parse(changelogFile); + changesetsE = XMLUtils.parse(changelogFile, "UTF-8").getDocumentElement(); } catch (IOException e) { throw new IOException("Failed to parse " + changelogFile, e); } catch (SAXException e) { throw new IOException("Failed to parse " + changelogFile + ": '" + Util.loadFile(changelogFile) + "'", e); } + NodeList changesetsNL = changesetsE.getChildNodes(); + for (int i = 0; i < changesetsNL.getLength(); i++) { + if (changesetsNL.item(i).getNodeType() != Node.ELEMENT_NODE) { + continue; + } + Element changesetE = (Element) changesetsNL.item(i); + MercurialChangeSet cs = new MercurialChangeSet(); + // See CHANGELOG_TEMPLATE: + cs.setNode(changesetE.getAttribute("node")); + if (changesetE.hasAttribute("user")) { + cs.setAuthor(changesetE.getAttribute("user")); + } else { + cs.setAuthor(changesetE.getAttribute("author")); + } + if (changesetE.hasAttribute("rev")) { // unit tests omit it + cs.setRev(Long.parseLong(changesetE.getAttribute("rev"))); + } + cs.setDate(changesetE.getAttribute("date")); + NodeList changesetNL = changesetE.getChildNodes(); + for (int j = 0; j < changesetNL.getLength(); j++) { + if (changesetNL.item(j).getNodeType() != Node.ELEMENT_NODE) { + continue; + } + Element otherE = (Element) changesetNL.item(j); + String text = otherE.getTextContent(); + switch (otherE.getTagName()) { + case "msg": + cs.setMsg(text); + break; + // Before JENKINS-55319: + case "added": + cs.setAdded(text); + break; + case "deleted": + cs.setDeleted(text); + break; + case "files": + cs.setFiles(text); + break; + // After JENKINS-55319: + case "file": + cs.addFile(text); + break; + case "addedFile": + cs.addAddedFile(text); + break; + case "deletedFile": + cs.addDeletedFile(text); + break; + case "parents": + cs.setParents(text); + break; + default: + throw new IOException(otherE.getTagName()); + } + } + r.add(cs); + } if (modules != null) { Iterator<MercurialChangeSet> it = r.iterator();
src/main/java/hudson/plugins/mercurial/MercurialChangeSet.java+18 −44 modified@@ -11,7 +11,7 @@ import java.util.Collections; import java.util.List; import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.DoNotUse; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.export.Exported; @@ -203,91 +203,66 @@ public List<EditType> getEditTypes() { } } -// -// used by Digester -// - @Restricted(DoNotUse.class) - public void setMsg(String msg) { + // For use from MercurialChangeLogParser: + + void setMsg(String msg) { this.msg = msg; } - @Restricted(DoNotUse.class) + @Restricted(NoExternalUse.class) // for tests public void setNode(String node) { this.node = node; } - @Restricted(DoNotUse.class) - public void setUser(String author) { - this.author = author; - } - - @Restricted(DoNotUse.class) - public String getUser() { - return author; - } - - @Restricted(DoNotUse.class) - public void setAuthor(String author) { + void setAuthor(String author) { this.author = author; } - @Restricted(DoNotUse.class) - public void setRev(long rev) { + void setRev(long rev) { this.rev = rev; } - @Restricted(DoNotUse.class) - public void setDate(String date) { + void setDate(String date) { this.date = date; } - @Restricted(DoNotUse.class) - public void addAddedFile(String file) { + void addAddedFile(String file) { added.add(file); } - @Restricted(DoNotUse.class) - public void addDeletedFile(String file) { + void addDeletedFile(String file) { deleted.add(file); } - @Restricted(DoNotUse.class) - public void addFile(String file) { + void addFile(String file) { modified.add(file); } - /** @deprecated predates JENKINS-55319, here only for compatibility */ - @Deprecated - @Restricted(DoNotUse.class) - public void setAdded(String list) { + /** predates JENKINS-55319, here only for compatibility */ + void setAdded(String list) { if (merge) { return; } added = toList(list); } - /** @deprecated predates JENKINS-55319, here only for compatibility */ - @Deprecated - @Restricted(DoNotUse.class) - public void setDeleted(String list) { + /** predates JENKINS-55319, here only for compatibility */ + void setDeleted(String list) { if (merge) { return; } deleted = toList(list); } - /** @deprecated predates JENKINS-55319, here only for compatibility */ - @Deprecated - @Restricted(DoNotUse.class) - public void setFiles(String list) { + /** predates JENKINS-55319, here only for compatibility */ + void setFiles(String list) { if (merge) { return; } modified = toList(list); } - @Restricted(DoNotUse.class) - public void setParents(String parents) { + void setParents(String parents) { // Possible values for parents when not using --debug: // "" - commit made in succession // "6019:b70a530bdb93 " - commit with older parent @@ -299,7 +274,6 @@ public void setParents(String parents) { merge = parents.indexOf(':') != parents.lastIndexOf(':') && !parents.contains("-1"); } - @Deprecated private List<String> toList(String list) { list = list.trim(); if(list.length()==0) return Collections.emptyList();
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
5- github.com/advisories/GHSA-x58r-wxc3-7pqrghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-2305ghsaADVISORY
- github.com/CVEProject/cvelist/blob/381fe967666a5ce01625a7a050427aa4757e3ca6/2020/2xxx/CVE-2020-2305.jsonghsaWEB
- github.com/jenkinsci/mercurial-plugin/commit/84af58b08f80bb92792f7bc04a31487f3eeee95aghsaWEB
- www.jenkins.io/security/advisory/2020-11-04/ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.