Preventing file-system access via include/layouts
See original GitHub issueContext
We are building a Node.js back-end application that sends emails to end-users and we would like to use liquidjs
to render email templates. The application provides default email templates out of the box, but we also allow tenants to customize the templates.
In order to support this use case, we’d like to restrict the use of the {% include ... %}
and {% layout ... %}
tags: we should not allow reading arbitrary files from the file system.
For example, a tenant would be able to use includes in a custom template like this:
<div>
{% include ../package.json %}
</div>
That would render the package.json file inside the email. Note that the root
option is set to a sub-directory of the project like myproject/templates
.
Potential solutions
We found various approaches to address this concern but we would like to validate them with you.
Restrict root
One way to address this concern would be to keep allowing file-system access, but set the root
option to an empty directory. But at the same time, liquidjs
should not allow relative paths OUTSIDE of this root (../
should not be allowed).
This would require a change to this library.
Override the include
and layout
tags
In the related issue #20, it is suggested to override the include
and layout
tags by registering alternate implementations. We could provide implementations that return an empty string or throw an exception.
One drawback of this approach is that tags are currently registered statically. See: https://github.com/harttle/liquidjs/blob/bbebb5515c7efe03c43ae7eaa25ecd9b8a113467/src/template/tag/tag.ts#L16)
That means that ALL instances of the liquidjs
engine will apply the overridden tags. Unfortunately, this is problematic for us: we want to have instances of the engine that allow fs access and others that don’t allow them (basically, default email templates allow them and custom email templates don’t allow them).
Patch the Liquid.getTemplate()
method
Both the include
and layout
tags’ current implementation are calling the Liquid.getTemplate()
method to read from disk. As a matter of fact, all file-system access is confined to this method. It might be more secure to patch this method by a custom implementation (returning an empty string or throwing an exception). This might be more future-proof if this library starts adding more tags that access the file-system. On the other hand, patching this method breaks the Liquid.renderFile()
method, but we don’t use this method.
If this approach sounds like a good idea, could we consider providing abstractions to this library that allow extending this behavior in a more structured approach? For example, there’s the liquid-node
library that supports registering custom “File System” objects: https://github.com/liquid-lang/liquid-node/blob/7f5076526adcef13ad03b11dfe69b33e9011731b/lib/liquid/engine.js#L76-L82
Adding a new option to liquidjs
If our use case is shared by other users of this lib, we might want to add a new option in liquidjs
to disable file system access (something like disableFs
?).
Any guidance with our use case is much appreciated. We’d be glad to contribute PRs if valuable.
Thanks for maintaining this library! ❤️
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (4 by maintainers)
Top GitHub Comments
Looks like a good enough solution
Or if you want to get fancy you can override the resolve method
🎉 This issue has been resolved in version 8.3.0 🎉
The release is available on:
Your semantic-release bot 📦🚀