LangChain Security Patterns: Governing Tools, Egress, and Output in a Chain
LangChain hands the model tools, memory, and retrieved context, and each one is a trust boundary the framework does not police for you. This article walks the security patterns that matter in a LangChain app: constrain what tools can do, propagate caller identity through the chain, validate output before it drives an action, and constrain egress. It marks which patterns live in your code and which need an enforcement layer on the HTTP path.

A LangChain agent is a loop: the model receives a prompt and a set of tools, decides which tool to call, the framework runs it, and the result feeds back into the next model call. Every element in that loop is a trust boundary. The tools reach real systems, the retrieved context is untrusted input, and the model's output can drive an action before any human sees it. LangChain's own security documentation opens by telling builders to limit permissions, anticipate misuse, and defend in depth, because the framework gives you the wiring and not the guardrails. I want to walk the patterns that hold in production, and mark which live in your code and which need an enforcement layer on the request path. The injection vector itself is covered in LangChain prompt injection; this piece is about the surrounding architecture.
Scope every tool to least privilege
The model decides which tool to call, and a compromised or injected prompt decides for it. So the blast radius of any agent is the union of what its tools can do. A tool wired to a database connection with write access means an injected instruction can write to the database. The pattern is least privilege at the tool boundary: give each tool the narrowest credential and the tightest scope that lets it do its one job.
A read-only agent role with an explicit table allowlist means the worst an injected DROP TABLE can do is fail an authorization check. This is your code, and it is the strongest control in the whole chain.
Propagate caller identity through the chain
LangChain does not carry your user's identity to the tools by default. The chain runs under whatever credential the process holds, so a database tool, an HTTP tool, or a retriever sees the application rather than the human who made the request. That erases per-user authorization at exactly the boundary where data access happens. The pattern is to thread the caller identity through the chain and enforce it at each tool:
Identity that reaches the tool is what lets a retriever return only documents this user may see, which is the difference between a shared-context leak and a scoped one.
Validate output before it drives an action
An agent's output is frequently an instruction: a tool call, a SQL string, a set of arguments, a piece of content bound for another system. Treating model output as trusted input to the next step is where injected instructions become actions. The pattern is to validate output against a schema and an authorization check before acting on it, never to route raw model text into an executor. LangChain's documented history here is instructive: early experimental chains that executed model-generated code and queries were the source of real CVEs, which is why the framework moved them behind explicit opt-in flags.
Constrain egress and treat retrieval as untrusted
Two more boundaries round out the chain. Retrieved context, whether from a vector store, a web tool, or a document loader, is untrusted input that can carry indirect injection, so it gets the same suspicion as user input rather than the trust of a system message. And the HTTP calls the chain makes, to the model provider and to any API tool, are an egress surface that belongs on an allowlist, so a tool cannot be talked into reaching an endpoint it has no business calling. Both of these are on the network path, which is where a control outside the application code can see them.
Where the patterns split
Some of these controls live only in your code. Tool credential scoping, the choice not to execute model-generated code, and the schema of a tool's arguments are application architecture, and no network layer can supply them. Others live on the HTTP request path: identity-bound authorization of each model and tool call, classification of prompt and retrieved content, validation of output before it leaves for a downstream system, and egress allowlisting. That second set is where an external enforcement layer applies, because it sits on the traffic the chain generates rather than inside the Python process. The tempo makes the split matter: Google Mandiant's M-Trends 2026 report put median attacker handoff at 22 seconds, so a control that reviews chain activity after the fact documents the incident rather than preventing it.
DeepInspect
LangChain gives you the loop. DeepInspect governs the traffic the loop generates.
DeepInspect is a stateless proxy on the AI request path between your LangChain application and the model and tool endpoints it calls. It binds each call to the caller identity your application supplies, classifies prompt and retrieved content across PII, PHI, source code, and jurisdictional categories, authorizes each model request and tool invocation against role and content, and evaluates output before it reaches a downstream system, applying a deterministic pass, block, or modify decision inline and fail-closed. It commits a per-decision audit record for every call, so an investigation can name which identity drove which action through the chain. The in-code patterns above stay your job; DeepInspect adds the enforcement and audit layer on the HTTP path that a framework running inside your process cannot provide for itself. Book a demo today.
Frequently asked questions
- Does LangChain enforce any security by default?
Minimally. LangChain provides the orchestration and expects the builder to supply the controls, which its security documentation states directly: limit permissions, anticipate misuse, and defend in depth. Some historically dangerous components, like chains that execute model-generated code or database queries, are gated behind explicit opt-in flags after they produced real CVEs. Beyond those guards, tool scoping, identity propagation, output validation, and egress control are all things you implement. Treat the framework as wiring and assume no control is present unless you added it.
- How do I stop an agent from misusing a tool?
Scope the tool, not the model. The model decides which tool to call, and an injected prompt can make that decision for it, so the durable control is at the tool boundary: give each tool the narrowest credential and tightest scope for its single job. A database tool gets a read-only role and an explicit table allowlist; an HTTP tool gets a destination allowlist; a filesystem tool gets a constrained path. Then authorize each invocation against the caller identity. That way the worst an injected instruction achieves is a failed authorization check rather than a destructive action.
- Why does identity propagation matter in a chain?
Because without it, every tool in the chain runs under the application's credential rather than the user's, which erases per-user authorization exactly where data is accessed. A retriever with no identity context returns documents from the whole corpus instead of the ones this user may see, and a database tool authorizes as the app rather than the person. Threading the caller identity through the chain and checking it at each tool is what keeps one user's request from reaching another user's data, and what makes a downstream audit log name the actor.
- Can a gateway replace these in-code patterns?
No, the two layers cover different boundaries. Tool credential scoping and the decision not to execute model-generated code are application architecture that no network layer can supply. A gateway on the HTTP path adds what the process cannot do for itself: identity-bound authorization of each model and tool call, content classification, output validation before it leaves for another system, and egress allowlisting. Run both. The in-code patterns shrink the blast radius, and the enforcement layer governs the traffic the chain generates and records every decision.