← Blog

LangChain and LangSmith Audit Logs: Why the User ID Field Is Not an Identity Check

LangSmith traces every LangChain LLM call in detail: messages, tool calls, token counts, and custom metadata. The user_id and session_id fields that group those traces into threads are optional strings a developer chooses to attach, not values LangSmith verifies against an identity provider. This article separates trace completeness from identity verification and lists what a security review should check before relying on either.

ByParminder Singh· Founder & CEO, DeepInspect Inc.
Platform & Architecturellm-securityai-securityauditidentity-and-authorizationinline-enforcement
LangChain and LangSmith Audit Logs: Why the User ID Field Is Not an Identity Check

A LangChain application wired to LangSmith produces a detailed trace for every model call: the full message history, tool calls the agent made, token counts by input and output, and whatever metadata the developer chose to attach. That trace is genuinely rich. I want to walk through exactly what it captures, because the field most reviewers assume is an identity check, user_id, is not one.

TL;DR

  • LangSmith traces capture full LLM call detail: messages, tool calls, token usage, and provider metadata like ls_provider and ls_model_name.
  • user_id, session_id, and thread_id are optional strings a developer attaches to group traces into "Threads" for the UI. Nothing in LangSmith verifies these values against an identity provider.
  • Access to LangSmith itself is governed by workspace and organization roles, which is Enterprise-plan RBAC, and API keys split into Personal Access Tokens and Service Keys.
  • A security review needs a record that ties one trace to a verified identity, not a string the application happened to pass.

What a LangSmith trace actually contains

LangSmith's tracing documentation describes a run object carrying inputs and outputs, the sequence of messages in OpenAI or Anthropic-compatible format, any tool calls the agent issued, and token usage broken down into input, output, cache, and reasoning tokens where the provider reports them. Runs also carry structured metadata: ls_provider and ls_model_name are populated automatically, and a developer can attach arbitrary metadata pairs on top. Traces roll up into projects, which is the authentication boundary: an API key or service key scopes access to a project, not to an individual end user.

That is a genuinely complete record of what a model saw and said. Most teams reviewing a LangSmith trace for the first time assume the completeness of the message log means the identity behind it is equally solid.

The field that looks like identity and isn't

LangSmith supports grouping related traces into "Threads" using user_id, session_id, or a similar identifier, and the Threads documentation is direct about what that field is: an optional string the application supplies, used to organize the UI. Nothing in LangSmith checks that value against an identity provider, a session store, or any authentication system. A developer can pass a real employee ID, a made-up placeholder, or the literal string "user" for every request in production, and LangSmith will group traces identically either way.

I think this is the single most consequential gap in LangChain's observability story, and most reviewers miss it because the field is right there in the trace, named user_id, looking exactly like the thing a compliance reviewer is looking for. A support tool built on LangChain, backed by one shared API key for the whole engineering org, can tag every trace with a hardcoded user_id of "support-bot" regardless of which customer or employee triggered the underlying call. The trace is complete. The identity is fiction.

RBAC governs who can read LangSmith, not who triggered a trace

LangSmith's own access model is separate from this problem and worth naming clearly so the two don't get conflated. Role-based access control is an Enterprise-plan feature with built-in workspace roles (Admin, Editor, Viewer) and organization-level roles governing who can view projects, manage members, or configure workspaces. API access splits into Personal Access Tokens, tied to the individual user who created them, and Service Keys, scoped to a workspace and incapable of exceeding their creator's own permissions. LangSmith and the LangGraph Platform both carry SOC 2 Type II attestation, and a self-hosted deployment option exists for teams that need LangSmith's control plane inside their own infrastructure.

All of that governs who can log into LangSmith and browse its traces. None of it touches the user_id field inside a trace, which remains whatever string the calling application decided to send.

A reminder that model output isn't automatically trustworthy either

In December 2025, researchers at Cyera disclosed CVE-2025-68664, nicknamed "LangGrinch", a CVSS 9.3 flaw in langchain-core's serialization functions. User-controlled dictionaries containing the library's internal "lc" marker key weren't escaped before serialization, so data that originated from a prompt injection embedded in model output could be deserialized back into a trusted LangChain object, opening a path to arbitrary code execution and secret exfiltration. The fix shipped in langchain-core 0.3.81 and 1.2.5. The lesson generalizes past this one bug: content flowing through a LangChain pipeline, including a model's own output, needs the same scrutiny as any other untrusted input, whether that content ends up in a trace, a serialized object, or a downstream tool call.

What a review should retrieve

Pull one trace involving a sensitive operation and check whether user_id maps to a value your identity system actually issued, or a static string the code hardcoded months ago. If it's the latter, the trace is complete but the identity attribution is decorative, and that gap is the finding. It's the same post-authentication gap that shows up wherever an application, not an independent proxy, is trusted to self-report who it's acting on behalf of. Signed audit logs for AI requests describes what a record has to contain to close that gap for good.

DeepInspect

This is the gap DeepInspect closes. DeepInspect sits inline as a stateless proxy between an authenticated user or agent and any HTTP-based LLM endpoint a LangChain application calls, evaluating the actual verified identity behind a request, its role, and the classification of the prompt, before the request reaches the model.

The resulting audit record ties one request to one verified principal, independent of whatever string the calling LangChain application chose to pass as user_id. LangSmith keeps doing what it does well: giving engineers a rich debugging and evaluation trace. DeepInspect adds what LangSmith's trace was never designed to verify, an identity-bound record a security review can actually trust. Book a demo today.