From aac87cc7ad9e6569d23f0da6651e0246d2ee9a48 Mon Sep 17 00:00:00 2001 From: ai-anant Date: Sat, 15 Aug 2026 01:36:35 +0000 Subject: [PATCH] feat(java): detect setAccessible(true) reflective access on non-local members (CWE-284) --- .../reflection/setaccessible-true.yaml | 35 +++++++++++++++++++ .../java/reflection-setaccessible-neg.java | 11 ++++++ .../java/reflection-setaccessible-pos.java | 10 ++++++ 3 files changed, 56 insertions(+) create mode 100644 java/jenkins/reflection/setaccessible-true.yaml create mode 100644 testcases/java/reflection-setaccessible-neg.java create mode 100644 testcases/java/reflection-setaccessible-pos.java diff --git a/java/jenkins/reflection/setaccessible-true.yaml b/java/jenkins/reflection/setaccessible-true.yaml new file mode 100644 index 0000000..e14b8a7 --- /dev/null +++ b/java/jenkins/reflection/setaccessible-true.yaml @@ -0,0 +1,35 @@ +rules: + - id: codevigilant.java.jenkins.reflection.setaccessible.true + patterns: + - pattern-either: + - pattern: $X.setAccessible(true) + - pattern: | + $X.accessible = true + - pattern-not: $X.setAccessible(false) + message: | + Detected reflective access turned on via setAccessible(true) (or the + Groovy property-assignment form `accessible = true`) on a + Field/Method/Constructor obtained from a class. setAccessible(true) + suppresses the Java language access checks, letting plugin code reach + protected/private members of other classes. In Jenkins this is + typically used to reach into core internals, bypassing the + access-control and safety guardrails the framework places around + protected APIs (permission checks, async isolation, timeouts, + synchronization). It also breaks under the Java module system + (InaccessibleObjectException). Prefer the public API; if internals + are genuinely needed, use the supported extension points or + Restricted/NoExternalUse APIs instead of reflection. + metadata: + category: security + cwe: "CWE-284: Improper Access Control" + owasp: "A01:2021 - Broken Access Control" + technology: jenkins + confidence: MEDIUM + references: + - https://www.jenkins.io/doc/developer/security/ + - https://www.jenkins.io/doc/developer/extensions/ + source: independent security review + license: MIT + languages: [generic] + mode: search + severity: HIGH diff --git a/testcases/java/reflection-setaccessible-neg.java b/testcases/java/reflection-setaccessible-neg.java new file mode 100644 index 0000000..96bb611 --- /dev/null +++ b/testcases/java/reflection-setaccessible-neg.java @@ -0,0 +1,11 @@ +public class ReflectionNeg { + public void touch(Class c) throws Exception { + java.lang.reflect.Field f = c.getDeclaredField("record"); + f.setAccessible(false); // access checks stay on + java.lang.reflect.Method m = c.getDeclaredMethod("monitor", Object.class); + // goes through the public API instead of reflection + Object v = c.newInstance(); + m.setAccessible(false); + Object r = m.invoke(v, new Object()); + } +} diff --git a/testcases/java/reflection-setaccessible-pos.java b/testcases/java/reflection-setaccessible-pos.java new file mode 100644 index 0000000..db7c766 --- /dev/null +++ b/testcases/java/reflection-setaccessible-pos.java @@ -0,0 +1,10 @@ +public class ReflectionPos { + public void touch(Class c) throws Exception { + java.lang.reflect.Field f = c.getDeclaredField("record"); + f.setAccessible(true); + Object v = f.get(c.newInstance()); + java.lang.reflect.Method m = c.getDeclaredMethod("monitor", Object.class); + m.accessible = true; // groovy-style property assignment + Object r = m.invoke(v, new Object()); + } +}