Prompt injection detection
Arcjet prompt injection detection evaluates each incoming prompt for injection patterns inside your application before it reaches the AI provider. Detected attacks are blocked before the AI call is made, protecting both your application behavior and your AI budget.
What is Arcjet?
Arcjet is the runtime security platform that ships with your code. Enforce budgets, stop prompt injection, detect bots, and protect personal information with Arcjet's AI security building blocks.Quick start
Section titled “Quick start”This example screens inbound user text for prompt injection before the model runs.
We assume you already have a LangChain project set up. For helper options and denial behavior, see the LangChain agent guard.
Install the dependencies:
# Export your Arcjet API key from https://app.arcjet.comexport ARCJET_KEY="ajkey_..."export ARCJET_ENV=development
pip install "arcjet[langchain-agents]" langchain langchain-openaiCreate the example:
import os
from arcjet.guard import DetectPromptInjection, launch_arcjet
arcjet = launch_arcjet(key=os.environ["ARCJET_KEY"])inbound = DetectPromptInjection()
async def screen_prompt(user_id: str, prompt: str) -> None: decision = await arcjet.guard( label="message.received", actor=user_id, rules=[inbound(prompt)], ) if decision.conclusion == "DENY" or decision.has_failed_open(): raise RuntimeError("Prompt injection detected – rephrase your message")Then start or invoke the agent with a test prompt.
Requests appear in your Arcjet dashboard in real time.
This example screens inbound user text for prompt injection before the model runs.
We assume you already have a Genkit project set up. For helper options and denial behavior, see the Genkit agent guard.
Until @arcjet/guard/genkit/v1 is published, the import lives on
4e416787,
not in the published @arcjet/guard package on npm.
Install the dependencies:
# Export your Arcjet API key from https://console.arcjet.comexport ARCJET_KEY="ajkey_..."
npm install @arcjet/guard genkitCreate the example:
import { launchArcjet, detectPromptInjection } from "@arcjet/guard";import { genkitContext } from "@arcjet/guard/genkit/v1";
const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });const inbound = detectPromptInjection();
export async function screenPrompt( conversationId: string, userText: string,) { const appContext = { sessionId: conversationId }; const decision = await arcjet.guard({ label: "message.received", rules: [inbound(userText)], ...genkitContext({ context: appContext }), });
if (decision.conclusion === "DENY" || decision.hasFailedOpen()) { throw new Error("Prompt injection detected – rephrase your message"); }}Then start or invoke the agent with a test prompt.
Requests appear in your Arcjet dashboard in real time.
This example screens inbound user text for prompt injection before the model runs.
We assume you already have a Mastra project set up. For helper options and denial behavior, see the Mastra agent guard.
Install the dependencies:
# Export your Arcjet API key from https://app.arcjet.comexport ARCJET_KEY="ajkey_..."
npm install @arcjet/guard @mastra/coreCreate the example:
import { launchArcjet, detectPromptInjection } from "@arcjet/guard";import { guardProcessor } from "@arcjet/guard/mastra/v1";import { Agent } from "@mastra/core/agent";
const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });
const inbound = guardProcessor(arcjet, { action: "message.received", rules: ({ text }) => [detectPromptInjection()(text)],});
export const agent = new Agent({ id: "support-agent", name: "support-agent", instructions: "Help the user.", model: "openai/gpt-4o-mini", inputProcessors: [inbound],});Then start or invoke the agent with a test prompt.
Requests appear in your Arcjet dashboard in real time.
This example screens inbound user text for prompt injection before the model runs.
We assume you already have a Claude Agent SDK project set up. For helper options and denial behavior, see the Claude Agent SDK agent guard.
Install the dependencies:
# Export your Arcjet API key from https://app.arcjet.comexport ARCJET_KEY="ajkey_..."
npm install @arcjet/guard @anthropic-ai/claude-agent-sdkCreate the example:
import { query } from "@anthropic-ai/claude-agent-sdk";import { launchArcjet, detectPromptInjection } from "@arcjet/guard";import { guardHooks } from "@arcjet/guard/claude-agent-sdk/v0";
const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });
export async function runAgent(sessionId: string, userText: string) { for await (const message of query({ prompt: userText, options: { sessionId, hooks: guardHooks(arcjet, { sessionId, inbound: { action: "message.received", rules: ({ prompt }) => [detectPromptInjection()(prompt)], }, }), }, })) { void message; }}Then start or invoke the agent with a test prompt.
Requests appear in your Arcjet dashboard in real time.
This example screens inbound user text for prompt injection before the model runs.
We assume you already have a LangGraph project set up. For helper options and denial behavior, see the LangGraph agent guard.
Install the dependencies:
# Export your Arcjet API key from https://app.arcjet.comexport ARCJET_KEY="ajkey_..."
npm install @arcjet/guard @langchain/langgraph @langchain/coreCreate the example:
import { launchArcjet, detectPromptInjection } from "@arcjet/guard";import { langgraphAgentContext } from "@arcjet/guard/langgraph/v1";
const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });const inbound = detectPromptInjection();
export async function screenPrompt( conversationId: string, userText: string,) { const config = { configurable: { thread_id: conversationId } }; const decision = await arcjet.guard({ label: "message.received", rules: [inbound(userText)], ...langgraphAgentContext(config), });
if (decision.conclusion === "DENY" || decision.hasFailedOpen()) { throw new Error("Prompt injection detected – rephrase your message"); }}Then start or invoke the agent with a test prompt.
Requests appear in your Arcjet dashboard in real time.
This example screens inbound user text for prompt injection before the model runs.
We assume you already have a OpenAI Agents project set up. For helper options and denial behavior, see the OpenAI Agents agent guard.
Install the dependencies:
# Export your Arcjet API key from https://app.arcjet.comexport ARCJET_KEY="ajkey_..."
npm install @arcjet/guard @openai/agentsCreate the example:
import { launchArcjet, detectPromptInjection } from "@arcjet/guard";import { openaiAgentsContext } from "@arcjet/guard/openai-agents/v0";
const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });const inbound = detectPromptInjection();
export async function screenPrompt( conversationId: string, userText: string,) { const appContext = { sessionId: conversationId }; const decision = await arcjet.guard({ label: "message.received", rules: [inbound(userText)], ...openaiAgentsContext({ context: appContext, conversationId }), });
if (decision.conclusion === "DENY" || decision.hasFailedOpen()) { throw new Error("Prompt injection detected – rephrase your message"); }}Then start or invoke the agent with a test prompt.
Requests appear in your Arcjet dashboard in real time.
This example screens inbound user text for prompt injection before the model runs.
We assume you already have a Vercel Eve project set up. For helper options and denial behavior, see the Vercel Eve agent guard.
Install the dependencies:
# Export your Arcjet API key from https://app.arcjet.comexport ARCJET_KEY="ajkey_..."
npm install @arcjet/guard eveCreate the example:
import { launchArcjet, detectPromptInjection } from "@arcjet/guard";import { guardInbound } from "@arcjet/guard/vercel-eve/v0";
const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });
export async function screenInbound( message: string, conversationId: string,) { const verdict = await guardInbound(arcjet, message, { action: "message.received", correlationId: conversationId, rules: [detectPromptInjection()(message)], });
if (!verdict.allowed) { throw new Error("Prompt injection detected – rephrase your message"); }}Then start or invoke the agent with a test prompt.
Requests appear in your Arcjet dashboard in real time.
This example screens inbound user text for prompt injection before the model runs.
We assume you already have a Vercel AI SDK project set up. For helper options and denial behavior, see the Vercel AI SDK agent guard.
Install the dependencies:
# Export your Arcjet API key from https://app.arcjet.comexport ARCJET_KEY="ajkey_..."
npm install @arcjet/guard ai @ai-sdk/provider-utilsCreate the example:
import { launchArcjet, detectPromptInjection } from "@arcjet/guard";import { generateText } from "ai";
const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });const inbound = detectPromptInjection();
export async function runAgent(userId: string, prompt: string) { const decision = await arcjet.guard({ label: "message.received", actor: userId, rules: [inbound(prompt)], });
if (decision.conclusion === "DENY" || decision.hasFailedOpen()) { throw new Error("Prompt injection detected – rephrase your message"); }
return generateText({ model: "openai/gpt-4o-mini", prompt, });}Then start or invoke the agent with a test prompt.
Requests appear in your Arcjet dashboard in real time.
In this example we use the Vercel AI SDK to create a simple AI chat endpoint with Next.js, and Arcjet to block prompt injection attacks before they reach the AI model. The same principles can be applied to any AI application, including those built with other frameworks.
We assume you already have a Next.js app set up.
Install the dependencies (prompt injection detection is available as of the
Arcjet 1.3.0 JS SDK release):
# Export your Arcjet API key from https://app.arcjet.comexport ARCJET_KEY="ajkey_..."
npm install @arcjet/next ai @ai-sdk/openaiCreate an AI chat endpoint:
import { openai } from "@ai-sdk/openai";import arcjet, { detectPromptInjection, shield } from "@arcjet/next";import type { UIMessage } from "ai";import { convertToModelMessages, isTextUIPart, streamText } from "ai";
const aj = arcjet({ key: process.env.ARCJET_KEY!, // Get your site key from https://app.arcjet.com rules: [ // Shield protects against common web attacks e.g. SQL injection shield({ mode: "LIVE" }), // Detect prompt injection attacks before they reach your AI model detectPromptInjection({ mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only }), ],});
export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } = await req.json();
// Check the most recent user message for prompt injection. // Pass the full conversation if you want to scan all messages. const lastMessage: string = (messages.at(-1)?.parts ?? []) .filter(isTextUIPart) .map((p) => p.text) .join(" ");
const decision = await aj.protect(req, { detectPromptInjectionMessage: lastMessage, });
if (decision.isDenied()) { if (decision.reason.isPromptInjection()) { console.warn("Request blocked due to prompt injection"); return new Response( "Prompt injection detected — please rephrase your message", { status: 403 }, ); } return new Response("Forbidden", { status: 403 }); }
// Arcjet approved — call your AI provider const result = await streamText({ model: openai("gpt-4o"), messages: await convertToModelMessages(messages), });
return result.toUIMessageStreamResponse();}And hook it up to a chat UI:
"use client";
import { useChat } from "@ai-sdk/react";import { useState } from "react";
export default function Chat() { const [input, setInput] = useState(""); const [errorMessage, setErrorMessage] = useState<string | null>(null); const { messages, sendMessage } = useChat({ onError: async (e) => setErrorMessage(e.message), }); return ( <div className="flex flex-col w-full max-w-md py-24 mx-auto stretch"> {messages.map((message) => ( <div key={message.id} className="whitespace-pre-wrap"> {message.role === "user" ? "User: " : "AI: "} {message.parts.map((part, i) => { switch (part.type) { case "text": return <div key={`${message.id}-${i}`}>{part.text}</div>; } })} </div> ))}
{errorMessage && ( <div className="text-red-500 text-sm mb-4">{errorMessage}</div> )}
<form onSubmit={(e) => { e.preventDefault(); sendMessage({ text: input }); setInput(""); setErrorMessage(null); }} > <input className="fixed dark:bg-zinc-900 bottom-0 w-full max-w-md p-2 mb-8 border border-zinc-300 dark:border-zinc-800 rounded shadow-xl" value={input} placeholder="Say something..." onChange={(e) => setInput(e.currentTarget.value)} /> </form> </div> );}Then run the server:
npm run devRequests appear in your Arcjet dashboard in real time.
In this example we use LangChain to create a simple AI chat server with Flask, and Arcjet to block prompt injection attacks before they reach the AI model. The same principles can be applied to any AI application, including those built with other frameworks.
Set up the environment and install dependencies (uses uv, but you can also use pip to install the Arcjet Python SDK):
# Export your Arcjet API key from https://app.arcjet.comexport ARCJET_KEY="ajkey_..."export ARCJET_ENV=development
# Export your OpenAI API key (used by LangChain)export OPENAI_API_KEY="sk-..."
# Install dependenciesuv add arcjet flask langchain langchain-openaiCreate the chat server:
import loggingimport os
from arcjet import Mode, arcjet_sync, detect_prompt_injection, shieldfrom flask import Flask, jsonify, requestfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAI
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)logger = logging.getLogger(__name__)
arcjet_key = os.getenv("ARCJET_KEY")if not arcjet_key: raise RuntimeError("ARCJET_KEY is required. Get one at https://app.arcjet.com")
openai_api_key = os.getenv("OPENAI_API_KEY")if not openai_api_key: raise RuntimeError( "OPENAI_API_KEY is required. Get one at https://platform.openai.com" )
llm = ChatOpenAI(model="gpt-4o-mini", api_key=openai_api_key)
prompt = ChatPromptTemplate.from_messages( [ ("system", "You are a helpful assistant."), ("human", "{message}"), ])
chain = prompt | llm | StrOutputParser()
# Create a single Arcjet client at startup and reuse it across requestsaj = arcjet_sync( key=arcjet_key, # Get your key from https://app.arcjet.com rules=[ # Shield protects against common web attacks e.g. SQL injection shield(mode=Mode.LIVE), # Detect prompt injection attacks before they reach your AI model detect_prompt_injection( mode=Mode.LIVE, # Blocks requests. Use Mode.DRY_RUN to log only ), ],)
@app.post("/chat")def chat(): body = request.get_json() message = body.get("message", "") if body else ""
# Pass the user message so detect_prompt_injection can evaluate it decision = aj.protect(request, detect_prompt_injection_message=message)
if decision.is_denied(): if decision.reason_v2.type == "PROMPT_INJECTION": logger.warning("Request blocked due to prompt injection") return jsonify( error="Prompt injection detected — please rephrase your message" ), 400 # SHIELD or any other denial return jsonify(error="Forbidden"), 403
# Arcjet approved — call the AI model reply = chain.invoke({"message": message})
return jsonify(reply=reply)
if __name__ == "__main__": app.run(debug=True)Then run the server:
uv run python app.pyAnd send a message to the API endpoint:
curl -X POST http://localhost:5000/chat \ -H "Content-Type: application/json" \ -d '{"message": "What is the capital of France?"}'Requests appear in your Arcjet dashboard in real time.
In this example we use LangChain to create a simple AI chat server with FastAPI, and Arcjet to block prompt injection attacks before they reach the AI model. The same principles can be applied to any AI application, including those built with other frameworks.
Set up the environment and install dependencies (uses uv, but you can also use pip to install the Arcjet Python SDK):
# Export your Arcjet API key from https://app.arcjet.comexport ARCJET_KEY="ajkey_..."export ARCJET_ENV=development
# Export your OpenAI API key (used by LangChain)export OPENAI_API_KEY="sk-..."
# Install dependenciesuv add arcjet fastapi uvicorn langchain langchain-openaiCreate the chat server:
import loggingimport os
from arcjet import Mode, arcjet, detect_prompt_injection, shieldfrom fastapi import FastAPI, Requestfrom fastapi.responses import JSONResponsefrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAIfrom pydantic import BaseModel
app = FastAPI()
logging.basicConfig(level=logging.INFO)logger = logging.getLogger(__name__)
arcjet_key = os.getenv("ARCJET_KEY")if not arcjet_key: raise RuntimeError("ARCJET_KEY is required. Get one at https://app.arcjet.com")
openai_api_key = os.getenv("OPENAI_API_KEY")if not openai_api_key: raise RuntimeError( "OPENAI_API_KEY is required. Get one at https://platform.openai.com" )
llm = ChatOpenAI(model="gpt-4o-mini", api_key=openai_api_key)
prompt = ChatPromptTemplate.from_messages( [ ("system", "You are a helpful assistant."), ("human", "{message}"), ])
chain = prompt | llm | StrOutputParser()
class ChatRequest(BaseModel): message: str
# Create a single Arcjet client at startup and reuse it across requestsaj = arcjet( key=arcjet_key, # Get your key from https://app.arcjet.com rules=[ # Shield protects against common web attacks e.g. SQL injection shield(mode=Mode.LIVE), # Detect prompt injection attacks before they reach your AI model detect_prompt_injection( mode=Mode.LIVE, # Blocks requests. Use Mode.DRY_RUN to log only ), ],)
@app.post("/chat")async def chat(request: Request, body: ChatRequest): # Pass the user message so detect_prompt_injection can evaluate it decision = await aj.protect( request, detect_prompt_injection_message=body.message )
if decision.is_denied(): if decision.reason_v2.type == "PROMPT_INJECTION": logger.warning("Request blocked due to prompt injection") return JSONResponse( {"error": "Prompt injection detected — please rephrase your message"}, status_code=400, ) # SHIELD or any other denial return JSONResponse({"error": "Forbidden"}, status_code=403)
# Arcjet approved — call the AI model reply = await chain.ainvoke({"message": body.message})
return {"reply": reply}Then run the server:
uv run uvicorn main:app --reloadAnd send a message to the API endpoint:
curl -X POST http://localhost:8000/chat \ -H "Content-Type: application/json" \ -d '{"message": "What is the capital of France?"}'Requests appear in your Arcjet dashboard in real time.
What next?
Section titled “What next?”Get help
Section titled “Get help”Need help with anything? Email support@arcjet.com to get support from our engineering team.