Skip to content

Commit b869047

Browse files
fix: use SandboxedEnvironment in templating (#1168)
1 parent 5dc6a4c commit b869047

File tree

3 files changed

+26
-3
lines changed

3 files changed

+26
-3
lines changed

docs/concepts/templating.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ description: Learn to dynamically create prompts using Jinja templating and vali
55

66
# Prompt Templating
77

8-
98
With Instructor's Jinja templating, you can:
109

1110
- Dynamically adapt prompts to any context
@@ -239,3 +238,9 @@ print(address)
239238
```
240239

241240
This allows you to preserve your sensitive information while still using it in your prompts.
241+
242+
## Security
243+
244+
We use the `jinja2.sandbox.SandboxedEnvironment` to prevent security issues with the templating engine. This means that you can't use arbitrary python code in your prompts. But this doesn't mean that you should pass untrusted input to the templating engine, as this could still be abused for things like Denial of Service attacks.
245+
246+
You should [always sanitize](https://jinja.palletsprojects.com/en/stable/sandbox/#security-considerations) any input that you pass to the templating engine.

instructor/templating.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# type: ignore[all]
22
from __future__ import annotations
33
from typing import Any
4-
from jinja2 import Template
54
from textwrap import dedent
65

6+
from jinja2.sandbox import SandboxedEnvironment
7+
78

89
def apply_template(text: str, context: dict[str, Any]) -> str:
910
"""Apply Jinja2 template to the given text."""
10-
return dedent(Template(text).render(**context))
11+
return dedent(SandboxedEnvironment().from_string(text).render(**context))
1112

1213

1314
def process_message(message: dict[str, Any], context: dict[str, Any]) -> dict[str, Any]:

tests/test_formatting.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
1+
import pytest
2+
from jinja2.exceptions import SecurityError
3+
14
from instructor.templating import handle_templating
25

36

7+
def test_handle_insecure_template():
8+
with pytest.raises(SecurityError):
9+
kwargs = {
10+
"messages": [
11+
{
12+
"role": "user",
13+
"content": "{{ self.__init__.__globals__.__builtins__.__import__('os').system('ls') }} {{ variable }}",
14+
}
15+
]
16+
}
17+
context = {"variable": "test"}
18+
handle_templating(kwargs, context)
19+
20+
421
def test_handle_templating_with_context():
522
kwargs = {"messages": [{"role": "user", "content": "Hello {{ name }}!"}]}
623
context = {"name": "Alice"}

0 commit comments

Comments
 (0)