LangChain Vulnerable to Template Injection via Attribute Access in Prompt Templates
LangChain Vulnerable to Template Injection via Attribute Access in Prompt Templates
High severity. Affects langchain-core >= 1.0.0, <= 1.0.6; langchain-core <= 0.3.79. Upgrade to 1.0.7 / 0.3.80 or later.
CVE-2025-65106 / GHSA-6qv9-48xg-fc7f · severity: high · PyPI
Affected
langchain-core>= 1.0.0, <= 1.0.6 → fixed in 1.0.7langchain-core<= 0.3.79 → fixed in 0.3.80
Details
Context
A template injection vulnerability exists in LangChain's prompt template system that allows attackers to access Python object internals through template syntax. This vulnerability affects applications that accept untrusted template strings (not just template variables) in ChatPromptTemplate and related prompt template classes.
Templates allow attribute access (.) and indexing ([]) but not method invocation (()).
The combination of attribute access and indexing may enable exploitation depending on which objects are passed to templates. When template variables are simple strings (the common case), the impact is limited. However, when using MessagesPlaceholder with chat message objects, attackers can traverse through object attributes and dictionary lookups (e.g., __globals__) to reach sensitive data such as environment variables.
The vulnerability specifically requires that applications accept template strings (the structure) from untrusted sources, not just template variables (the data). Most applications either do not use templates or else use hardcoded templates and are not vulnerable.
Affected Components
langchain-corepackage- Template formats:
- F-string templates (
template_format="f-string") - Vulnerability fixed - Mustache templates (
template_format="mustache") - Defensive hardening - Jinja2 templates (
template_format="jinja2") - Defensive hardening
- F-string templates (
Impact
Attackers who can control template strings (not just template variables) can:
- Access Python object attributes and internal properties via attribute traversal
- Extract sensitive information from object internals (e.g.,
__class__,__globals__) - Potentially escalate to more severe attacks depending on the objects passed to templates
Attack Vectors
1. F-string Template Injection
Before Fix:
from langchain_core.prompts import ChatPromptTemplate
malicious_template = ChatPromptTemplate.from_messages(
[("human", "{msg.__class__.__name__}")],
template_format="f-string"
)
# Note that this requires passing a placeholder variable for "msg.__class__.__name__".
result = malicious_template.invoke({"msg": "foo", "msg.__class__.__name__": "safe_placeholder"})
# Previously returned
# >>> result.messages[0].content
# >>> 'str'
2. Mustache Template Injection
Before Fix:
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage
msg = HumanMessage("Hello")
# Attacker controls the template string
malicious_template = ChatPromptTemplate.from_messages(
[("human", "{{question.__class__.__name__}}")],
template_format="mustache"
)
result = malicious_template.invoke({"question": msg})
# Previously returned: "HumanMessage" (getattr() exposed internals)
3. Jinja2 Template Injection
Before Fix:
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage
msg = HumanMessage("Hello")
# Attacker controls the template string
malicious_template = ChatPromptTemplate.from_messages(
[("human", "{{question.parse_raw}}")],
template_format="jinja2"
)
result = malicious_template.invoke({"question": msg})
# Could access non-dunder attributes/methods on objects
Root Cause
- F-string templates: The implementation used Python's
string.Formatter().parse()to extract variable names from template strings. This method returns the complete field expression, including attribute access syntax:
The extracted names were not validated to ensure they were simple identifiers. As a result, template strings containing attribute traversal and indexing expressions (e.g.,from string import Formatter template = "{msg.__class__} and {x}" print([var_name for (_, var_name, _, _) in Formatter().parse(template)]) # Returns: ['msg.__class__', 'x']{obj.__class__.__name__}or{obj.method.__globals__[os]}) were accepted and subsequently evaluated during formatting. While f-string templates do not support method calls with(), they do support[]indexing, which could allow traversal through dictionaries like__globals__to reach sensitive objects. - Mustache templates: By design, used
getattr()as a fallback to support accessing attributes on objects (e.g.,{{user.name}}on a User object). However, we decided to restrict this to simpler primitives that subclass dict, list, and tuple types as defensive hardening, since untrusted templates could exploit attribute access to reach internal properties like class on arbitrary objects - Jinja2 templates: Jinja2's default
SandboxedEnvironmentblocks dunder attributes (e.g.,__class__) but permits access to other attributes and methods on objects. While Jinja2 templates in LangChain are typically used with trusted template strings, as a defense-in-depth measure, we've restricted the environment to block all attribute and method access on objects passed to templates.
Who Is Affected?
High Risk Scenarios
You are affected if your application:
- Accepts template strings from untrusted sources (user input, external APIs, databases)
- Dynamically constructs prompt templates based on user-provided patterns
- Allows users to customize or create prompt templates
Example vulnerable code:
# User controls the template string itself
user_template_string = request.json.get("template") # DANGEROUS
prompt = ChatPromptTemplate.from_messages(
[("human", user_template_string)],
template_format="mustache"
)
result = prompt.invoke({"data": sensitive_object})
Low/No Risk Scenarios
You are NOT affected if:
- Template strings are hardcoded in your application code
- Template strings come only from trusted, controlled sources
- Users can only provide values for template variables, not the template structure itself
Example safe code:
# Template is hard
Source: [GHSA-6qv9-48xg-fc7f](https://github.com/advisories/GHSA-6qv9-48xg-fc7f) — GitHub Advisory Database (CC-BY-4.0).