VYPR
High severityNVD Advisory· Published Sep 12, 2019· Updated Aug 4, 2024

CVE-2019-10392

CVE-2019-10392

Description

Jenkins Git Client Plugin allowed OS command injection via unsanitized URL argument to git ls-remote, enabling attackers with Job/Configure permission to execute arbitrary commands.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Jenkins Git Client Plugin allowed OS command injection via unsanitized URL argument to git ls-remote, enabling attackers with Job/Configure permission to execute arbitrary commands.

Vulnerability

Description CVE-2019-10392 is an OS command injection vulnerability in the Jenkins Git Client Plugin versions 2.8.4 and earlier, and 3.0.0-rc [1]. The plugin did not properly restrict user-supplied values passed as the URL argument to the git ls-remote command, allowing attackers to inject arbitrary OS commands [2].

Exploitation

An attacker with Job/Configure permission can exploit this by providing a malicious repository URL containing shell metacharacters [3]. The plugin does not validate the URL format, so a crafted string like ; malicious_command can be appended to the URL, leading to command execution [2]. The attack occurs during job configuration when the plugin validates the repository URL via git ls-remote [3].

Impact

Successful exploitation allows the attacker to execute arbitrary system commands on the Jenkins controller, running with the same privileges as the Jenkins process [3]. This can lead to full compromise of the Jenkins server and any data accessible to it [1].

Mitigation

The vulnerability is fixed in Git Client Plugin version 2.8.5 [4]. Users of version 3.0.0-rc should downgrade to 2.8.5 until a stable 3.x fix is available [3]. The fix introduces URL validation and uses the -- separator in git commands to prevent option injection [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.

PackageAffected versionsPatched versions
org.jenkins-ci.plugins:git-clientMaven
< 2.8.52.8.5

Affected products

2

Patches

1
899123fa2eb9

[SECURITY-1534] Prevent remote execution by repo URL

1 file changed · +73 7
  • src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java+73 7 modified
    @@ -369,6 +369,67 @@ public List<IndexEntry> getSubmodules( String treeIsh ) throws GitException, Int
             return submodules;
         }
     
    +    /**
    +     * Constant which disables safety check of remote URL.
    +     *
    +     * <code>CHECK_REMOTE_URL=Boolean.valueOf(System.getProperty(CliGitAPIImpl.class.getName() + ".checkRemoteURL", "true"))</code>.
    +     *
    +     * Refuse unsafe git URL's, including URL's that start with '-'
    +     * and URL's that contain space characters.
    +     *
    +     * Use '-Dorg.jenkinsci.plugins.gitclient.CliGitAPIImpl.checkRemoteURL=false'
    +     * to prevent check of remote URL.
    +     */
    +    private static final boolean CHECK_REMOTE_URL = Boolean.valueOf(System.getProperty(CliGitAPIImpl.class.getName() + ".checkRemoteURL", "true"));
    +
    +    /**
    +     * SECURITY-1534 found that arguments
    +     * added to a git URL from the user interface can allow a user
    +     * with job creation permissions to execute an arbitrary program
    +     * on the git server if the git server is configured to allow
    +     * custom pack programs. Reject a URL if it includes invalid
    +     * content.
    +     */
    +    private void addCheckedRemoteUrl(@NonNull ArgumentListBuilder args, @NonNull String url) {
    +        String trimmedUrl = url.trim();
    +        /* Don't check for invalid args if URL starts with known good cases.
    +         * Known good cases include:
    +         * '/' - Unix local file
    +         * 'C:' - Windows local file
    +         * 'file:', 'git:', 'http:', 'https:', 'ssh:', and 'git@' - known protocols
    +         */
    +        if (CHECK_REMOTE_URL
    +                && !trimmedUrl.startsWith("/")
    +                && !trimmedUrl.startsWith("\\\\")
    +                && !trimmedUrl.startsWith("file:")
    +                && !trimmedUrl.startsWith("git:")
    +                && !trimmedUrl.startsWith("git@")
    +                && !trimmedUrl.startsWith("http:")
    +                && !trimmedUrl.startsWith("https:")
    +                && !trimmedUrl.startsWith("ssh:")
    +                && !trimmedUrl.matches("^[A-Za-z]:.+")) {
    +            /* Not one of the known good cases, check if this could be a bad case
    +             * Bad cases include:
    +             * '-' - starts with 'dash' as possible argument
    +             * '`' - includes backquote in the string (command execution)
    +             * ' ' - includes a space (not guaranteed a threat, but threat risk increases)
    +             */
    +            if (trimmedUrl.startsWith("-")
    +                    || trimmedUrl.contains("`")
    +                    || trimmedUrl.contains("--upload-pack=")
    +                    || trimmedUrl.matches(".*\\s+.*")) {
    +                throw new GitException("Invalid remote URL: " + url);
    +            }
    +        }
    +        // Mark the end of options for git versions that support it.
    +        // Tells command line git that later arguments are operands, not options.
    +        // See POSIX 1-2017 guideline 10.
    +        if (isAtLeastVersion(2, 8, 0, 0)) {
    +            args.add("--"); // SECURITY-1534 - end of options, causes tests to fail with git 2.7.4 and older
    +        }
    +        args.add(trimmedUrl);
    +    }
    +
         /**
          * fetch_.
          *
    @@ -497,7 +558,7 @@ public void fetch(String remoteName, RefSpec... refspec) throws GitException, In
             String url = getRemoteUrl(remoteName);
             if (url == null)
                 throw new GitException("remote." + remoteName + ".url not defined");
    -        args.add(url);
    +        addCheckedRemoteUrl(args, url);
             if (refspec != null && refspec.length > 0)
                 for (RefSpec rs: refspec)
                     if (rs != null)
    @@ -2770,7 +2831,10 @@ public Set<String> getRemoteTagNames(String tagPattern) throws GitException {
             try {
                 ArgumentListBuilder args = new ArgumentListBuilder();
                 args.add("ls-remote", "--tags");
    -            args.add(getRemoteUrl("origin"));
    +            String remoteUrl = getRemoteUrl("origin");
    +            if (remoteUrl != null) {
    +                addCheckedRemoteUrl(args, remoteUrl);
    +            }
                 if (tagPattern != null)
                     args.add(tagPattern);
                 String result = launchCommandIn(args, workspace);
    @@ -2872,7 +2936,7 @@ public Set<String> getRefNames(String refPrefix) throws GitException, Interrupte
         public Map<String, ObjectId> getHeadRev(String url) throws GitException, InterruptedException {
             ArgumentListBuilder args = new ArgumentListBuilder("ls-remote");
             args.add("-h");
    -        args.add(url);
    +        addCheckedRemoteUrl(args, url);
     
             StandardCredentials cred = credentials.get(url);
             if (cred == null) cred = defaultCredentials;
    @@ -2902,7 +2966,8 @@ public ObjectId getHeadRev(String url, String branchSpec) throws GitException, I
             StandardCredentials cred = credentials.get(url);
             if (cred == null) cred = defaultCredentials;
     
    -        args.add(url);
    +        addCheckedRemoteUrl(args, url);
    +
             if (branchName.startsWith("refs/tags/")) {
                 args.add(branchName+"^{}"); // JENKINS-23299 - tag SHA1 needs to be converted to commit SHA1
             } else {
    @@ -2922,7 +2987,7 @@ public Map<String, ObjectId> getRemoteReferences(String url, String pattern, boo
             if (tagsOnly) {
                 args.add("-t");
             }
    -        args.add(url);
    +        addCheckedRemoteUrl(args, url);
             if (pattern != null) {
                 args.add(pattern);
             }
    @@ -2964,7 +3029,7 @@ public Map<String, String> getRemoteSymbolicReferences(String url, String patter
                 // https://github.com/git/git/blob/afd6726309/Documentation/RelNotes/2.8.0.txt#L72-L73
                 ArgumentListBuilder args = new ArgumentListBuilder("ls-remote");
                 args.add("--symref");
    -            args.add(url);
    +            addCheckedRemoteUrl(args, url);
                 if (pattern != null) {
                     args.add(pattern);
                 }
    @@ -3013,7 +3078,8 @@ public void push(RemoteConfig repository, String refspec) throws GitException, I
             StandardCredentials cred = credentials.get(url);
             if (cred == null) cred = defaultCredentials;
     
    -        args.add("push", url);
    +        args.add("push");
    +        addCheckedRemoteUrl(args, url);
     
             if (refspec != null)
                 args.add(refspec);
    

Vulnerability mechanics

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

References

5

News mentions

0

No linked articles in our index yet.