java-topology/defects/langchain/CLEAN.md
russell@unturf.com 483f1cb5e5 ollama+langchain: 5-MOAD scan complete; langchain-0002 MultiQueryRetriever _unique_documents O(D^2), 21x at D=500
Ollama: all 5 MOADs scanned. MOAD-0001 ollama-0001 (pre-existing). MOADs 0002/0003/0004/0005 CLEAN
per defects/ollama/CLEAN.md (scanned 2026-03-31).

LangChain: all 5 MOADs scanned. New defect langchain-0002 MOAD-0001 CWE-407.
- multi_query.py _unique_documents: `doc not in documents[:i]` creates O(D) slice each iteration
  and performs O(D) linear scan, giving O(D^2) overall. D = Q*k where Q=queries, k=results per query.
- Fix: seen set with hashable proxy key (id, page_content, str(metadata items)). O(D) total.
- 9/9 unit tests PASS, 21.4x speedup at D=500.
MOADs 0002/0003/0004/0005 CLEAN per updated defects/langchain/CLEAN.md.
SCAN-TODO.md: mark both targets [x].
2026-04-03 15:15:33 -04:00

2.5 KiB

LangChain — 5-MOAD Scan Result

Date: 2026-04-03 Target: https://github.com/langchain-ai/langchain (Python) Scanner: Agent Blackops 5-MOAD sweep

MOAD-0001 (CWE-407) — 2 defects found

langchain-0001 (pre-existing): MultiVectorRetriever id dedup not in ids O(D^2). Fixed.

langchain-0002 (new): MultiQueryRetriever._unique_documents slice-in-loop O(D^2). Fixed. See defects/langchain-0002/.

Other patterns examined and cleared:

  • jsx.py:67if tag not in component_tags: bounded by file's unique JSX tags (small constant)
  • html.py:695if tag not in [header[0] for header in headers_to_split_on]: init-time, bounded by 6 HTML header levels
  • format_to_tool_messages (tools.py:70) — new not in messages: agent steps typically bounded (<50), LOW severity, not filed

MOAD-0002 (Intertangle) — CLEAN

globals.py has _llm_cache, _verbose, _debug as module-level mutable globals. These are configuration values set once at startup, not request-scoped state. No coupling of independent subsystems through shared mutable god objects. CallbackManager is per-invocation, not shared. RunnableConfig is a TypedDict passed explicitly, not a global.

MOAD-0003 (Leaked Context) — CLEAN

tracers/context.py uses ContextVar correctly: tracing_v2_callback_var and run_collector_var are module-level ContextVar instances (correct pattern for Python async), with proper token = var.set(cb); try: yield; finally: var.reset(token) lifecycle in context managers. No threading.local misuse. var_child_runnable_config in runnables/config.py is also a properly scoped ContextVar. No request-scoped identity leaked into thread-local storage.

MOAD-0004 (CWE-312) — CLEAN

Scanned all logger.* calls for credential patterns. No log calls found that include password, api_key, secret, token, or credential variable contents verbatim. Credential values are passed via environment variables (not logged). LANGCHAIN_API_KEY and similar are consumed by LangSmith client, not logged by LangChain core.

MOAD-0005 (Thundering Herd) — CLEAN

_cached_empty_embedding in openai/embeddings/base.py is a closure-local variable created fresh per call — not a shared singleton. _llm_cache global is a simple assignment (not a double-checked locking pattern). _enums_for_spec_lock = threading.Lock() in runnables/configurable.py properly guards its critical section. No unsynchronized check-then-set cache patterns found.