11package com .hubspot .jinjava .el .ext ;
22
3+ import com .fasterxml .jackson .databind .ObjectMapper ;
34import com .google .common .base .CaseFormat ;
45import com .google .common .collect .ImmutableSet ;
56import com .hubspot .jinjava .interpret .DeferredValueException ;
@@ -26,6 +27,11 @@ public class JinjavaBeanELResolver extends BeanELResolver {
2627 .add ("class" )
2728 .build ();
2829
30+ // These aren't required, but they prevent someone from misconfiguring Jinjava to allow sandbox bypass unintentionally
31+ private static final String JAVA_LANG_REFLECT_PACKAGE =
32+ Method .class .getPackage ().getName (); // java.lang.reflect
33+ private static final String JACKSON_DATABIND_PACKAGE =
34+ ObjectMapper .class .getPackage ().getName (); // com.fasterxml.jackson.databind
2935 private static final Set <String > DEFAULT_RESTRICTED_METHODS = ImmutableSet
3036 .<String >builder ()
3137 .add ("class" )
@@ -64,13 +70,46 @@ public class JinjavaBeanELResolver extends BeanELResolver {
6470
6571 @ Value .Immutable (singleton = true )
6672 public interface JinjavaBeanELResolverConfig {
67- ImmutableSet <Method > allowListedMethods ();
73+ ImmutableSet <Method > allowMethods ();
74+ ImmutableSet <Class <?>> allowDeclaredMethodsFromClasses ();
6875
6976 @ Value .Default
7077 default boolean readOnly () {
7178 return false ;
7279 }
7380
81+ @ Value .Check
82+ default void banClassesAndMethods () {
83+ if (
84+ allowMethods ()
85+ .stream ()
86+ .anyMatch (method ->
87+ Class .class .equals (method .getDeclaringClass ()) ||
88+ Object .class .equals (method .getDeclaringClass ()) ||
89+ method .getDeclaringClass ().getName ().startsWith (JAVA_LANG_REFLECT_PACKAGE ) ||
90+ method .getDeclaringClass ().getName ().startsWith (JACKSON_DATABIND_PACKAGE )
91+ )
92+ ) {
93+ throw new IllegalStateException (
94+ "Methods from banned classes (Object.class, Class.class) are not allowed"
95+ );
96+ }
97+ if (
98+ allowDeclaredMethodsFromClasses ()
99+ .stream ()
100+ .anyMatch (clazz ->
101+ Class .class .equals (clazz ) ||
102+ Object .class .equals (clazz ) ||
103+ clazz .getName ().startsWith (JAVA_LANG_REFLECT_PACKAGE ) ||
104+ clazz .getName ().startsWith (JACKSON_DATABIND_PACKAGE )
105+ )
106+ ) {
107+ throw new IllegalStateException (
108+ "Banned classes (Object.class, Class.class) are not allowed"
109+ );
110+ }
111+ }
112+
74113 static JinjavaBeanELResolverConfig .Builder builder () {
75114 return new Builder ();
76115 }
@@ -182,7 +221,10 @@ protected Method findMethod(
182221 List <Method > potentialMethods = new LinkedList <>();
183222
184223 for (Method m : methods ) {
185- if (m .getName ().equals (name )) {
224+ if (
225+ m .getName ().equals (name ) &&
226+ (isDeclaringClassAllowed (m .getDeclaringClass ()) || methodAllowed (m ))
227+ ) {
186228 int formalParamCount = m .getParameterTypes ().length ;
187229 if (m .isVarArgs () && paramCount >= formalParamCount - 1 ) {
188230 varArgsMethod = m ;
@@ -208,10 +250,17 @@ protected Method findMethod(
208250 )
209251 );
210252 }
211- if (true || jinjavaBeanELResolverConfig .allowListedMethods ().contains (method )) {
212- return method ;
213- }
214- return null ;
253+ return method ;
254+ }
255+
256+ private boolean methodAllowed (Method m ) {
257+ return jinjavaBeanELResolverConfig .allowMethods ().contains (m );
258+ }
259+
260+ private boolean isDeclaringClassAllowed (Class <?> declaringClass ) {
261+ return jinjavaBeanELResolverConfig
262+ .allowDeclaredMethodsFromClasses ()
263+ .contains (declaringClass );
215264 }
216265
217266 private static boolean checkAssignableParameterTypes (Object [] params , Method method ) {
0 commit comments