Home / Class/ TestEscaping Class — langchain Architecture

TestEscaping Class — langchain Architecture

Architecture documentation for the TestEscaping class in test_serializable.py from the langchain codebase.

Entity Profile

Dependency Diagram

graph TD
  a193f10f_1a60_b879_b342_d29b1680b3e6["TestEscaping"]
  de5a7878_b3fe_95d7_2575_7f534546dc1e["AIMessage"]
  a193f10f_1a60_b879_b342_d29b1680b3e6 -->|extends| de5a7878_b3fe_95d7_2575_7f534546dc1e
  d90477e3_b806_4058_daf0_8495f08436d6["test_serializable.py"]
  a193f10f_1a60_b879_b342_d29b1680b3e6 -->|defined in| d90477e3_b806_4058_daf0_8495f08436d6
  1eefacbe_c43e_84e8_dc3c_c9a29bcb1069["test_document_metadata_with_lc_key_escaped()"]
  a193f10f_1a60_b879_b342_d29b1680b3e6 -->|method| 1eefacbe_c43e_84e8_dc3c_c9a29bcb1069
  1a2dadb3_bc1b_7714_b00d_afa1425cccfe["test_document_metadata_with_nested_lc_key_escaped()"]
  a193f10f_1a60_b879_b342_d29b1680b3e6 -->|method| 1a2dadb3_bc1b_7714_b00d_afa1425cccfe
  33676637_7c9e_175a_2a9a_b13128e89d47["test_document_metadata_with_lc_key_in_list_escaped()"]
  a193f10f_1a60_b879_b342_d29b1680b3e6 -->|method| 33676637_7c9e_175a_2a9a_b13128e89d47
  822e55fc_290f_8fbc_606a_e45a85e0a0af["test_malicious_payload_not_instantiated()"]
  a193f10f_1a60_b879_b342_d29b1680b3e6 -->|method| 822e55fc_290f_8fbc_606a_e45a85e0a0af
  4946a8d3_7a23_7518_def8_ca78da82b4e7["test_message_additional_kwargs_with_lc_key_escaped()"]
  a193f10f_1a60_b879_b342_d29b1680b3e6 -->|method| 4946a8d3_7a23_7518_def8_ca78da82b4e7
  2ea9aeeb_6aff_6243_335b_f7c665722dad["test_message_response_metadata_with_lc_key_escaped()"]
  a193f10f_1a60_b879_b342_d29b1680b3e6 -->|method| 2ea9aeeb_6aff_6243_335b_f7c665722dad
  4209f521_1764_26ee_927c_789549188624["test_double_escape_handling()"]
  a193f10f_1a60_b879_b342_d29b1680b3e6 -->|method| 4209f521_1764_26ee_927c_789549188624

Relationship Graph

Source Code

libs/core/tests/unit_tests/load/test_serializable.py lines 400–527

class TestEscaping:
    """Tests that escape-based serialization prevents injection attacks.

    When user data contains an `'lc'` key, it's escaped during serialization
    (wrapped in `{"__lc_escaped__": ...}`). During deserialization, escaped
    dicts are unwrapped and returned as plain dicts - NOT instantiated as
    LC objects.
    """

    def test_document_metadata_with_lc_key_escaped(self) -> None:
        """Test that `Document` metadata with `'lc'` key round-trips as plain dict."""
        # User data that looks like an LC constructor - should be escaped, not executed
        suspicious_metadata = {"lc": 1, "type": "constructor", "id": ["some", "module"]}
        doc = Document(page_content="test", metadata=suspicious_metadata)

        # Serialize - should escape the metadata
        serialized = dumpd(doc)
        assert serialized["kwargs"]["metadata"] == {
            "__lc_escaped__": suspicious_metadata
        }

        # Deserialize - should restore original metadata as plain dict
        loaded = load(serialized, allowed_objects=[Document])
        assert loaded.metadata == suspicious_metadata  # Plain dict, not instantiated

    def test_document_metadata_with_nested_lc_key_escaped(self) -> None:
        """Test that nested `'lc'` key in `Document` metadata is escaped."""
        suspicious_nested = {"lc": 1, "type": "constructor", "id": ["some", "module"]}
        doc = Document(page_content="test", metadata={"nested": suspicious_nested})

        serialized = dumpd(doc)
        # The nested dict with 'lc' key should be escaped
        assert serialized["kwargs"]["metadata"]["nested"] == {
            "__lc_escaped__": suspicious_nested
        }

        loaded = load(serialized, allowed_objects=[Document])
        assert loaded.metadata == {"nested": suspicious_nested}

    def test_document_metadata_with_lc_key_in_list_escaped(self) -> None:
        """Test that `'lc'` key in list items within `Document` metadata is escaped."""
        suspicious_item = {"lc": 1, "type": "constructor", "id": ["some", "module"]}
        doc = Document(page_content="test", metadata={"items": [suspicious_item]})

        serialized = dumpd(doc)
        assert serialized["kwargs"]["metadata"]["items"][0] == {
            "__lc_escaped__": suspicious_item
        }

        loaded = load(serialized, allowed_objects=[Document])
        assert loaded.metadata == {"items": [suspicious_item]}

    def test_malicious_payload_not_instantiated(self) -> None:
        """Test that malicious LC-like structures in user data are NOT instantiated."""
        # An attacker might craft a payload with a valid AIMessage structure in metadata
        malicious_data = {
            "lc": 1,
            "type": "constructor",
            "id": ["langchain", "schema", "document", "Document"],
            "kwargs": {
                "page_content": "test",
                "metadata": {
                    # This looks like a valid LC object but is in escaped form
                    "__lc_escaped__": {
                        "lc": 1,
                        "type": "constructor",
                        "id": ["langchain_core", "messages", "ai", "AIMessage"],
                        "kwargs": {"content": "injected message"},
                    }
                },
            },
        }

        # Even though AIMessage is allowed, the metadata should remain as dict
        loaded = load(malicious_data, allowed_objects=[Document, AIMessage])
        assert loaded.page_content == "test"
        # The metadata is the original dict (unescaped), NOT an AIMessage instance
        assert loaded.metadata == {
            "lc": 1,
            "type": "constructor",
            "id": ["langchain_core", "messages", "ai", "AIMessage"],

Extends

Frequently Asked Questions

What is the TestEscaping class?
TestEscaping is a class in the langchain codebase, defined in libs/core/tests/unit_tests/load/test_serializable.py.
Where is TestEscaping defined?
TestEscaping is defined in libs/core/tests/unit_tests/load/test_serializable.py at line 400.
What does TestEscaping extend?
TestEscaping extends AIMessage.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free