diff --git a/pom.xml b/pom.xml
index 010439d5..3745a77a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,7 +75,7 @@
io.jenkins.tools.bom
bom-2.176.x
- 9
+ 16
import
pom
diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/DefaultStepContext.java b/src/main/java/org/jenkinsci/plugins/workflow/support/DefaultStepContext.java
index 4ccdbcc4..2b15f9c3 100644
--- a/src/main/java/org/jenkinsci/plugins/workflow/support/DefaultStepContext.java
+++ b/src/main/java/org/jenkinsci/plugins/workflow/support/DefaultStepContext.java
@@ -31,11 +31,18 @@
import hudson.model.Computer;
import hudson.model.Job;
import hudson.model.Node;
+import hudson.model.ParameterValue;
+import hudson.model.ParametersAction;
+import hudson.model.PasswordParameterValue;
import hudson.model.Run;
import hudson.model.TaskListener;
import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.jenkinsci.plugins.workflow.flow.FlowExecution;
@@ -77,6 +84,9 @@ public abstract class DefaultStepContext extends StepContext {
return value;
} else if (key == TaskListener.class) {
return key.cast(getListener(false));
+ } else if (key == EnvironmentExpander.class) {
+ // Only called when `value == null` so that it does not override expanders contributed by steps.
+ return key.cast(new PasswordParameterEnvironmentExpander(get(Run.class)));
} else if (Node.class.isAssignableFrom(key)) {
Computer c = get(Computer.class);
Node n = null;
@@ -172,4 +182,35 @@ private T castOrNull(Class key, Object o) {
*/
protected abstract @Nonnull FlowNode getNode() throws IOException;
+ /**
+ * Default implementation of {@link EnvironmentExpander} that recognizes password parameters as sensitive variables.
+ */
+ private static class PasswordParameterEnvironmentExpander extends EnvironmentExpander {
+ private static final long serialVersionUID = 1L;
+
+ private final Set passwordParameterVariables;
+
+ public PasswordParameterEnvironmentExpander(Run, ?> run) {
+ ParametersAction action = run.getAction(ParametersAction.class);
+ if (action != null) {
+ passwordParameterVariables = action.getParameters().stream()
+ .filter(PasswordParameterValue.class::isInstance)
+ .map(ParameterValue::getName)
+ .collect(Collectors.toCollection(() -> new HashSet<>())); // Make sure the set is serializable.
+ } else {
+ passwordParameterVariables = Collections.emptySet();
+ }
+ }
+
+ @Override
+ public void expand(EnvVars ev) {
+ // Do nothing.
+ }
+
+ @Override
+ public Set getSensitiveVariables() {
+ return passwordParameterVariables;
+ }
+ }
+
}