Skip to content

Commit d169a08

Browse files
authored
Merge commit from fork
Prevent JinjavaBeanELResolver restriction bypassing through ForTag's loopVars for 2.7.x version
2 parents 7f641c6 + 59d9f2d commit d169a08

5 files changed

Lines changed: 83 additions & 3 deletions

File tree

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# Jinjava Releases #
2+
### 2025-01-30 Version 2.7.6 ([Maven Central](https://search.maven.org/artifact/com.hubspot.jinjava/jinjava/2.7.6/jar)) ###
3+
* Disallow accessing properties on restricted classes while rendering through ForTag
4+
* Upgrade jackson to version 2.20
5+
### 2025-09-30 Version 2.7.5 ([Maven Central](https://search.maven.org/artifact/com.hubspot.jinjava/jinjava/2.7.5/jar)) ###
6+
* Disallow accessing properties on restricted classes while rendering
27
### 2024-12-06 Verision 2.7.4 ([Maven Central](https://search.maven.org/artifact/com.hubspot.jinjava/jinjava/2.7.4/jar)) ###
38
* [Implement jinja2.ext.loopcontrols extensions (break and continue)](https://github.com/HubSpot/jinjava/pull/1219)
49
* [Apply whitespace rules for LStrip and Trim to comment blocks](https://github.com/HubSpot/jinjava/pull/1217)

src/main/java/com/hubspot/jinjava/el/ext/JinjavaBeanELResolver.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.hubspot.jinjava.el.ext;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
34
import com.google.common.base.CaseFormat;
45
import com.google.common.collect.ImmutableSet;
56
import com.hubspot.jinjava.interpret.DeferredValueException;
@@ -36,6 +37,7 @@ public class JinjavaBeanELResolver extends BeanELResolver {
3637
.add("notify")
3738
.add("notifyAll")
3839
.add("wait")
40+
.add("readValueAs")
3941
.build();
4042

4143
private static final Set<String> DEFERRED_EXECUTION_RESTRICTED_METHODS = ImmutableSet
@@ -59,6 +61,10 @@ public class JinjavaBeanELResolver extends BeanELResolver {
5961
.add("set")
6062
.add("merge")
6163
.build();
64+
private static final String JAVA_LANG_REFLECT_PACKAGE =
65+
Method.class.getPackage().getName(); // java.lang.reflect
66+
private static final String JACKSON_DATABIND_PACKAGE =
67+
ObjectMapper.class.getPackage().getName(); // com.fasterxml.jackson.databind
6268

6369
/**
6470
* Creates a new read/write {@link JinjavaBeanELResolver}.
@@ -251,9 +257,11 @@ protected boolean isRestrictedClass(Object o) {
251257
return false;
252258
}
253259

260+
Package oPackage = o.getClass().getPackage();
254261
return (
255-
(o.getClass().getPackage() != null &&
256-
o.getClass().getPackage().getName().startsWith("java.lang.reflect")) ||
262+
(oPackage != null &&
263+
(oPackage.getName().startsWith(JAVA_LANG_REFLECT_PACKAGE) ||
264+
oPackage.getName().startsWith(JACKSON_DATABIND_PACKAGE))) ||
257265
o instanceof Class ||
258266
o instanceof ClassLoader ||
259267
o instanceof Thread ||

src/main/java/com/hubspot/jinjava/lib/tag/ForTag.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ public String renderForCollection(
248248
if (loopVar.equals(valProp.getName())) {
249249
interpreter
250250
.getContext()
251-
.put(loopVar, valProp.getReadMethod().invoke(val));
251+
.put(loopVar, interpreter.resolveProperty(val, valProp.getName()));
252252
break;
253253
}
254254
}

src/test/java/com/hubspot/jinjava/el/ext/JinjavaBeanELResolverTest.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
import static org.mockito.Mockito.mock;
66
import static org.mockito.Mockito.when;
77

8+
import com.fasterxml.jackson.databind.ObjectMapper;
89
import com.google.common.collect.ImmutableSet;
910
import com.hubspot.jinjava.JinjavaConfig;
1011
import com.hubspot.jinjava.el.JinjavaELContext;
1112
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
13+
import java.util.List;
1214
import javax.el.ELContext;
1315
import javax.el.MethodNotFoundException;
1416
import javax.el.PropertyNotFoundException;
@@ -184,4 +186,60 @@ public void itDoesNotAllowAccessingPropertiesOfInterpreter() {
184186
JinjavaInterpreter.popCurrent();
185187
}
186188
}
189+
190+
@Test
191+
public void itDoesNotGettingFromObjectMapper() {
192+
try (
193+
AutoCloseableSupplier.AutoCloseableImpl<JinjavaInterpreter> c = JinjavaInterpreter
194+
.closeablePushCurrent(interpreter)
195+
.get()
196+
) {
197+
assertThat(
198+
jinjavaBeanELResolver.getValue(elContext, new ObjectMapper(), "dateFormat")
199+
)
200+
.isNull();
201+
}
202+
}
203+
204+
@Test
205+
public void itDoesNotAllowInvokingFromObjectMapper() throws NoSuchMethodException {
206+
try (
207+
AutoCloseableSupplier.AutoCloseableImpl<JinjavaInterpreter> c = JinjavaInterpreter
208+
.closeablePushCurrent(interpreter)
209+
.get()
210+
) {
211+
ObjectMapper objectMapper = new ObjectMapper();
212+
assertThatThrownBy(() ->
213+
jinjavaBeanELResolver.invoke(
214+
elContext,
215+
objectMapper,
216+
"getDateFormat",
217+
new Class[] {},
218+
new Object[] {}
219+
)
220+
)
221+
.isInstanceOf(MethodNotFoundException.class);
222+
}
223+
}
224+
225+
@Test
226+
public void itDoesNotAllowInvokingFromMethod() throws NoSuchMethodException {
227+
try (
228+
AutoCloseableSupplier.AutoCloseableImpl<JinjavaInterpreter> c = JinjavaInterpreter
229+
.closeablePushCurrent(interpreter)
230+
.get()
231+
) {
232+
List<String> list = List.of("foo");
233+
assertThatThrownBy(() ->
234+
jinjavaBeanELResolver.invoke(
235+
elContext,
236+
list.getClass().getMethod("get", int.class),
237+
"invoke",
238+
new Class[] { Object.class, Object[].class },
239+
new Object[] { list, 0 }
240+
)
241+
)
242+
.isInstanceOf(MethodNotFoundException.class);
243+
}
244+
}
187245
}

src/test/java/com/hubspot/jinjava/lib/tag/ForTagTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,15 @@ public void forLoopTupleWithNullValues() {
406406
assertThat(result).isEqualTo(" -1 -1 null null null ");
407407
}
408408

409+
@Test
410+
public void itUsesJinjavaRestrictedResolverOnReadingLoopVars() {
411+
String template =
412+
"""
413+
{% for _, config, class in ____int3rpr3t3r____ %}{{ class }}{% endfor %}""";
414+
String result = interpreter.render(template);
415+
assertThat(result).isEqualTo("");
416+
}
417+
409418
public static boolean inForLoop() {
410419
JinjavaInterpreter interpreter = JinjavaInterpreter.getCurrent();
411420
return interpreter.getContext().isInForLoop();

0 commit comments

Comments
 (0)