Skip to content

Fix: Harden FreeMarker against SSTI#705

Merged
angelozerr merged 2 commits into
opensagres:masterfrom
AT190510-Cuong:fix/ssti
Nov 15, 2025
Merged

Fix: Harden FreeMarker against SSTI#705
angelozerr merged 2 commits into
opensagres:masterfrom
AT190510-Cuong:fix/ssti

Conversation

@AT190510-Cuong

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Member

@AT190510-Cuong

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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

AT190510-Cuong commented Oct 23, 2025

Copy link
Copy Markdown
Contributor Author

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Member

LGTM, let's see the CI build result.

@AT190510-Cuong

Copy link
Copy Markdown
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
Copy Markdown
Member

Thanks @AT190510-Cuong !

kevinleturc pushed a commit to kevinleturc/xdocreport that referenced this pull request Jan 23, 2026
* fix: SSTI freemarker

* fix: Harden FreeMarker SSTI
kevinleturc pushed a commit to kevinleturc/xdocreport that referenced this pull request Jan 30, 2026
* fix: SSTI freemarker

* fix: Harden FreeMarker SSTI
kevinleturc pushed a commit to kevinleturc/xdocreport that referenced this pull request Jan 30, 2026
* fix: SSTI freemarker

* fix: Harden FreeMarker SSTI
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