GHSA-8p4x-wr7x-3788
python-liquid: Absolute paths escape filesystem loader search path
Packages
| Ecosystem | Package | Affected | Fixed in |
|---|---|---|---|
| PyPI | python-liquid | < 2.2.0 | 2.2.0 |
Details
As written in the advisory (Markdown source, shown as plain text).
### Impact
The built-in `FileSystemLoader` and `CachingFileSystemLoader` do not guard against reading files outside their search paths when given an absolute path to resolve. This allows malicious template authors to load and render arbitrary files via the `{% include %}` and `{% render %}` tags. Targeted files would need to contain valid Liquid markup and be readable by the application process.
### Patches
The issue is fixed in version 2.2.0 with the inclusion of a `template_path.is_absolute()` condition in `liquid/builtin/loaders/file_system_loader.py`.
```python
if os.path.pardir in template_path.parts or template_path.is_absolute():
raise TemplateNotFoundError(template_name)
```
### Workarounds
Create a custom template loader by inheriting from `FileSystemLoader` and overriding `resolve_path()`. Use an instance of the custom loader as the `loader` argument when instantiating your Liquid environment.
```python
import os
from pathlib import Path
from liquid import Environment
from liquid import FileSystemLoader
from liquid.exceptions import TemplateNotFoundError
class MyFileSystemLoader(FileSystemLoader):
def resolve_path(self, template_name: str) -> Path:
template_path = Path(template_name)
if self.ext and not template_path.suffix:
template_path = template_path.with_suffix(self.ext)
if os.path.pardir in template_path.parts or template_path.is_absolute():
raise TemplateNotFoundError(template_name)
for path in self.search_path:
source_path = path.joinpath(template_path)
if not source_path.exists():
continue
return source_path
raise TemplateNotFoundError(template_name)
env = Environment(loader=MyFileSystemLoader("path/to/templates/"))
```
References
External links from the advisory. They lead to third-party sites.