Checkpoint Lab — Security Hardening, CSRF, Agent-to-Controller Controls, Script Security, CSP, TLS, and Reverse Proxies
Harden an intentionally weak but local-only Jenkins lab, prove each control with safe tests, preserve before/after evidence, and document rollback boundaries without ever disabling CSRF, authorization, Script Security, TLS verification, or agent-to-controller protection.
Learning objectives
- Predict security-state changes before hardening the lab.
- Move execution off the controller and prove queue behavior.
- Verify CSRF, script, CSP, proxy/TLS and agent boundaries independently.
- Capture a complete before/after evidence packet without secret material.
- Document rollback so hardening is repeatable rather than a one-off UI exercise.
1. Mission: harden a weak but local-only controller
Your lab starts with Jenkins 2.568.3 LTS/Java 21 on loopback or an
isolated container network. CSRF and authorization are already
enabled. Weaknesses are deliberately limited to conditions that do
not require disabling security: the built-in node has one executor,
security evidence has not been documented, the general UI CSP is not
enforced, and the reverse-proxy/TLS design exists only as an
unverified local configuration. A disposable
trusted-lab agent is available.
Finish with a controller that does not execute builds, current Script Security, tested CSRF behavior, staged/enforced CSP in the disposable clone, a correct TLS/proxy model, documented agent isolation and a reproducible evidence packet.
2. Assumptions and preflight
| Component | Checkpoint assumption |
|---|---|
| Jenkins | 2.568.3 LTS |
| Java | 21 (25 also supported by this LTS) |
| Script Security | 1422.v06869826dd9b_ or newer; do not continue on 1415 or earlier |
| Agent |
Disposable trusted-lab, separate
process/identity, no JENKINS_HOME access
|
| Credentials | Fake lab user/API token only; never archive or print it |
| TLS/proxy | Local Nginx/Caddy simulation or reviewed config; no public DNS required |
3. Predict before changing anything
Write at least these predictions:
-
After built-in executors become zero, a job constrained to
trusted-labwill wait rather than run on the controller when that agent is offline. - After correct proxy headers are introduced, public HTTPS requests will no longer produce HTTP absolute redirects, and WebSocket upgrade evidence will be available for inbound agents.
- After CSP enforcement is enabled in the clone, compatible Jenkins UI pages will carry the enforced policy while violations identify any incompatible plugin UI.
Also predict which states should not change: source SHA, prior build records, archived artifacts and credentials values.
4. Capture the before packet
evidence/security-ch29/
├── assumptions.md
├── controller-version.txt
├── plugins-security.txt
├── listeners-before.txt
├── node-executors-before.txt
├── approvals-before.txt
├── headers-before.txt
└── proxy-config-before.conf
Use screenshots for UI-only settings if needed. Redact Authorization/Cookie headers and never store a private key or API token in this directory.
5. Apply bounded hardening changes
A. Controller execution
Set built-in executors from 1 to 0. Run the synthetic job on
trusted-lab; record build number, node name and
workspace. Mark the agent temporarily offline and trigger again;
record the queue reason, then reconnect the agent and let the same
queued item proceed.
B. CSRF behavior
Using the disposable identity, perform one harmless authenticated read. Then trigger the exact synthetic job with an API token and record the returned status/queue location. Separately document the password/session crumb flow from Lesson 2 without storing credentials. CSRF remains enabled throughout.
C. Script boundary
Confirm Script Security 1422.v06869826dd9b_ or later
and export the list/count of pending and approved entries. Do not
create a dangerous approval merely to have evidence; “none pending”
is valid evidence.
D. CSP
Review violation data and core plugin screens, then enable general UI CSP in the disposable clone. Record the response header and any violation that occurs. If a plugin breaks, revert the CSP change in the clone and record the incompatibility rather than weakening the rule globally.
E. TLS/reverse proxy
Validate the local configuration contains host/scheme forwarding and
WebSocket upgrade support; confirm the Jenkins context path matches.
If you run it locally with a self-signed certificate,
curl -k is allowed only for this isolated test. In
production, install a trusted chain instead.
F. Agent boundary
Record agent process identity, Java/Remoting context, labels and
workspace root. Prove the worker does not mount/read
JENKINS_HOME. Do not attempt to disable
agent→controller access control—it is always enabled in current
Jenkins.
6. Independent verification checklist
- Built-in node shows 0 executors.
- A queued lab build does not fall back to the controller when the agent is offline.
- CSRF protection is still enabled; API-token behavior and session/crumb behavior are documented correctly.
- Script Security is 1422+ and approval inventory is captured.
- General UI CSP state is recorded with header/violation evidence; user-content isolation plan is documented.
- Proxy config preserves Host and X-Forwarded-Proto, supports WebSocket upgrade and does not expose the backend as an unintended public entry point.
- Agent identity/workspace is separate from controller home.
- No evidence file contains credentials, tokens, session cookies or TLS private keys.
7. Evidence packet
Add these files or equivalent records:
evidence/security-ch29/
├── build-and-queue-ids.txt
├── node-executors-after.txt
├── csrf-test-redacted.txt
├── approvals-after.txt
├── csp-headers-after.txt
├── proxy-config-after.conf
├── agent-identity.txt
├── listeners-after.txt
├── rollback.md
└── findings.md
findings.md should distinguish configuration truth from
test outcome: “header present” is not the same as “every plugin UI
is compatible,” and “agent connected” is not the same as “agent is
trustworthy.”
8. Cleanup and rollback
Rollback is not “turn security off.” If the local proxy test is no longer needed, stop/remove only the disposable proxy and delete the lab certificate/key securely. If CSP exposes a plugin incompatibility, return the clone to its prior CSP state while preserving the violation evidence and opening a remediation item. Keep built-in executors at zero if an eligible agent exists. Remove the fake lab token/user and synthetic jobs after exporting non-secret evidence.
9. What this chapter adds to the production operating model
You now have a layered security model that links HTTP/TLS, identity, CSRF, controller execution, script/plugin trust, agent Remoting and browser content to independent evidence. That is the prerequisite for Chapter 30: external identity and access governance. SSO/LDAP/OIDC/SAML can improve identity lifecycle, but they do not replace these controller, script, agent and transport boundaries.
Knowledge check
Answer before revealing the explanation.
1. The agent is offline and the build remains queued after hardening. Is that a failure?
Not necessarily. With built-in executors at zero, waiting for an eligible trusted agent is the expected safe state. Diagnose capacity/labels rather than running on the controller.
2. A plugin UI breaks after CSP enforcement. What should the checkpoint record?
The exact plugin/version, page, violation evidence and rollback of the clone CSP state. Do not silently weaken the policy or omit the incompatibility.
3. Why is an API-token POST without a crumb not evidence that CSRF is disabled?
Current Jenkins intentionally exempts API-token-authenticated requests from crumb validation. Verify the CSRF setting and session/password behavior separately.
4. What is the correct response if the lab reports Script Security 1415?
Stop relying on sandbox protections and upgrade through the reviewed plugin-maintenance path to 1422 or later, because 1415 and earlier are affected by the 16 September 2026 sandbox vulnerabilities.
5. Which Chapter 30 topic naturally follows this hardening work?
External identity and access governance—SSO, LDAP and OIDC/SAML—because identity federation must sit on top of, not replace, the controller/transport/script/agent boundaries established here.
Official references and version notes
- Jenkins LTS changelog — confirms Jenkins 2.568.3 (2 September 2026) and tested Java 21/25.
- Securing Jenkins — access control, controller isolation, CSRF, CSP, user content, ports and credentials.
- Controller Isolation — do not run builds on the built-in node; agent→controller access control is always enabled since Jenkins 2.326.
- CSRF Protection — crumb/session behavior and API-token exemption.
- Content Security Policy — general UI CSP in Jenkins 2.539+, rollout guidance and Resource Root URL recommendation for user content.
- Reverse proxy configuration — request/response rewriting, forwarded headers, context paths and WebSocket handling.
- Script Security plugin and Jenkins Security Advisory 2026-09-16 — sandbox fixes in Script Security 1422.v06869826dd9b_.
2.568.3 LTS with Java 21 (Jenkins
2.568.3 is tested with Java 21 and 25) and Script Security
1422.v06869826dd9b_. Script Security
1415.v9a_f9b_3a_c253d and earlier are affected by
multiple sandbox vulnerabilities disclosed 16 September 2026.
General Jenkins UI CSP is a core feature in Jenkins 2.539+ but is
disabled by default because plugin compatibility varies; introduce
it using report evidence and testing. Re-check Jenkins core/plugin
advisories before applying these patterns to a long-lived
controller.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.