Skip to content

Commit 3b35d10

Browse files
Fix: Harden FreeMarker against SSTI (#705)
* fix: SSTI freemarker * fix: Harden FreeMarker SSTI
1 parent 4841df5 commit 3b35d10

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

template/fr.opensagres.xdocreport.template.freemarker/src/main/java/fr/opensagres/xdocreport/template/freemarker/FreemarkerTemplateEngine.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,21 @@ public void setFreemarkerConfiguration( Configuration freemarkerConfiguration )
197197
{
198198
}
199199
this.freemarkerConfiguration.setLocalizedLookup( false );
200+
201+
// Security fix: Block dangerous class instantiation via ?new operator to prevent SSTI attacks
202+
//
203+
// This setting prevents Server-Side Template Injection (SSTI) attacks where malicious users
204+
// By setting NEW_BUILTIN_CLASS_RESOLVER_KEY to "safer", FreeMarker will block instantiation
205+
// of dangerous classes while still allowing legitimate template operations.
206+
try
207+
{
208+
this.freemarkerConfiguration.setSetting( Configuration.NEW_BUILTIN_CLASS_RESOLVER_KEY, "safer" );
209+
}
210+
catch ( Exception e )
211+
{
212+
// Ignore configuration errors to maintain compatibility with older FreeMarker versions
213+
// that might not support this security setting
214+
}
200215
}
201216

202217
public void extractFields( Reader reader, String entryName, FieldsExtractor extractor )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package fr.opensagres.xdocreport.template.freemarker;
2+
3+
import java.io.Reader;
4+
import java.io.StringReader;
5+
import java.io.StringWriter;
6+
import java.io.Writer;
7+
8+
import junit.framework.TestCase;
9+
import fr.opensagres.xdocreport.core.XDocReportException;
10+
import fr.opensagres.xdocreport.template.IContext;
11+
import freemarker.template.Configuration;
12+
import freemarker.template.TemplateException;
13+
14+
/**
15+
* Test case to verify security fixes for Server-Side Template Injection (SSTI) vulnerabilities
16+
* in the FreeMarker template engine.
17+
*/
18+
public class FreemarkerTemplateEngineSecurityTestCase
19+
extends TestCase
20+
{
21+
22+
/**
23+
* Test that legitimate template operations still work after security fix.
24+
*/
25+
public void testLegitimateTemplateOperationsStillWork()
26+
throws Exception
27+
{
28+
FreemarkerTemplateEngine templateEngine = new FreemarkerTemplateEngine();
29+
30+
// Test basic variable substitution
31+
String legitimateTemplate = "Hello ${name}!";
32+
Reader reader = new StringReader( legitimateTemplate );
33+
Writer writer = new StringWriter();
34+
IContext context = templateEngine.createContext();
35+
context.put( "name", "World" );
36+
37+
templateEngine.process( "", context, reader, writer );
38+
assertEquals( "Hello World!", writer.toString() );
39+
}
40+
41+
42+
/**
43+
* Test protection against SSTI payload with freemarker.template.utility.Execute.
44+
*/
45+
public void testSSTIProtectionAgainstExecutePayload()
46+
throws Exception
47+
{
48+
FreemarkerTemplateEngine templateEngine = new FreemarkerTemplateEngine();
49+
50+
String maliciousTemplate ="${\"freemarker.template.utility.Execute\"?new()(\"whoami\")}";
51+
Reader reader = new StringReader( maliciousTemplate );
52+
Writer writer = new StringWriter();
53+
IContext context = templateEngine.createContext();
54+
55+
try
56+
{
57+
templateEngine.process( "", context, reader, writer );
58+
fail( "Security fix failed: Execute payload should be blocked" );
59+
}
60+
catch ( XDocReportException e )
61+
{
62+
assertTrue( "Expected security-related exception",
63+
e.getCause() instanceof TemplateException );
64+
}
65+
}
66+
}
67+

0 commit comments

Comments
 (0)