From 89e39a307153d168ec25070b05377ffd629b82e5 Mon Sep 17 00:00:00 2001 From: Rodrigo Navarro Date: Fri, 28 Aug 2026 15:30:56 -0400 Subject: [PATCH 1/2] RUN-4693: Document job option injection controls Document the opt-in option-value allowlist and the undeclared-option reject controls added under RUN-4693: - config-file-reference.md: new "Job Option Injection Controls" section under Security, covering rundeck.option.input.validation.default.pattern (system), project.option.input.validation.default.pattern (project), and rundeck.execution.rejectUndeclaredOptions, with precedence, a recommended starting pattern, and caveats (full-match, multi-line, fail-closed). - job-options.md: new "Restricting option input" section summarizing the three controls and linking to the full property reference. Co-Authored-By: Claude Opus 4.8 --- .../configuration/config-file-reference.md | 35 +++++++++++++++++++ docs/manual/jobs/job-options.md | 10 ++++++ 2 files changed, 45 insertions(+) diff --git a/docs/administration/configuration/config-file-reference.md b/docs/administration/configuration/config-file-reference.md index 6010c2a9e..856898e99 100644 --- a/docs/administration/configuration/config-file-reference.md +++ b/docs/administration/configuration/config-file-reference.md @@ -602,6 +602,41 @@ Enables dynamic conditional execution in workflows based on runtime conditions. **See also:** [User Management Guide](/manual/user-management/user-mgmt.md#manage-local-users) +#### Job Option Injection Controls + +Job option **values** are user input. When referenced in commands and scripts (`${option.name}`, `@option.name@`) they can carry shell metacharacters. Rundeck escapes option values used in the standard command/exec path, but these two opt-in controls validate or reject option input *before* an execution runs. They are defense-in-depth on top of — not a replacement for — the per-option **Match Regular Expression** and **Enforced** allowed-values restrictions described in [Job Options](/manual/jobs/job-options.md). + +**Default option-value allowlist** + +An allowlist regular expression applied to every option value that does not already define its own validation regex or enforced value list. When set, each such value must **fully match** the pattern or the execution is rejected before it runs. + +| Property | Scope | Default | Description | +|----------|-------|---------|-------------| +| `rundeck.option.input.validation.default.pattern` | System (`rundeck-config.properties` or System Configuration UI, category Execution) | (none) | Allowlist regex applied to option values instance-wide unless overridden per project. | +| `project.option.input.validation.default.pattern` | Project (project configuration) | (none) | Per-project override. Takes precedence over the system value. | + +Precedence for a given option value: a per-option regex or enforced allowed-values list wins; otherwise the project pattern; otherwise the system pattern. Leave both unset to disable the control (the default). File-reference (`file` type) option values are exempt, because they are validated separately. + +A good general-purpose starting pattern that allows upper- and lower-case letters, digits, and spaces is `[A-Za-z0-9 ]+`. Widen it as your option values require. + +When writing a pattern, note: + +- Matching is a **full match** (anchored): `[A-Za-z0-9_-]+` accepts `abc-1` but rejects `abc 1`. +- To allow multi-line values, the pattern must match newlines — prefix with the DOTALL flag, for example `(?s).*`. A bare `.*` rejects any value containing a line break. +- If the configured pattern is **not a valid regular expression**, Rundeck fails closed: affected executions are rejected and an error is logged, rather than silently running without validation. + +::: warning +This control is opt-in. With no pattern configured (the default), option values are not restricted by it. +::: + +**Reject undeclared options** + +| Property | Default | Description | +|----------|---------|-------------| +| `rundeck.execution.rejectUndeclaredOptions` | `true` | When enabled, an execution that provides an option not defined on the job is created and then failed at start, with a message in the execution log. | + +Options not declared on a job would otherwise bypass all server-side option validation yet still reach the option data context and `RD_OPTION_*` environment variables. With this control enabled (the default), such executions are rejected before any workflow step runs. Disable it only if you must allow undeclared options to pass through — for example, re-running a job whose option set has since changed. Disabling it weakens protection against option injection, and Rundeck logs a security warning at startup when it is set to `false`. Scope: top-level executions (UI, API, webhook, and scheduled). + ### Security HTTP Headers **Purpose:** Add security headers to HTTP responses to protect against common web vulnerabilities. diff --git a/docs/manual/jobs/job-options.md b/docs/manual/jobs/job-options.md index 00741180e..c16e4ae2d 100644 --- a/docs/manual/jobs/job-options.md +++ b/docs/manual/jobs/job-options.md @@ -429,6 +429,16 @@ Using non-escaped values can expose the environment to security risks like Comma > You can limit the risk by adopting appropriate regex masks, coding the script > defensively, and using the least privilege principle. +## Restricting option input + +Because option values are user input, a value containing shell metacharacters can be a command-injection risk when used in commands or scripts (see [Escaped values](#escaped-values) above). Beyond escaping, you can restrict which values are accepted: + +- **Per option** — set a **Match Regular Expression** or an **Enforced** allowed-values list on the option (see the option Restrictions described in [Defining an option](#defining-an-option) above). These constrain that single option. +- **Project- or system-wide default allowlist** — configure a default regular expression applied to every option value that does not already have its own regex or enforced list. Set `project.option.input.validation.default.pattern` for a project, or `rundeck.option.input.validation.default.pattern` instance-wide. A value that does not fully match the pattern causes the execution to be rejected before it runs. +- **Reject undeclared options** — by default (`rundeck.execution.rejectUndeclaredOptions=true`), an execution that supplies an option the job does not declare is rejected, so unvalidated values cannot reach scripts or `RD_OPTION_*` environment variables. + +See [Job Option Injection Controls](/administration/configuration/config-file-reference.md#job-option-injection-controls) for the full property reference, precedence rules, and pattern caveats (full-match behavior, multi-line matching, international characters, and fail-closed handling of an invalid pattern). + ## Secure Options Options can be marked as Secure, to show a password prompt in the GUI, instead of a normal text field or drop down menu. Secure option values are not stored with the Execution as are the other option values. From cf3ff406154a5899bcea4c9eb07dc442862fb108 Mon Sep 17 00:00:00 2001 From: Rodrigo Navarro <50217398+ronaveva@users.noreply.github.com> Date: Fri, 28 Aug 2026 15:39:27 -0400 Subject: [PATCH 2/2] GH suggestion Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- docs/administration/configuration/config-file-reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/administration/configuration/config-file-reference.md b/docs/administration/configuration/config-file-reference.md index 856898e99..1fc8a9e47 100644 --- a/docs/administration/configuration/config-file-reference.md +++ b/docs/administration/configuration/config-file-reference.md @@ -604,7 +604,7 @@ Enables dynamic conditional execution in workflows based on runtime conditions. #### Job Option Injection Controls -Job option **values** are user input. When referenced in commands and scripts (`${option.name}`, `@option.name@`) they can carry shell metacharacters. Rundeck escapes option values used in the standard command/exec path, but these two opt-in controls validate or reject option input *before* an execution runs. They are defense-in-depth on top of — not a replacement for — the per-option **Match Regular Expression** and **Enforced** allowed-values restrictions described in [Job Options](/manual/jobs/job-options.md). +Job option **values** are user input. When referenced in commands and scripts (`${option.name}`, `@option.name@`) they can carry shell metacharacters. Rundeck escapes option values used in the standard command/exec path, but these controls validate or reject option input *before* an execution runs. They are defense-in-depth on top of — not a replacement for — the per-option **Match Regular Expression** and **Enforced** allowed-values restrictions described in [Job Options](/manual/jobs/job-options.md). **Default option-value allowlist**