Skip to content

Conversation

@AT190510-Cuong
Copy link
Contributor

Summary

This pull request hardens the FreeMarker template rendering logic to prevent potential Server-Side Template Injection (SSTI) vulnerabilities.

Details

  • Added strict configuration for FreeMarker to disallow arbitrary expression evaluation.
  • Ensured only whitelisted template variables are accessible.
  • Added validation for user-controlled inputs before passing to template engine.

Impact

Prevents attackers from injecting malicious template expressions that could lead to arbitrary code execution.

References

@AT190510-Cuong
Copy link
Contributor Author

Hi @angelozerr, thanks for your reply.
This PR fixes a potential SSTI issue in FreeMarker.
Please review when you have time — I’ll be happy to update it if needed.

@@ -0,0 +1,146 @@
# XDocReport FreeMarker SSTI Security Fixes

## Tổng quan
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use english

@angelozerr
Copy link
Member

@AT190510-Cuong
Copy link
Contributor Author

Hi @angelorerr,
Sorry for the confusion earlier — I’ve now updated the original PR (#705) with the latest code from fix/ssti_new.
I’ve fixed the issue and really hope it works properly this time 😊
Thank you for your patience and for reviewing again!

@angelozerr
Copy link
Member

@AT190510-Cuong it is hard to follow your PR since code changes everytime.

I have no idea what your PR fixes now?

@AT190510-Cuong
Copy link
Contributor Author

@angelozerr Thank you for the feedback, and I apologize again for the confusion.
To clarify — this PR addresses a Server-Side Template Injection (SSTI) vulnerability in the FreeMarker template engine.

Issue:

  • The ?new operator in FreeMarker allows creating arbitrary Java objects.
  • Attackers could exploit this to execute system commands (e.g., Runtime.getRuntime().exec()).

Fix:

  • Added configuration NEW_BUILTIN_CLASS_RESOLVER_KEY = "safer".
  • This blocks access to dangerous classes like Runtime, ProcessBuilder, etc.
  • Regular template features remain unaffected.

Code Changes:

  • File: FreemarkerTemplateEngine.java
  • Lines: 201–209
  • Added ~8 lines of code (with a small try-catch for backward compatibility).

@angelozerr
Copy link
Member

@AT190510-Cuong I understand now what you are trying to do, but I don t think it is relevant for XDocReport project.

Indeed I dont see any usecase where a user will write a mergefield with freemarker operator. And even if a report contains this syntax it is the resposability of the application which uses XDocReport which must take care of that.

It is the same thing when you are writting a webapp application which uses freemarker to render html page.

I am sorry to not accept your PR. It is not relevant for XDocReport project.

@AT190510-Cuong
Copy link
Contributor Author

AT190510-Cuong commented Oct 23, 2025

Hi @angelozerr ,

Thanks for your response — I completely understand your point.
However, I’d like to clarify that this isn’t only an application-level concern; the library’s default behavior can also affect security.

I agree that XDocReport is designed to render variables like username inside documents — that’s exactly what the library is meant to do.
However, when it goes beyond variable rendering — without sandboxing or disabling dangerous function calls — and allows remote code execution (RCE) through untrusted template input, that becomes a security vulnerability, not just normal behavior.

A similar case happened with Log4Shell (Log4j) — the library was only supposed to log simple variables like logger.info("User: " + username), but because of unsafe defaults (${jndi:ldap://...}), attackers could trigger RCE.
This shows that even libraries not intended for code execution can become attack vectors if they process untrusted input without restrictions.

Likewise, I’ve seen a real-world example where an employee management web app allowed users to upload .docx files, which were then rendered using XDocReport. If such files contained malicious FreeMarker expressions, they could potentially lead to remote code execution.

That’s why I believe having safe defaults, or at least a security note in the documentation, would greatly reduce the risk for downstream users.

@angelozerr
Copy link
Member

Hi @angelozerr ,

Thanks for your response — I completely understand your point.
However, I’d like to clarify that this isn’t only an application-level concern; the library’s default behavior can also affect security.

I agree that XDocReport is designed to render variables like username inside documents — that’s exactly what the library is meant to do.
However, when it goes beyond variable rendering — without sandboxing or disabling dangerous function calls — and allows remote code execution (RCE) through untrusted template input, that becomes a security vulnerability, not just normal behavior.

A similar case happened with Log4Shell (Log4j) — the library was only supposed to log simple variables like logger.info("User: " + username), but because of unsafe defaults (${jndi:ldap://...}), attackers could trigger RCE.
This shows that even libraries not intended for code execution can become attack vectors if they process untrusted input without restrictions.

Likewise, I’ve seen a real-world example where an employee management web app allowed users to upload .docx files, which were then rendered using XDocReport. If such files contained malicious FreeMarker expressions, they could potentially lead to remote code execution.

Good catch! Excellent usecase!

That’s why I believe having safe defaults, or at least a security note in the documentation, would greatly reduce the risk for downstream users.

You have changed my mind. Please add again some tests and add more comments in your code by setting an exemple of malicious field.

// Security fix: Block dangerous class instantiation via ?new operator to prevent SSTI attacks
try
{
this.freemarkerConfiguration.setSetting( Configuration.NEW_BUILTIN_CLASS_RESOLVER_KEY, "safer" );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this constant exists in any freemarker version? I - think you should catch Exception instead of catching TemplateException

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@angelozerr Thanks for the question!
Configuration.NEW_BUILTIN_CLASS_RESOLVER_KEY was introduced in FreeMarker 2.3.30, so it is supported in the FreeMarker version currently used in XDocReport (2.3.32).

@angelozerr
Copy link
Member

LGTM, let's see the CI build result.

@AT190510-Cuong
Copy link
Contributor Author

Hi @angelozerr ,
All CI checks have passed successfully.
Thank you very much for reviewing and for your kind support! 🙏

@angelozerr angelozerr merged commit 3b35d10 into opensagres:master Nov 15, 2025
3 checks passed
@angelozerr
Copy link
Member

Thanks @AT190510-Cuong !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants