此漏洞的产生是因为用户控制的输入被不安全地注入到Git检出命令中。
用户输入作为构建参数提供(例如gitParameters),其中可能包含恶意shell命令。
该参数被包装到GitParameterValue(继承StringParameterValue)中,其buildEnvironment()方法在不进行清理的情况下将其暴露为构建上下文中的环境变量。
在SCM检出过程中,Jenkins通过build.getEnvironment()加载构建环境变量。
用于检出的分支名(localBranchName)从这些环境变量中获取。
分支名随后直接传递给CheckoutCommand.branch()方法。
最后,CheckoutCommand.execute()调用底层的Git CLI命令,该命令将分支名未经验证或转义地拼接在一起。
这使得攻击者能够在Jenkins构建主机上执行任意shell命令。
处理用户输入的createValue方法(例如来自HTTP POST JSON负载),这是Jenkins通过请求接受用户提供的参数值的地方(例如"selected": "master; rm -rf /")。
输入被包装到GitParameterValue中,它继承自StringParameterValue,没有输入清理或验证。
这意味着原始用户数据被作为构建参数接受并存储为ParameterValue实例。

GitParameterValue类扩展StringParameterValue,GitParameterValue继承自StringParameterValue但不添加任何清理。
构造函数链意味着用户输入现在存储在一个稍后将被Jenkins用于构建环境变量的对象中。
这会将恶意输入传播到Jenkins构建环境变量中。

StringParameterValue类及其buildEnvironment方法,此方法至关重要——它通过执行以下操作将参数作为环境变量暴露在构建上下文中:

env.put(name, value);
env.put(name.toUpperCase(Locale.ENGLISH), value);
由于值未经过清理,允许恶意输入进入Jenkins的环境变量,使其可供后续进程(如Git命令)访问。
GitSCM插件中的_checkout方法,此方法调用build.getEnvironment(listener),收集环境变量,包括之前设置的恶意变量。
它使用这些变量获取分支名(通过localBranchName),然后将其传递给CheckoutCommand。
来自恶意参数的环境变量直接流入检出过程。

创建CheckoutCommand并使用用户输入设置分支/引用,CheckoutCommand.branch(localBranchName)使用未清理的环境变量。
由于localBranchName来自用户控制的环境变量,它将任意命令注入到检出中,这为调用execute()时的命令注入设置了条件。

CheckoutCommand.execute()方法运行Git CLI命令,这是最终步骤,注入的分支字符串直接传递到系统的Git CLI,没有转义或清理,因此恶意负载作为shell命令执行,允许在Jenkins主机上远程执行代码。

此分析揭示了Jenkins Git参数插件与Git SCM插件结合如何导致严重的命令注入漏洞。通过不安全地将用户控制的参数值暴露为环境变量,然后将其直接传递给Git CLI命令而不进行适当清理,攻击者可以在Jenkins构建服务器上执行任意命令。
这种信任链的破坏——从最初的恶意JSON负载到最终的shell执行——强调了在持续集成系统中严格输入验证和安全处理构建参数的重要性。
用户和管理员应确保运行更新的Jenkins版本和所有插件,并仔细审计影响shell命令的任何参数。诸如输入清理、允许的分支白名单或隔离构建环境等缓解措施可以降低风险。
理解这一流程使安全专业人员和开发人员能够洞察以检测、预防和修复Jenkins或类似CI/CD平台中类似的注入漏洞。