Yak Docs
Reference

Security

This page documents the security model of the Yak SDK and best practices for secure integration.

Overview

The Yak SDK is designed with security in mind. The widget runs in an iframe hosted on chat.yak.io, communicating with your application via postMessage. This architecture provides several security benefits:

  • Origin isolation – The iframe is sandboxed from your application's DOM
  • Controlled communication – All messages are validated against expected origins
  • Allowlisted tools – Only explicitly allowed tools can be executed

Communication Flow

┌─────────────────────┐        postMessage        ┌─────────────────────┐
│   Your Application  │◄────────────────────────►│   Yak Chat Widget   │
│   (host origin)     │    (origin validated)     │   (chat.yak.io)     │
└─────────────────────┘                           └─────────────────────┘

         │ fetch (same-origin)

┌─────────────────────┐
│   /api/yak          │
│   Server Handlers   │
└─────────────────────┘

Origin Validation

The SDK validates all incoming postMessage events against allowed origins:

  1. The environment-determined iframe origin (localhost → http://localhost:3001, dev → https://chat.yak.supply, production → https://chat.yak.io)
  2. Your application's own origin (for same-origin messages)

Messages from unexpected origins are rejected and logged. The iframe origin is determined automatically based on your environment and cannot be configured—this ensures communication only happens with trusted Yak domains.

Redirect Protection

The SDK includes built-in protection against open redirect attacks. When the chat widget requests a redirect, the SDK validates the path:

  • ✅ Relative paths (/dashboard, /settings)
  • ✅ Hash and query paths (#section, ?tab=profile)
  • ✅ Same-origin absolute URLs
  • ❌ External domain URLs (blocked)
// These redirects are allowed
"/dashboard"           // ✅ Relative path
"/posts/123"           // ✅ Relative path
"#comments"            // ✅ Hash path
"?filter=active"       // ✅ Query path

// These redirects are blocked
"https://evil.com"     // ❌ External domain
"//evil.com/phish"     // ❌ Protocol-relative URL

If you need custom redirect behavior, provide your own handler:

<YakProvider
  appId="your-app"
  onRedirect={(path) => {
    // Implement your own validation if needed
    if (isAllowedPath(path)) {
      router.push(path);
    }
  }}
/>

Tool Security

Allowlisting Procedures

When using the tRPC adapter, you must explicitly allowlist which procedures can be invoked as tools:

import { createTRPCToolAdapter } from "@yak-io/trpc";

const toolAdapter = createTRPCToolAdapter({
  router: appRouter,
  createContext,
  // Only these procedures can be called
  allowedProcedures: [
    "orders.list",
    "orders.getById",
    "products.search",
  ],
});

Never use a wildcard or allow all procedures. The allowlist ensures only safe, read-oriented operations are exposed to the AI.

Tool Execution Context

Tool calls receive the original Request object, allowing you to:

  • Validate authentication via cookies/headers
  • Apply rate limiting
  • Log tool invocations
const toolAdapter = createTRPCToolAdapter({
  router: appRouter,
  createContext: async ({ req }) => {
    // Your existing auth logic
    const session = await getSession(req);
    if (!session) throw new Error("Unauthorized");
    return { user: session.user };
  },
  allowedProcedures: ["..."],
});

Prototype Pollution Protection

The SDK includes protection against prototype pollution attacks in dynamic property access paths:

// These paths are blocked
"__proto__.polluted"    // ❌ Blocked
"constructor.prototype" // ❌ Blocked
"prototype.isAdmin"     // ❌ Blocked

Data Flow Security

What Data Flows to the Widget

Data TypeDirectionDescription
Page ContextHost → WidgetCurrent URL, page title, visible text
Route ManifestHost → WidgetList of available routes
Tool ManifestHost → WidgetTool names, descriptions, schemas
Tool ResultsHost → WidgetResults of executed tools
PromptsWidget → HostUser messages (for redirect/tool calls)

What Data Does NOT Flow

  • Cookies – Not sent to the iframe
  • localStorage – Not accessible from the iframe
  • DOM access – The iframe cannot read your page's DOM
  • Auth tokens – Never sent to the widget

Page context (visible text) is extracted from your page and sent to the AI for contextual assistance. If you have sensitive information on the page, consider what's visible to users.

Server-Side Security

Authentication

Always authenticate tool requests on the server:

// app/api/yak/route.ts
import { createNextYakHandler } from "@yak-io/nextjs/server";
import { auth } from "@clerk/nextjs/server";

export const { GET, POST } = createNextYakHandler({
  routes: scanRoutes("./src/app"),
  tools: createTRPCToolAdapter({
    router: appRouter,
    createContext: async ({ req }) => {
      const { userId } = await auth();
      if (!userId) throw new Error("Unauthorized");
      return { userId };
    },
    allowedProcedures: ["..."],
  }),
});

Rate Limiting

Consider adding rate limiting to your tool endpoint:

// Using a rate limiter (example with upstash)
import { Ratelimit } from "@upstash/ratelimit";

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, "10 s"),
});

export async function POST(req: Request) {
  const ip = req.headers.get("x-forwarded-for") ?? "anonymous";
  const { success } = await ratelimit.limit(ip);
  
  if (!success) {
    return new Response("Too many requests", { status: 429 });
  }
  
  return handler.POST(req);
}

Input Validation

Tool inputs are validated against the JSON Schema you define. Always validate on the server side as well:

// In your tRPC procedures
export const ordersRouter = router({
  list: protectedProcedure
    .input(z.object({
      limit: z.number().min(1).max(100).default(10),
      status: z.enum(["pending", "shipped", "delivered"]).optional(),
    }))
    .query(async ({ ctx, input }) => {
      // Input is validated by Zod
      return db.orders.findMany({
        where: { userId: ctx.userId, status: input.status },
        take: input.limit,
      });
    }),
});

Production Checklist

Before deploying to production, verify:

  • Tool allowlist – Only safe procedures are exposed
  • Authentication – Tool requests require valid auth
  • Rate limiting – Prevent abuse of tool endpoints
  • HTTPS – All endpoints use HTTPS
  • CSP headers – Allow frame-src chat.yak.io if using CSP
  • Logging – Tool invocations are logged for audit

Content Security Policy

If your application uses Content Security Policy headers, add the following:

frame-src https://chat.yak.io;

This allows the Yak widget iframe to load while maintaining your CSP protections.

Reporting Security Issues

If you discover a security vulnerability in the Yak SDK, please report it responsibly:

  1. Do not create a public GitHub issue
  2. Email security@yak.io with details
  3. Include steps to reproduce if possible

We take security seriously and will respond promptly to all reports.

On this page