CVE-2022-46166: Improper Control of Generation of Code ('Code Injection') (CWE-94)
value: Spring boot admins is an open source administrative user interface for management of spring boot applications. All users who run Spring Boot Admin Server, having enabled Notifiers (e.g. Teams-Notifier) and write access to environment variables via UI are affected. Users are advised to upgrade to the most recent releases of Spring Boot Admin 2.6.10 and 2.7.8 to resolve this issue. Users unable to upgrade may disable any notifier or disable write access (POST request) on `/env` actuator endpoint.


CWE description: The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
CVSS v3 base score: 9.8
Published: 2022-12-09T21:15Z
Repository: https://github.com/codecentric/spring-boot-admin
Language: Java
Files changed: spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/DingTalkNotifier.java, spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/DiscordNotifier.java, spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/HipchatNotifier.java, spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/LetsChatNotifier.java, spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/MicrosoftTeamsNotifier.java, spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/OpsGenieNotifier.java, spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/PagerdutyNotifier.java, spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/SlackNotifier.java, spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/TelegramNotifier.java
Commit date: 2022-12-02 08:28:01 +0100
Commit message: feat: improve notifiers

Diff: diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/DingTalkNotifier.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/DingTalkNotifier.java
index 8a3b56df..06223330 100644
--- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/DingTalkNotifier.java
+++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/DingTalkNotifier.java
@@ -15,10 +15,11 @@
  */
 
 package de.codecentric.boot.admin.server.notify;
 
 import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 
 import javax.annotation.Nullable;
 import javax.crypto.Mac;
@@ -27,11 +28,12 @@ import javax.crypto.spec.SecretKeySpec;
 import org.apache.commons.codec.binary.Base64;
 import org.springframework.context.expression.MapAccessor;
 import org.springframework.expression.Expression;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
+import org.springframework.expression.spel.support.SimpleEvaluationContext;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.web.client.RestTemplate;
 import reactor.core.publisher.Mono;
@@ -99,21 +101,22 @@ public class DingTalkNotifier extends AbstractStatusChangeNotifier {
 	private Object getText(InstanceEvent event, Instance instance) {
 		Map<String, Object> root = new HashMap<>();
 		root.put("event", event);
 		root.put("instance", instance);
 		root.put("lastStatus", getLastStatus(event.getInstance()));
-		StandardEvaluationContext context = new StandardEvaluationContext(root);
-		context.addPropertyAccessor(new MapAccessor());
+		SimpleEvaluationContext context = SimpleEvaluationContext
+				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
+				.withRootObject(root).build();
 		return message.getValue(context, String.class);
 	}
 
 	private String getSign(Long timestamp) {
 		try {
 			String stringToSign = timestamp + "\n" + secret;
 			Mac mac = Mac.getInstance("HmacSHA256");
-			mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
-			byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
+			mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
+			byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
 			return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
 		}
 		catch (Exception ex) {
 			ex.printStackTrace();
 		}
diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/DiscordNotifier.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/DiscordNotifier.java
index 224749d1..51b8ed41 100644
--- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/DiscordNotifier.java
+++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/DiscordNotifier.java
@@ -24,11 +24,12 @@ import javax.annotation.Nullable;
 
 import org.springframework.context.expression.MapAccessor;
 import org.springframework.expression.Expression;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
+import org.springframework.expression.spel.support.SimpleEvaluationContext;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.web.client.RestTemplate;
 import reactor.core.publisher.Mono;
@@ -115,12 +116,13 @@ public class DiscordNotifier extends AbstractStatusChangeNotifier {
 	protected String createContent(InstanceEvent event, Instance instance) {
 		Map<String, Object> root = new HashMap<>();
 		root.put("event", event);
 		root.put("instance", instance);
 		root.put("lastStatus", getLastStatus(event.getInstance()));
-		StandardEvaluationContext context = new StandardEvaluationContext(root);
-		context.addPropertyAccessor(new MapAccessor());
+		SimpleEvaluationContext context = SimpleEvaluationContext
+				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
+				.withRootObject(root).build();
 		return message.getValue(context, String.class);
 	}
 
 	@Nullable
 	public URI getWebhookUrl() {
diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/HipchatNotifier.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/HipchatNotifier.java
index bbacfa01..febe29c0 100644
--- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/HipchatNotifier.java
+++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/HipchatNotifier.java
@@ -24,11 +24,12 @@ import javax.annotation.Nullable;
 
 import org.springframework.context.expression.MapAccessor;
 import org.springframework.expression.Expression;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
+import org.springframework.expression.spel.support.SimpleEvaluationContext;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.web.client.RestTemplate;
 import reactor.core.publisher.Mono;
@@ -94,11 +95,11 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier {
 
 	protected String buildUrl() {
 		if (url == null) {
 			throw new IllegalStateException("'url' must not be null.");
 		}
-		return String.format("%s/room/%s/notification?auth_token=%s", url.toString(), roomId, authToken);
+		return String.format("%s/room/%s/notification?auth_token=%s", url, roomId, authToken);
 	}
 
 	protected HttpEntity<Map<String, Object>> createHipChatNotification(InstanceEvent event, Instance instance) {
 		Map<String, Object> body = new HashMap<>();
 		body.put("color", getColor(event));
@@ -119,12 +120,13 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier {
 	protected String getMessage(InstanceEvent event, Instance instance) {
 		Map<String, Object> root = new HashMap<>();
 		root.put("event", event);
 		root.put("instance", instance);
 		root.put("lastStatus", getLastStatus(event.getInstance()));
-		StandardEvaluationContext context = new StandardEvaluationContext(root);
-		context.addPropertyAccessor(new MapAccessor());
+		SimpleEvaluationContext context = SimpleEvaluationContext
+				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
+				.withRootObject(root).build();
 		return description.getValue(context, String.class);
 	}
 
 	protected String getColor(InstanceEvent event) {
 		if (event instanceof InstanceStatusChangedEvent) {
@@ -134,53 +136,53 @@ public class HipchatNotifier extends AbstractStatusChangeNotifier {
 		else {
 			return "gray";
 		}
 	}
 
-	public void setUrl(@Nullable URI url) {
-		this.url = url;
-	}
-
 	@Nullable
 	public URI getUrl() {
 		return url;
 	}
 
-	public void setAuthToken(@Nullable String authToken) {
-		this.authToken = authToken;
+	public void setUrl(@Nullable URI url) {
+		this.url = url;
 	}
 
 	@Nullable
 	public String getAuthToken() {
 		return authToken;
 	}
 
-	public void setRoomId(@Nullable String roomId) {
-		this.roomId = roomId;
+	public void setAuthToken(@Nullable String authToken) {
+		this.authToken = authToken;
 	}
 
 	@Nullable
 	public String getRoomId() {
 		return roomId;
 	}
 
-	public void setNotify(boolean notify) {
-		this.notify = notify;
+	public void setRoomId(@Nullable String roomId) {
+		this.roomId = roomId;
 	}
 
 	public boolean isNotify() {
 		return notify;
 	}
 
-	public void setDescription(String description) {
-		this.description = parser.parseExpression(description, ParserContext.TEMPLATE_EXPRESSION);
+	public void setNotify(boolean notify) {
+		this.notify = notify;
 	}
 
 	public String getDescription() {
 		return description.getExpressionString();
 	}
 
+	public void setDescription(String description) {
+		this.description = parser.parseExpression(description, ParserContext.TEMPLATE_EXPRESSION);
+	}
+
 	public void setRestTemplate(RestTemplate restTemplate) {
 		this.restTemplate = restTemplate;
 	}
 
 }
diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/LetsChatNotifier.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/LetsChatNotifier.java
index eb126b23..0733c82b 100644
--- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/LetsChatNotifier.java
+++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/LetsChatNotifier.java
@@ -25,11 +25,12 @@ import javax.annotation.Nullable;
 
 import org.springframework.context.expression.MapAccessor;
 import org.springframework.expression.Expression;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
+import org.springframework.expression.spel.support.SimpleEvaluationContext;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.MediaType;
 import org.springframework.util.Base64Utils;
@@ -117,58 +118,59 @@ public class LetsChatNotifier extends AbstractStatusChangeNotifier {
 	protected String getText(InstanceEvent event, Instance instance) {
 		Map<String, Object> root = new HashMap<>();
 		root.put("event", event);
 		root.put("instance", instance);
 		root.put("lastStatus", getLastStatus(event.getInstance()));
-		StandardEvaluationContext context = new StandardEvaluationContext(root);
-		context.addPropertyAccessor(new MapAccessor());
+		SimpleEvaluationContext context = SimpleEvaluationContext
+				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
+				.withRootObject(root).build();
 		return message.getValue(context, String.class);
 	}
 
 	public void setRestTemplate(RestTemplate restTemplate) {
 		this.restTemplate = restTemplate;
 	}
 
-	public void setUrl(@Nullable URI url) {
-		this.url = url;
-	}
-
 	@Nullable
 	public URI getUrl() {
 		return url;
 	}
 
-	public void setUsername(String username) {
-		this.username = username;
+	public void setUrl(@Nullable URI url) {
+		this.url = url;
 	}
 
 	public String getUsername() {
 		return username;
 	}
 
-	public void setRoom(@Nullable String room) {
-		this.room = room;
+	public void setUsername(String username) {
+		this.username = username;
 	}
 
 	@Nullable
 	public String getRoom() {
 		return room;
 	}
 
-	public void setToken(@Nullable String token) {
-		this.token = token;
+	public void setRoom(@Nullable String room) {
+		this.room = room;
 	}
 
 	@Nullable
 	public String getToken() {
 		return token;
 	}
 
-	public void setMessage(String message) {
-		this.message = parser.parseExpression(message, ParserContext.TEMPLATE_EXPRESSION);
+	public void setToken(@Nullable String token) {
+		this.token = token;
 	}
 
 	public String getMessage() {
 		return message.getExpressionString();
 	}
 
+	public void setMessage(String message) {
+		this.message = parser.parseExpression(message, ParserContext.TEMPLATE_EXPRESSION);
+	}
+
 }
diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/MicrosoftTeamsNotifier.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/MicrosoftTeamsNotifier.java
index 09edea79..8332f50a 100644
--- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/MicrosoftTeamsNotifier.java
+++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/MicrosoftTeamsNotifier.java
@@ -28,14 +28,16 @@ import javax.annotation.Nullable;
 import lombok.Builder;
 import lombok.Data;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.context.expression.MapAccessor;
+import org.springframework.expression.EvaluationContext;
 import org.springframework.expression.Expression;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
+import org.springframework.expression.spel.support.SimpleEvaluationContext;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.web.client.RestTemplate;
 import reactor.core.publisher.Mono;
@@ -139,11 +141,11 @@ public class MicrosoftTeamsNotifier extends AbstractStatusChangeNotifier {
 	}
 
 	@Override
 	protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
 		Message message;
-		StandardEvaluationContext context = createEvaluationContext(event, instance);
+		EvaluationContext context = createEvaluationContext(event, instance);
 		if (event instanceof InstanceRegisteredEvent) {
 			message = getRegisteredMessage(instance, context);
 		}
 		else if (event instanceof InstanceDeregisteredEvent) {
 			message = getDeregisteredMessage(instance, context);
@@ -170,27 +172,27 @@ public class MicrosoftTeamsNotifier extends AbstractStatusChangeNotifier {
 	protected boolean shouldNotify(InstanceEvent event, Instance instance) {
 		return event instanceof InstanceRegisteredEvent || event instanceof InstanceDeregisteredEvent
 				|| super.shouldNotify(event, instance);
 	}
 
-	protected Message getDeregisteredMessage(Instance instance, StandardEvaluationContext context) {
+	protected Message getDeregisteredMessage(Instance instance, EvaluationContext context) {
 		String activitySubtitle = evaluateExpression(context, deregisterActivitySubtitle);
 		return createMessage(instance, deRegisteredTitle, activitySubtitle, context);
 	}
 
-	protected Message getRegisteredMessage(Instance instance, StandardEvaluationContext context) {
+	protected Message getRegisteredMessage(Instance instance, EvaluationContext context) {
 		String activitySubtitle = evaluateExpression(context, registerActivitySubtitle);
 		return createMessage(instance, registeredTitle, activitySubtitle, context);
 	}
 
-	protected Message getStatusChangedMessage(Instance instance, StandardEvaluationContext context) {
+	protected Message getStatusChangedMessage(Instance instance, EvaluationContext context) {
 		String activitySubtitle = evaluateExpression(context, statusActivitySubtitle);
 		return createMessage(instance, statusChangedTitle, activitySubtitle, context);
 	}
 
 	protected Message createMessage(Instance instance, String registeredTitle, String activitySubtitle,
-			StandardEvaluationContext context) {
+			EvaluationContext context) {
 		List<Fact> facts = new ArrayList<>();
 		facts.add(new Fact(STATUS_KEY, instance.getStatusInfo().getStatus()));
 		facts.add(new Fact(SERVICE_URL_KEY, instance.getRegistration().getServiceUrl()));
 		facts.add(new Fact(HEALTH_URL_KEY, instance.getRegistration().getHealthUrl()));
 		facts.add(new Fact(MANAGEMENT_URL_KEY, instance.getRegistration().getManagementUrl()));
@@ -201,22 +203,22 @@ public class MicrosoftTeamsNotifier extends AbstractStatusChangeNotifier {
 
 		return Message.builder().title(registeredTitle).summary(messageSummary)
 				.themeColor(evaluateExpression(context, themeColor)).sections(singletonList(section)).build();
 	}
 
-	protected String evaluateExpression(StandardEvaluationContext context, Expression expression) {
+	protected String evaluateExpression(EvaluationContext context, Expression expression) {
 		return Objects.requireNonNull(expression.getValue(context, String.class));
 	}
 
-	protected StandardEvaluationContext createEvaluationContext(InstanceEvent event, Instance instance) {
+	protected EvaluationContext createEvaluationContext(InstanceEvent event, Instance instance) {
 		Map<String, Object> root = new HashMap<>();
 		root.put("event", event);
 		root.put("instance", instance);
 		root.put("lastStatus", getLastStatus(event.getInstance()));
-		StandardEvaluationContext context = new StandardEvaluationContext(root);
-		context.addPropertyAccessor(new MapAccessor());
-		return context;
+		return SimpleEvaluationContext
+				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
+				.withRootObject(root).build();
 	}
 
 	@Nullable
 	public URI getWebhookUrl() {
 		return webhookUrl;
diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/OpsGenieNotifier.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/OpsGenieNotifier.java
index 7928e164..5c5a9171 100644
--- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/OpsGenieNotifier.java
+++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/OpsGenieNotifier.java
@@ -24,11 +24,12 @@ import javax.annotation.Nullable;
 
 import org.springframework.context.expression.MapAccessor;
 import org.springframework.expression.Expression;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
+import org.springframework.expression.spel.support.SimpleEvaluationContext;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.MediaType;
 import org.springframework.web.client.RestTemplate;
@@ -116,11 +117,11 @@ public class OpsGenieNotifier extends AbstractStatusChangeNotifier {
 	}
 
 	protected String buildUrl(InstanceEvent event, Instance instance) {
 		if ((event instanceof InstanceStatusChangedEvent)
 				&& (StatusInfo.STATUS_UP.equals(((InstanceStatusChangedEvent) event).getStatusInfo().getStatus()))) {
-			return String.format("%s/%s/close", url.toString(), generateAlias(instance));
+			return String.format("%s/%s/close", url, generateAlias(instance));
 		}
 		return url.toString();
 	}
 
 	protected HttpEntity<?> createRequest(InstanceEvent event, Instance instance) {
@@ -170,30 +171,31 @@ public class OpsGenieNotifier extends AbstractStatusChangeNotifier {
 	protected String getMessage(InstanceEvent event, Instance instance) {
 		Map<String, Object> root = new HashMap<>();
 		root.put("event", event);
 		root.put("instance", instance);
 		root.put("lastStatus", getLastStatus(event.getInstance()));
-		StandardEvaluationContext context = new StandardEvaluationContext(root);
-		context.addPropertyAccessor(new MapAccessor());
+		SimpleEvaluationContext context = SimpleEvaluationContext
+				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
+				.withRootObject(root).build();
 		return description.getValue(context, String.class);
 	}
 
 	protected String getDescription(InstanceEvent event, Instance instance) {
 		return String.format("Instance %s (%s) went from %s to %s", instance.getRegistration().getName(),
 				instance.getId(), getLastStatus(instance.getId()),
 				((InstanceStatusChangedEvent) event).getStatusInfo().getStatus());
 	}
 
-	public void setApiKey(@Nullable String apiKey) {
-		this.apiKey = apiKey;
-	}
-
 	@Nullable
 	public String getApiKey() {
 		return apiKey;
 	}
 
+	public void setApiKey(@Nullable String apiKey) {
+		this.apiKey = apiKey;
+	}
+
 	public void setDescription(String description) {
 		this.description = parser.parseExpression(description, ParserContext.TEMPLATE_EXPRESSION);
 	}
 
 	public String getMessage() {
diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/PagerdutyNotifier.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/PagerdutyNotifier.java
index b12b212a..4a36c8a0 100644
--- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/PagerdutyNotifier.java
+++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/PagerdutyNotifier.java
@@ -24,11 +24,12 @@ import javax.annotation.Nullable;
 
 import org.springframework.context.expression.MapAccessor;
 import org.springframework.expression.Expression;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
+import org.springframework.expression.spel.support.SimpleEvaluationContext;
 import org.springframework.web.client.RestTemplate;
 import reactor.core.publisher.Mono;
 
 import de.codecentric.boot.admin.server.domain.entities.Instance;
 import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
@@ -130,13 +131,13 @@ public class PagerdutyNotifier extends AbstractStatusChangeNotifier {
 	protected String getDescription(InstanceEvent event, Instance instance) {
 		Map<String, Object> root = new HashMap<>();
 		root.put("event", event);
 		root.put("instance", instance);
 		root.put("lastStatus", getLastStatus(event.getInstance()));
-		StandardEvaluationContext context = new StandardEvaluationContext(root);
-		context.addPropertyAccessor(new MapAccessor());
-
+		SimpleEvaluationContext context = SimpleEvaluationContext
+				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
+				.withRootObject(root).build();
 		return description.getValue(context, String.class);
 	}
 
 	protected Map<String, Object> getDetails(InstanceEvent event) {
 		Map<String, Object> details = new HashMap<>();
@@ -145,53 +146,53 @@ public class PagerdutyNotifier extends AbstractStatusChangeNotifier {
 			details.put("to", ((InstanceStatusChangedEvent) event).getStatusInfo());
 		}
 		return details;
 	}
 
-	public void setUrl(URI url) {
-		this.url = url;
-	}
-
 	public URI getUrl() {
 		return url;
 	}
 
-	public void setClient(@Nullable String client) {
-		this.client = client;
+	public void setUrl(URI url) {
+		this.url = url;
 	}
 
 	@Nullable
 	public String getClient() {
 		return client;
 	}
 
-	public void setClientUrl(@Nullable URI clientUrl) {
-		this.clientUrl = clientUrl;
+	public void setClient(@Nullable String client) {
+		this.client = client;
 	}
 
 	@Nullable
 	public URI getClientUrl() {
 		return clientUrl;
 	}
 
-	public void setServiceKey(@Nullable String serviceKey) {
-		this.serviceKey = serviceKey;
+	public void setClientUrl(@Nullable URI clientUrl) {
+		this.clientUrl = clientUrl;
 	}
 
 	@Nullable
 	public String getServiceKey() {
 		return serviceKey;
 	}
 
-	public void setDescription(String description) {
-		this.description = parser.parseExpression(description, ParserContext.TEMPLATE_EXPRESSION);
+	public void setServiceKey(@Nullable String serviceKey) {
+		this.serviceKey = serviceKey;
 	}
 
 	public String getDescription() {
 		return description.getExpressionString();
 	}
 
+	public void setDescription(String description) {
+		this.description = parser.parseExpression(description, ParserContext.TEMPLATE_EXPRESSION);
+	}
+
 	public void setRestTemplate(RestTemplate restTemplate) {
 		this.restTemplate = restTemplate;
 	}
 
 }
diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/SlackNotifier.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/SlackNotifier.java
index dec61383..d54c273f 100644
--- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/SlackNotifier.java
+++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/SlackNotifier.java
@@ -25,11 +25,12 @@ import javax.annotation.Nullable;
 
 import org.springframework.context.expression.MapAccessor;
 import org.springframework.expression.Expression;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
+import org.springframework.expression.spel.support.SimpleEvaluationContext;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.web.client.RestTemplate;
 import reactor.core.publisher.Mono;
@@ -126,12 +127,14 @@ public class SlackNotifier extends AbstractStatusChangeNotifier {
 	protected String getText(InstanceEvent event, Instance instance) {
 		Map<String, Object> root = new HashMap<>();
 		root.put("event", event);
 		root.put("instance", instance);
 		root.put("lastStatus", getLastStatus(event.getInstance()));
-		StandardEvaluationContext context = new StandardEvaluationContext(root);
-		context.addPropertyAccessor(new MapAccessor());
+		SimpleEvaluationContext context = SimpleEvaluationContext
+				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
+				.withRootObject(root).build();
+
 		return message.getValue(context, String.class);
 	}
 
 	protected String getColor(InstanceEvent event) {
 		if (event instanceof InstanceStatusChangedEvent) {
diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/TelegramNotifier.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/TelegramNotifier.java
index 1ba4edc5..8c7e3cb1 100644
--- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/TelegramNotifier.java
+++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/TelegramNotifier.java
@@ -23,11 +23,12 @@ import javax.annotation.Nullable;
 
 import org.springframework.context.expression.MapAccessor;
 import org.springframework.expression.Expression;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
+import org.springframework.expression.spel.support.SimpleEvaluationContext;
 import org.springframework.web.client.RestTemplate;
 import reactor.core.publisher.Mono;
 
 import de.codecentric.boot.admin.server.domain.entities.Instance;
 import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
@@ -105,12 +106,14 @@ public class TelegramNotifier extends AbstractStatusChangeNotifier {
 	protected String getText(InstanceEvent event, Instance instance) {
 		Map<String, Object> root = new HashMap<>();
 		root.put("event", event);
 		root.put("instance", instance);
 		root.put("lastStatus", getLastStatus(event.getInstance()));
-		StandardEvaluationContext context = new StandardEvaluationContext(root);
-		context.addPropertyAccessor(new MapAccessor());
+		SimpleEvaluationContext context = SimpleEvaluationContext
+				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
+				.withRootObject(root).build();
+
 		return message.getValue(context, String.class);
 	}
 
 	public void setRestTemplate(RestTemplate restTemplate) {
 		this.restTemplate = restTemplate;

Vulnerable code: import org.springframework.expression.spel.support.StandardEvaluationContext;
		StandardEvaluationContext context = new StandardEvaluationContext(root);
		context.addPropertyAccessor(new MapAccessor());
			mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
			byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
import org.springframework.expression.spel.support.StandardEvaluationContext;
		StandardEvaluationContext context = new StandardEvaluationContext(root);
		context.addPropertyAccessor(new MapAccessor());
import org.springframework.expression.spel.support.StandardEvaluationContext;
		return String.format("%s/room/%s/notification?auth_token=%s", url.toString(), roomId, authToken);
		StandardEvaluationContext context = new StandardEvaluationContext(root);
		context.addPropertyAccessor(new MapAccessor());
	public void setUrl(@Nullable URI url) {
		this.url = url;
	}

	public void setAuthToken(@Nullable String authToken) {
		this.authToken = authToken;
	public void setRoomId(@Nullable String roomId) {
		this.roomId = roomId;
	public void setNotify(boolean notify) {
		this.notify = notify;
	public void setDescription(String description) {
		this.description = parser.parseExpression(description, ParserContext.TEMPLATE_EXPRESSION);
import org.springframework.expression.spel.support.StandardEvaluationContext;
		StandardEvaluationContext context = new StandardEvaluationContext(root);
		context.addPropertyAccessor(new MapAccessor());
	public void setUrl(@Nullable URI url) {
		this.url = url;
	}

	public void setUsername(String username) {
		this.username = username;
	public void setRoom(@Nullable String room) {
		this.room = room;
	public void setToken(@Nullable String token) {
		this.token = token;
	public void setMessage(String message) {
		this.message = parser.parseExpression(message, ParserContext.TEMPLATE_EXPRESSION);
import org.springframework.expression.spel.support.StandardEvaluationContext;
		StandardEvaluationContext context = createEvaluationContext(event, instance);
	protected Message getDeregisteredMessage(Instance instance, StandardEvaluationContext context) {
	protected Message getRegisteredMessage(Instance instance, StandardEvaluationContext context) {
	protected Message getStatusChangedMessage(Instance instance, StandardEvaluationContext context) {
			StandardEvaluationContext context) {
	protected String evaluateExpression(StandardEvaluationContext context, Expression expression) {
	protected StandardEvaluationContext createEvaluationContext(InstanceEvent event, Instance instance) {
		StandardEvaluationContext context = new StandardEvaluationContext(root);
		context.addPropertyAccessor(new MapAccessor());
		return context;
import org.springframework.expression.spel.support.StandardEvaluationContext;
			return String.format("%s/%s/close", url.toString(), generateAlias(instance));
		StandardEvaluationContext context = new StandardEvaluationContext(root);
		context.addPropertyAccessor(new MapAccessor());
	public void setApiKey(@Nullable String apiKey) {
		this.apiKey = apiKey;
	}

import org.springframework.expression.spel.support.StandardEvaluationContext;
		StandardEvaluationContext context = new StandardEvaluationContext(root);
		context.addPropertyAccessor(new MapAccessor());

	public void setUrl(URI url) {
		this.url = url;
	}

	public void setClient(@Nullable String client) {
		this.client = client;
	public void setClientUrl(@Nullable URI clientUrl) {
		this.clientUrl = clientUrl;
	public void setServiceKey(@Nullable String serviceKey) {
		this.serviceKey = serviceKey;
	public void setDescription(String description) {
		this.description = parser.parseExpression(description, ParserContext.TEMPLATE_EXPRESSION);
import org.springframework.expression.spel.support.StandardEvaluationContext;
		StandardEvaluationContext context = new StandardEvaluationContext(root);
		context.addPropertyAccessor(new MapAccessor());
import org.springframework.expression.spel.support.StandardEvaluationContext;
		StandardEvaluationContext context = new StandardEvaluationContext(root);
		context.addPropertyAccessor(new MapAccessor());
Fixed code: import java.nio.charset.StandardCharsets;
import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
		SimpleEvaluationContext context = SimpleEvaluationContext
				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
				.withRootObject(root).build();
			mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
			byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
		SimpleEvaluationContext context = SimpleEvaluationContext
				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
				.withRootObject(root).build();
import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
		return String.format("%s/room/%s/notification?auth_token=%s", url, roomId, authToken);
		SimpleEvaluationContext context = SimpleEvaluationContext
				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
				.withRootObject(root).build();
	public void setUrl(@Nullable URI url) {
		this.url = url;
	public void setAuthToken(@Nullable String authToken) {
		this.authToken = authToken;
	public void setRoomId(@Nullable String roomId) {
		this.roomId = roomId;
	public void setNotify(boolean notify) {
		this.notify = notify;
	public void setDescription(String description) {
		this.description = parser.parseExpression(description, ParserContext.TEMPLATE_EXPRESSION);
	}

import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
		SimpleEvaluationContext context = SimpleEvaluationContext
				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
				.withRootObject(root).build();
	public void setUrl(@Nullable URI url) {
		this.url = url;
	public void setUsername(String username) {
		this.username = username;
	public void setRoom(@Nullable String room) {
		this.room = room;
	public void setToken(@Nullable String token) {
		this.token = token;
	public void setMessage(String message) {
		this.message = parser.parseExpression(message, ParserContext.TEMPLATE_EXPRESSION);
	}

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
		EvaluationContext context = createEvaluationContext(event, instance);
	protected Message getDeregisteredMessage(Instance instance, EvaluationContext context) {
	protected Message getRegisteredMessage(Instance instance, EvaluationContext context) {
	protected Message getStatusChangedMessage(Instance instance, EvaluationContext context) {
			EvaluationContext context) {
	protected String evaluateExpression(EvaluationContext context, Expression expression) {
	protected EvaluationContext createEvaluationContext(InstanceEvent event, Instance instance) {
		return SimpleEvaluationContext
				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
				.withRootObject(root).build();
import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
			return String.format("%s/%s/close", url, generateAlias(instance));
		SimpleEvaluationContext context = SimpleEvaluationContext
				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
				.withRootObject(root).build();
	public void setApiKey(@Nullable String apiKey) {
		this.apiKey = apiKey;
	}

import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
		SimpleEvaluationContext context = SimpleEvaluationContext
				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
				.withRootObject(root).build();
	public void setUrl(URI url) {
		this.url = url;
	public void setClient(@Nullable String client) {
		this.client = client;
	public void setClientUrl(@Nullable URI clientUrl) {
		this.clientUrl = clientUrl;
	public void setServiceKey(@Nullable String serviceKey) {
		this.serviceKey = serviceKey;
	public void setDescription(String description) {
		this.description = parser.parseExpression(description, ParserContext.TEMPLATE_EXPRESSION);
	}

import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
		SimpleEvaluationContext context = SimpleEvaluationContext
				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
				.withRootObject(root).build();

import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
		SimpleEvaluationContext context = SimpleEvaluationContext
				.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess(), new MapAccessor())
				.withRootObject(root).build();