Jenkins is still everywhere. Despite the rise of cloud-native CI/CD platforms, Jenkins powers a massive share of enterprise build infrastructure. That longevity comes with baggage — years of plugins with varying security quality, a permissive default configuration, and a Groovy scripting engine that gives pipeline authors the keys to the kingdom.
If Jenkins is part of your stack, hardening it is not optional. This guide covers the changes that reduce your attack surface the most.
Why Jenkins Is a High-Value Target
Jenkins servers typically have access to source code repositories, cloud credentials, signing keys, deployment targets, and internal networks. A compromised Jenkins instance is a supply chain compromise. Attackers do not need to target your application directly — they modify the build process and let your own pipeline deliver the payload.
The 2021 Jenkins security advisories alone covered remote code execution, credential exposure, and cross-site scripting across dozens of plugins. If you are running Jenkins, assume that at least some of your installed plugins have known vulnerabilities right now.
Lock Down the Script Security Plugin
Jenkins Pipeline scripts run Groovy code. The Script Security plugin mediates what methods and classes are available, but administrators often approve everything to stop build failures.
Do not do this.
Instead, maintain a whitelist of approved method signatures. Review every script approval request. If a pipeline needs java.lang.Runtime.exec(), that is a red flag unless you know exactly why.
// Instead of allowing arbitrary shell execution via Groovy
"ls -la".execute()
// Use the designated sh step which runs in the agent's sandbox
sh 'ls -la'
The sh step runs in the agent workspace with the agent's permissions. Direct Groovy execution runs in the Jenkins controller's JVM. That distinction matters enormously.
Isolate Credentials with Folder-Scoped Stores
Jenkins credentials are globally accessible by default. Any pipeline in any folder can reference any credential. This is terrible from a least-privilege perspective.
Use folder-scoped credential stores:
- Create a folder for each team or application.
- Store credentials in the folder's credential store, not the global one.
- Pipelines in that folder can access those credentials; pipelines elsewhere cannot.
For additional isolation, use the Credential Binding plugin to inject credentials as environment variables only for the specific step that needs them:
withCredentials([usernamePassword(credentialsId: 'deploy-creds',
usernameVariable: 'USER',
passwordVariable: 'PASS')]) {
sh './deploy.sh --user $USER --password $PASS'
}
Credentials are masked in build logs, but do not rely on masking alone. A determined attacker can encode and exfiltrate them.
Use Ephemeral Build Agents
Persistent build agents accumulate state: cached dependencies, leftover files from previous builds, potentially compromised tools. Use ephemeral agents that are provisioned for each build and destroyed afterward.
Options include:
- Kubernetes plugin: Spins up a pod per build with a defined container image.
- EC2 plugin: Launches an EC2 instance per build from a hardened AMI.
- Docker plugin: Runs each build in a fresh container.
Ephemeral agents eliminate persistence. Even if a build is compromised, the attack surface disappears when the agent is destroyed.
Restrict Pipeline Access with RBAC
The Role-Based Access Control plugin (or the built-in Matrix Authorization) lets you define who can create, modify, and run pipelines. Enforce these rules:
- Developers can trigger builds but cannot modify Jenkinsfile or pipeline configuration.
- Only designated pipeline engineers can edit pipeline definitions.
- Only the security team can approve script security exceptions.
- No one outside the operations team can access production deployment jobs.
If everyone is an administrator on your Jenkins instance, you do not have security. You have a shared root shell.
Enforce Jenkinsfile from Source Control
Pipelines defined in the Jenkins UI are editable by anyone with job configuration permissions. Pipelines defined in a Jenkinsfile stored in source control are subject to code review, branch protection, and audit trails.
Use the Organization Folders or Multibranch Pipeline features to automatically discover Jenkinsfile from repositories. Disable the ability to define pipeline scripts inline in the Jenkins UI.
This also means pipeline changes go through pull requests. Your security team can review changes to build logic the same way they review application code.
Harden the Jenkins Controller
The controller (formerly "master") should never run builds. It should only orchestrate.
- Set the number of executors on the controller to zero.
- Disable the built-in node in agent configuration.
- Run the controller behind a reverse proxy with TLS.
- Enable CSRF protection (crumb issuer).
- Disable the Jenkins CLI over remoting — it has been a recurring source of vulnerabilities.
- Restrict access to
/script(the Groovy console) to a tiny set of administrators.
Audit and Update Plugins Relentlessly
The Jenkins plugin ecosystem is massive, and many plugins are maintained by a single person or are effectively abandoned. Every installed plugin expands your attack surface.
- Remove plugins you are not using.
- Subscribe to the Jenkins security mailing list.
- Run the Plugin Health Score checker to identify plugins with known issues.
- Update plugins weekly, or at minimum when security advisories drop.
- Test plugin updates in a staging Jenkins instance before rolling to production.
Secure the Jenkins API
Jenkins exposes a REST API and a CLI. Both can be used to extract credentials, trigger builds, and modify configurations.
- Disable anonymous read access.
- Require API tokens instead of passwords for API authentication.
- Rate-limit API access.
- Monitor API calls for unusual patterns — bulk credential reads, rapid job creation, or configuration exports.
Network Segmentation
Jenkins should not be on the public internet. If remote developers need access, put it behind a VPN or a zero-trust access proxy. The controller should only be reachable by build agents and authorized users.
Build agents should have network access scoped to what their builds require — artifact repositories, container registries, deployment targets. They should not have unrestricted outbound internet access, which is what an attacker uses to exfiltrate data.
Pipeline-Level Security Scanning
Add security scanning steps directly into your Jenkinsfiles:
stage('Security Scan') {
parallel {
stage('SAST') {
steps {
sh 'semgrep --config auto .'
}
}
stage('Dependency Check') {
steps {
sh 'npm audit --production'
}
}
stage('Container Scan') {
steps {
sh 'trivy image myapp:${BUILD_TAG}'
}
}
}
}
Make these stages non-skippable. If they fail, the pipeline fails.
How Safeguard.sh Helps
Safeguard.sh provides continuous monitoring of your Jenkins infrastructure and pipeline configurations. It detects insecure credential usage, overly permissive script approvals, and pipelines missing security scanning stages. By integrating with your Jenkins instance, Safeguard.sh builds a real-time inventory of every pipeline, plugin, and credential scope — flagging deviations from your security baseline and generating actionable remediation guidance. Your team can enforce pipeline security policies without manually auditing every Jenkinsfile across every repository.