diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java
index e291ba8d8aa..62dff6442d9 100644
--- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java
+++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java
@@ -2845,6 +2845,7 @@ private TestSnapshotListener setupInstrumentTheWorldTransformer(
return listener;
}
+ // TODO: JEP 500 - avoid mutating final fields
private void setCorrelationSingleton(Object instance) {
Class> singletonClass = CorrelationAccess.class.getDeclaredClasses()[0];
try {
diff --git a/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/Bug4304Instrumentation.java b/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/Bug4304Instrumentation.java
index b185117f882..dcfcfe207cb 100644
--- a/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/Bug4304Instrumentation.java
+++ b/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/Bug4304Instrumentation.java
@@ -16,13 +16,17 @@
import datadog.trace.api.gateway.RequestContext;
import datadog.trace.api.gateway.RequestContextSlot;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
+import de.thetaphi.forbiddenapis.SuppressForbidden;
import java.lang.reflect.Field;
import java.util.regex.Pattern;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
-/** See https://github.com/akka/akka-http/issues/4304 */
+/**
+ * See Duplicated 100 responses if there is
+ * an exception thrown by the unmarshaller
+ */
@AutoService(InstrumenterModule.class)
public class Bug4304Instrumentation extends InstrumenterModule.AppSec
implements Instrumenter.ForTypeHierarchy,
@@ -91,6 +95,11 @@ public void methodAdvice(MethodTransformer transformer) {
}
static class GraphStageLogicAdvice {
+ // Field::set() is forbidden because it may be used to mutate final fields, disallowed by
+ // https://openjdk.org/jeps/500.
+ // However, in this case the method is called on a non-final field, so it is safe. See
+ // https://github.com/akka/akka-http/blob/8fb19fce3548c3bfa1e8ebcb1115be29f342df69/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala#L588
+ @SuppressForbidden
@Advice.OnMethodExit(suppress = Throwable.class)
static void after(@Advice.This GraphStageLogic thiz)
throws NoSuchFieldException, IllegalAccessException {
diff --git a/dd-java-agent/instrumentation/weaver-0.9/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java b/dd-java-agent/instrumentation/weaver-0.9/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java
index f28a45f03c5..fe8e60e4fd2 100644
--- a/dd-java-agent/instrumentation/weaver-0.9/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java
+++ b/dd-java-agent/instrumentation/weaver-0.9/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java
@@ -5,6 +5,7 @@
import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.agent.tooling.InstrumenterModule;
+import de.thetaphi.forbiddenapis.SuppressForbidden;
import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
@@ -42,6 +43,8 @@ public void methodAdvice(MethodTransformer transformer) {
}
public static class SbtTaskCreationAdvice {
+ // TODO: JEP 500 - avoid mutating final fields
+ @SuppressForbidden
@Advice.OnMethodExit(suppress = Throwable.class)
public static void onTaskCreation(
@Advice.This Object sbtTask, @Advice.FieldValue("taskDef") TaskDef taskDef) {
diff --git a/gradle/forbiddenApiFilters/main.txt b/gradle/forbiddenApiFilters/main.txt
index db69659cb7a..334e0d79822 100644
--- a/gradle/forbiddenApiFilters/main.txt
+++ b/gradle/forbiddenApiFilters/main.txt
@@ -1,7 +1,7 @@
# loads and instantiates a class which may be inefficient depending on context
java.lang.Class#forName(java.lang.String)
-# String methods which uses regexes for matching
+# String methods which use regexes for matching
java.lang.String#split(java.lang.String)
java.lang.String#split(java.lang.String,int)
java.lang.String#replaceAll(java.lang.String,java.lang.String)
@@ -34,6 +34,19 @@ java.lang.System#err
java.lang.System#getenv()
java.lang.System#getenv(java.lang.String)
-#Use jdk LongAdder
+# use jdk LongAdder
@defaultMessage use LongAdder instead of the legacy jctools FixedSizeStripedLongCounter
org.jctools.counters.FixedSizeStripedLongCounter
+
+# avoid methods that mutate final fields, as this will soon be disallowed. For more details: https://openjdk.org/jeps/500.
+@defaultMessage Avoid mutating final fields (e.g. with methods such as Field::set and MethodHandles.Lookup::unreflectSetter). If the field is not final, override with @SuppressForbidden.
+java.lang.reflect.Field#set(java.lang.Object,java.lang.Object)
+java.lang.reflect.Field#setBoolean(java.lang.Object,boolean)
+java.lang.reflect.Field#setByte(java.lang.Object,byte)
+java.lang.reflect.Field#setChar(java.lang.Object,char)
+java.lang.reflect.Field#setShort(java.lang.Object,short)
+java.lang.reflect.Field#setInt(java.lang.Object,int)
+java.lang.reflect.Field#setLong(java.lang.Object,long)
+java.lang.reflect.Field#setFloat(java.lang.Object,float)
+java.lang.reflect.Field#setDouble(java.lang.Object,double)
+java.lang.invoke.MethodHandles.Lookup#unreflectSetter(java.lang.reflect.Field)
diff --git a/internal-api/src/main/java/datadog/trace/api/iast/InstrumentationBridge.java b/internal-api/src/main/java/datadog/trace/api/iast/InstrumentationBridge.java
index 7c5c9d1ae3f..835364fafcf 100644
--- a/internal-api/src/main/java/datadog/trace/api/iast/InstrumentationBridge.java
+++ b/internal-api/src/main/java/datadog/trace/api/iast/InstrumentationBridge.java
@@ -29,6 +29,7 @@
import datadog.trace.api.iast.sink.XContentTypeModule;
import datadog.trace.api.iast.sink.XPathInjectionModule;
import datadog.trace.api.iast.sink.XssModule;
+import de.thetaphi.forbiddenapis.SuppressForbidden;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
@@ -124,6 +125,10 @@ private static M get(final Field field) {
}
}
+ // Field::set() is forbidden because it may be used to mutate final fields, disallowed by
+ // https://openjdk.org/jeps/500.
+ // However, in this case the method is called on a non-final field, so it is safe.
+ @SuppressForbidden
private static void set(final Field field, final IastModule module) {
try {
field.set(null, module);
diff --git a/internal-api/src/main/java/datadog/trace/util/UnsafeUtils.java b/internal-api/src/main/java/datadog/trace/util/UnsafeUtils.java
index cc0830b68c8..06cd5f832a0 100644
--- a/internal-api/src/main/java/datadog/trace/util/UnsafeUtils.java
+++ b/internal-api/src/main/java/datadog/trace/util/UnsafeUtils.java
@@ -1,5 +1,6 @@
package datadog.trace.util;
+import de.thetaphi.forbiddenapis.SuppressForbidden;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.slf4j.Logger;
@@ -57,6 +58,8 @@ public static T tryShallowClone(T original) {
}
}
+ // TODO: JEP 500 - avoid mutating final fields
+ @SuppressForbidden
private static void cloneFields(Class> clazz, Object original, Object clone) throws Exception {
for (Field field : clazz.getDeclaredFields()) {
if ((field.getModifiers() & Modifier.STATIC) != 0) {