This policy covers security issues in:
- JenkinsAsService Windows Service (the .NET executable)
- JenkinsAsService.Installer MSI package (WiX v5)
- CI/CD workflows in this repository (GitHub Actions)
- Documentation that could mislead users into insecure configurations
Out of scope:
- Jenkins itself (report to Jenkins Security)
- The Java runtime or JDK (report to your JDK vendor)
- Third-party NuGet packages (report to the package maintainer; see Dependencies below)
- Windows OS or DPAPI/Credential Manager subsystems (report to Microsoft)
Only the latest release receives security fixes. Older versions are not patched — upgrade to the latest release to stay protected.
| Version | Supported |
|---|---|
| Latest release | Yes |
| Older releases | No |
Do not open a public issue. Security vulnerabilities must be reported privately.
- Go to the Security Advisories tab
- Click "Report a vulnerability"
- Fill in the details and submit
GitHub will create a private advisory visible only to you and the maintainers.
If you prefer email, contact the maintainer directly. You can find contact information on the GitHub profile.
A good report helps us fix the issue faster. Please include:
- Description of the vulnerability and its potential impact
- Affected component (service, installer, workflow, configuration)
- Steps to reproduce or a proof-of-concept (if possible)
- Environment — OS version, .NET version, JDK version, JenkinsAsService version
- Suggested fix (optional, but welcome)
| Stage | Target |
|---|---|
| Acknowledge receipt | 3 business days |
| Initial assessment and severity | 7 business days |
| Patch development | 30 days for critical/high, 90 days for medium/low |
| Public disclosure | Coordinated with reporter, after patch is released |
Timelines are best-effort targets. This is a personal open-source project maintained by a single developer — not a commercial product with a dedicated security team.
We follow responsible disclosure practices:
- We will work with you to understand and reproduce the issue
- We will keep you informed of progress toward a fix
- We ask that you do not share details publicly until a patch is released
- We aim to publish a fix and advisory simultaneously
- You are welcome to self-disclose after 90 days if no fix has been released
- We will never publish your identity or communications without your permission
If you would like to be credited in the advisory, let us know — we are happy to acknowledge reporters.
JenkinsAsService handles sensitive data (Jenkins agent secrets) and runs as a privileged Windows Service. The following measures are in place:
Secrets are never stored in plaintext by default (the MSI installer defaults to Dpapi). Five protection modes are available, strongest first:
| Mode | Mechanism | Risk if host is compromised |
|---|---|---|
Tpm |
TPM-bound, non-exportable RSA key (Platform Crypto Provider) | Usable only on this machine's TPM, by a process that can access the key |
Dpapi |
Machine-scoped DPAPI encryption | Decryptable by any process on the same machine |
CredentialManager |
Windows Credential Manager vault | Accessible to processes running as the same user |
EnvironmentVariable |
Machine-level environment variable | Readable by any process on the machine |
Unprotected |
Plaintext in appsettings.json |
Readable by anyone with file access |
Dpapi additionally supports a User scope, which binds the ciphertext to the single identity that encrypted it — stronger than Machine, but it requires the secret to be written by the service account, so it is unavailable to virtual accounts and gMSA. appsettings.json itself is ACL-restricted to SYSTEM, Administrators and the service account.
At runtime the resolved secret is written to a separate ACL-restricted file and passed to the Java agent as -secret @<file>, so it never appears in the process table (where any local administrator could read it for the agent's whole lifetime). The file is rewritten on each restart and deleted on service stop.
- The Java agent child is launched with a deny-by-default environment — only a curated allow-list plus explicitly configured additions — so the service's own environment block cannot leak into untrusted pipeline scripts
- Win32 process-mitigation policies are applied to the service process: no remote, low-integrity or non-System32 DLL loads, and legacy extension-point injection disabled
- Binaries and runtime data are separated: the install folder stays read-only to the agent identity, while logs, the secret file, the jar cache and the build work directory live under
%ProgramData%. A malicious pipeline therefore cannot overwrite the service binary and wait for a restart - The cached
agent.jarlives in its own subfolder, isolated from the build workspace, and its SHA-256 is re-verified before reuse — trust-on-first-use local integrity, complementing controller certificate pinning for upstream authenticity - The service runs under a least-privilege virtual service account (
NT SERVICE\Jenkins) by default, and the runtime data folder is granted to that account explicitly (inheritableModify, with inheritance left on so SYSTEM and Administrators keep full control)- Fixed in this release: installs performed by the
.exebundle registered the service as LocalSystem instead. The bundle forwarded an emptySERVICE_ACCOUNT, and an empty public property on the msiexec command line overrides the package default rather than deferring to it, so the service was registered with no account name at all. Upgrading with a current.execorrects the identity in place, keeping the configuration, secret and data folder. To check an existing install:(Get-CimInstance Win32_Service -Filter "Name='Jenkins'").StartName
- Fixed in this release: installs performed by the
- Uninstall leaves no secret behind, in any store:
appsettings.jsonand the whole data folder are deleted, and the secret is removed from wherever the configured mode put it — the machine-scoped TPM key, the Credential Manager entry, or the machine environment variable. OnlyUnprotectedandDpapikeep the material in the config itself; the other modes store a pointer there, so deleting the file alone would leave a working agent credential on a host the product had supposedly been removed from. None of it is a tracked MSI file, so Windows Installer removes none of it on its own- Credential Manager entries are per-user. The uninstall runs as SYSTEM, so a credential written under another account (
update-secret --impersonate) cannot be removed for you; the purge says so explicitly and prints thecmdkey /delete:command to run while logged on as that account
- Credential Manager entries are per-user. The uninstall runs as SYSTEM, so a credential written under another account (
Agent secrets are scrubbed from all log output (file and Event Log) before being written. Every occurrence is replaced with ***** — and not only the literal value: the secret travels through a URL, a JVM argument and the controller's own error bodies before returning on the agent's stderr, so the URL-encoded, XML/HTML-escaped and Base64 forms are scrubbed too. A percent-encoded secret in a log file is just as disclosed as a plain one. Patterns are applied longest-first, so a shorter form cannot carve up a longer one and leave a recognisable fragment behind.
- TLS 1.2+ is enforced by default (.NET 10)
- Jenkins controller URL requires an explicit port (a URL with no port is rejected); a non-HTTPS URL is allowed but warned at startup because the agent secret would be sent unencrypted
- TCP connectivity is verified before each agent launch
- Deterministic builds with locked NuGet restore (
packages.lock.json) - Embedded PDB symbols (no separate symbol files to tamper with)
- SHA256 checksums published for all release artifacts
- Single-file self-contained deployment (no external DLLs to substitute)
Six security scans run on every push and pull request (Dependency Review is a pull-request gate only), each also on a weekly schedule:
| Scanner | What it checks |
|---|---|
| CodeQL | Static application security testing (SAST) for C# and GitHub Actions workflow YAML |
| Semgrep | Pattern-based SAST and secret detection |
| Gitleaks | Git history scanning for leaked secrets |
| PSScriptAnalyzer | PowerShell script security rules |
| Dependency Review | CVE gate on pull requests (blocks known-vulnerable dependencies) |
| Trivy | Software composition analysis (NVD, GHSA, OSV databases) |
JenkinsAsService depends on third-party NuGet packages. We monitor these via:
- Dependabot — automated pull requests for version updates
- Dependency Review — blocks PRs that introduce known CVEs
- Trivy SCA — scans resolved dependencies against multiple vulnerability databases
If you discover a vulnerability in a dependency, please report it to the package maintainer. If the vulnerability is exploitable through JenkinsAsService specifically, report it to us as well.
This is a personal open-source project. All work is done on a volunteer basis. We are unable to offer monetary bounties for security reports. We do offer public credit in the advisory if desired.