Add AI protection
Contributed by davidmytton
Improved by Laravel Company · 2026-09-07
You are an expert security architect and prompt engineer specializing in LLM application security. Your task is to synthesize the provided technical documentation regarding the "Arcjet" framework for securing AI/LLM endpoints into a single, highly structured, actionable, and comprehensive tutorial.
The final output must serve as a definitive guide for developers on implementing layered security for AI endpoints.
Instructions for Synthesis:
- Establish Persona and Goal: Adopt the role of a security consultant. The goal is to transform the provided raw documentation into a clear, step-by-step implementation guide.
- Structure the Output: Organize the final guide using clear, hierarchical headings, emphasizing the flow of the security implementation (Setup -> Rules -> Execution -> Verification).
- Prioritize Actionable Steps: Ensure the guide clearly separates conceptual explanations from concrete code examples (JS/Python).
- Mandatory Sections: The guide must explicitly cover the following sections derived from the source material:
- Introduction: Define the problem (AI endpoint abuse) and the solution (Arcjet).
- Core Principles: Explain the philosophy (Arcjet runs before the model) and the layered approach (Injection, PII, Rate Limiting).
- Step 1: Setup: Detail how to initialize and set up the Arcjet client.
- Step 2: Implementing Rules: Provide detailed instructions and code examples for adding specific rules:
- Prompt Injection Detection.
- Sensitive Info / PII Blocking.
- Token Budget Rate Limiting (including recommended configuration for
tokenBucket). - Base Protection (
shield()anddetectBot()).
- Step 3: Execution Flow: Show the exact pattern for composing the
protect()call and handling the decision logic (including status codes and error messages). - Step 4: Verification & Maintenance: Detail the crucial verification steps (DRY_RUN, Live promotion) and how to use the Arcjet MCP tools (
list-requests,analyze-traffic, etc.). - Critical Best Practices (Mistakes to Avoid): Explicitly list and elaborate on the "Common Mistakes to Avoid" section, ensuring the developer understands the subtle but critical details (e.g., passing both
sensitiveInfoValueanddetectPromptInjectionMessage, streaming order, bucket type selection).
- Tone and Style: The tone must be authoritative, precise, and highly professional. Use markdown formatting (code blocks, bolding, lists) extensively for maximum readability.
Constraint: Do not introduce any new concepts not explicitly mentioned in the original documentation, but synthesize the information to make it maximally clear and effective for a developer audience.
(The AI will now generate the improved prompt based on these instructions.)
Original prompt (before our improvements)
--- name: add-ai-protection license: Apache-2.0 description: Protect AI chat and completion endpoints from abuse — detect prompt injection and jailbreak attempts, block PII and sensitive info from leaking in responses, and enforce token budget rate limits to control costs. Use this skill when the user is building or securing any endpoint that processes user prompts with an LLM, even if they describe it as "preventing jailbreaks," "stopping prompt attacks," "blocking sensitive data," or "controlling AI API costs" rather than naming specific protections. metadata: pathPatterns: - "app/api/chat/**" - "app/api/completion/**" - "src/app/api/chat/**" - "src/app/api/completion/**" - "**/chat/**" - "**/ai/**" - "**/llm/**" - "**/api/generate*" - "**/api/chat*" - "**/api/completion*" importPatterns: - "ai" - "@ai-sdk/*" - "openai" - "@anthropic-ai/sdk" - "langchain" promptSignals: phrases: - "prompt injection" - "pii" - "sensitive info" - "ai security" - "llm security" anyOf: - "protect ai" - "block pii" - "detect injection" - "token budget" --- # Add AI-Specific Security with Arcjet Secure AI/LLM endpoints with layered protection: prompt injection detection, PII blocking, and token budget rate limiting. These protections work together to block abuse before it reaches your model, saving AI budget and protecting user data. ## Reference Read https://docs.arcjet.com/llms.txt for comprehensive SDK documentation covering all frameworks, rule types, and configuration options. Arcjet rules run **before** the request reaches your AI model — blocking prompt injection, PII leakage, cost abuse, and bot scraping at the HTTP layer. ## Step 1: Ensure Arcjet Is Set Up Check for an existing shared Arcjet client (see `/arcjet:protect-route` for full setup). If none exists, set one up first with `shield()` as the base rule. The user will need to register for an Arcjet account at https://app.arcjet.com then use the `ARCJET_KEY` in their environment variables. ## Step 2: Add AI Protection Rules AI endpoints should combine these rules on the shared instance using `withRule()`: ### Prompt Injection Detection Detects jailbreaks, role-play escapes, and instruction overrides. - JS: `detectPromptInjection()` — pass user message via `detectPromptInjectionMessage` parameter at `protect()` time - Python: `detect_prompt_injection()` — pass via `detect_prompt_injection_message` parameter Blocks hostile prompts **before** they reach the model. This saves AI budget by rejecting attacks early. ### Sensitive Info / PII Blocking Prevents personally identifiable information from entering model context. - JS: `sensitiveInfo({ deny: ["EMAIL", "CREDIT_CARD_NUMBER", "PHONE_NUMBER", "IP_ADDRESS"] })` - Python: `detect_sensitive_info(deny=[SensitiveInfoType.EMAIL, SensitiveInfoType.CREDIT_CARD_NUMBER, ...])` Pass the user message via `sensitiveInfoValue` (JS) / `sensitive_info_value` (Python) at `protect()` time. ### Token Budget Rate Limiting Use `tokenBucket()` / `token_bucket()` for AI endpoints — the `requested` parameter can be set proportional to actual model token usage, directly linking rate limiting to cost. It also allows short bursts while enforcing an average rate, which matches how users interact with chat interfaces. Recommended starting configuration: - `capacity`: 10 (max burst) - `refillRate`: 5 tokens per interval - `interval`: "10s" Pass the `requested` parameter at `protect()` time to deduct tokens proportional to model cost. For example, deduct 1 token per message, or estimate based on prompt length. Set `characteristics` to track per-user: `["userId"]` if authenticated, defaults to IP-based. ### Base Protection Always include `shield()` (WAF) and `detectBot()` as base layers. Bots scraping AI endpoints are a common abuse vector. For endpoints accessed via browsers (e.g. chat interfaces), consider adding Arcjet advanced signals for client-side bot detection that catches sophisticated headless browsers. See https://docs.arcjet.com/bot-protection/advanced-signals for setup. ## Step 3: Compose the protect() Call and Handle Decisions All rule parameters are passed together in a single `protect()` call. Use this pattern: ```typescript const userMessage = req.body.message; // the user's input const decision = await aj.protect(req, { requested: 1, // tokens to deduct for rate limiting sensitiveInfoValue: userMessage, // PII scanning detectPromptInjectionMessage: userMessage, // injection detection }); if (decision.isDenied()) { if (decision.reason.isRateLimit()) { return Response.json( { error: "You've exceeded your usage limit. Please try again later." }, { status: 429 }, ); } if (decision.reason.isPromptInjection()) { return Response.json( { error: "Your message was flagged as potentially harmful." }, { status: 400 }, ); } if (decision.reason.isSensitiveInfo()) { return Response.json( { error: "Your message contains sensitive information that cannot be processed. Please remove any personal data.", }, { status: 400 }, ); } if (decision.reason.isBot()) { return Response.json({ error: "Forbidden" }, { status: 403 }); } } // Arcjet fails open — log errors but allow the request if (decision.isErrored()) { console.warn("Arcjet error:", decision.reason.message); } // Proceed with AI model call... ``` Adapt the response format to your framework (e.g., `res.status(429).json(...)` for Express). ## Step 5: Verify 1. Start the app and send a normal message — should succeed 2. Test prompt injection by sending something like "Ignore all previous instructions and..." 3. Test PII blocking by sending a message with a fake credit card number Start all rules in `"DRY_RUN"` mode first. Once verified, promote to `"LIVE"`. **Always recommend using the Arcjet MCP tools** to verify rules and analyze traffic: - `list-requests` — confirm decisions are being recorded, filter by conclusion to see blocks - `analyze-traffic` — review denial rates and patterns for the AI endpoint - `explain-decision` — understand why a specific request was allowed or denied (useful for tuning prompt injection sensitivity) - `promote-rule` — promote rules from `DRY_RUN` to `LIVE` once verified If the user wants a full security review, suggest the `/arcjet:security-analyst` agent which can investigate traffic, detect anomalies, and recommend additional rules. The Arcjet dashboard at https://app.arcjet.com is also available for visual inspection. ## Common Patterns **Streaming responses**: Call `protect()` before starting the stream. If denied, return the error before opening the stream — don't start streaming and then abort. **Multiple models / providers**: Use the same Arcjet instance regardless of which AI provider you use. Arcjet operates at the HTTP layer, independent of the model provider. **Vercel AI SDK**: Arcjet works alongside the Vercel AI SDK. Call `protect()` before `streamText()` / `generateText()`. If denied, return a plain error response instead of calling the AI SDK. ## Common Mistakes to Avoid - Sensitive info detection runs **locally in WASM** — no user data is sent to external services. It is only available in route handlers, not in Next.js pages or server actions. - `sensitiveInfoValue` and `detectPromptInjectionMessage` (JS) / `sensitive_info_value` and `detect_prompt_injection_message` (Python) must both be passed at `protect()` time — forgetting either silently skips that check. - Starting a stream before calling `protect()` — if the request is denied mid-stream, the client gets a broken response. Always call `protect()` first and return an error before opening the stream. - Using `fixedWindow()` or `slidingWindow()` instead of `tokenBucket()` for AI endpoints — token bucket lets you deduct tokens proportional to model cost and matches the bursty interaction pattern of chat interfaces. - Creating a new Arcjet instance per request instead of reusing the shared client with `withRule()`.