diff --git a/instructions/langchain-python.instructions.md b/instructions/langchain-python.instructions.md index 06001eb5..bdbb023c 100644 --- a/instructions/langchain-python.instructions.md +++ b/instructions/langchain-python.instructions.md @@ -210,6 +210,7 @@ Models have a finite context window measured in tokens. When designing conversat - Exact-input caching for conversations is often ineffective. Consider semantic caching (embedding-based) for repeated meaning-level queries. - Semantic caching introduces dependency on embeddings and is not universally suitable. - Cache only where it reduces cost and meets correctness requirements (e.g., FAQ bots). +- Configure caches through `set_llm_cache(...)` from `langchain_core.globals`; exact-match backends include `InMemoryCache`, `SQLiteCache`, `RedisCache`, and `UpstashRedisCache` (serverless Redis over HTTP, with optional `ttl`), and `RedisSemanticCache` is an embedding-based option. ## Best practices diff --git a/instructions/security-and-owasp.instructions.md b/instructions/security-and-owasp.instructions.md index 2ab43d40..91d2bc0b 100644 --- a/instructions/security-and-owasp.instructions.md +++ b/instructions/security-and-owasp.instructions.md @@ -279,6 +279,15 @@ app.post('/api/auth/login', loginHandler); import rateLimit from 'express-rate-limit'; const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 5 }); app.post('/api/auth/login', authLimiter, loginHandler); + +// GOOD — serverless / multi-instance: the default in-memory store is per process, +// so back the counter with shared storage (e.g. rate-limit-redis for Express, +// or a Redis-backed limiter such as @upstash/ratelimit in edge/serverless handlers) +import { Ratelimit } from '@upstash/ratelimit'; +import { Redis } from '@upstash/redis'; +const loginLimiter = new Ratelimit({ redis: Redis.fromEnv(), limiter: Ratelimit.slidingWindow(5, '15 m'), prefix: 'auth:login' }); +const { success } = await loginLimiter.limit(`login:${clientIp}`); +if (!success) return new Response('Too Many Requests', { status: 429 }); ``` ### AU6: Missing Session Regeneration on Login (Session Fixation) @@ -673,6 +682,28 @@ ALWAYS validate on server too. Use zod, joi, or class-validator. - **Severity**: IMPORTANT - **OWASP**: A05 +```typescript +// BAD — new endpoint shipped without a limiter +app.post('/api/export', exportHandler); + +// GOOD — Express: per-route limiter sized to the endpoint's cost +import rateLimit from 'express-rate-limit'; +const exportLimiter = rateLimit({ windowMs: 60 * 1000, max: 10 }); +app.post('/api/export', exportLimiter, exportHandler); + +// GOOD — Next.js route handler / serverless or edge: use a store shared across instances +// (e.g. rate-limit-redis with Express, or @upstash/ratelimit as shown) +import { Ratelimit } from '@upstash/ratelimit'; +import { Redis } from '@upstash/redis'; +const limiter = new Ratelimit({ redis: Redis.fromEnv(), limiter: Ratelimit.slidingWindow(10, '1 m') }); +export async function POST(req: Request) { + const ip = req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'anonymous'; + const { success } = await limiter.limit(ip); + if (!success) return new Response('Too Many Requests', { status: 429 }); + // ... +} +``` + ### AP2: GraphQL Without Depth Limiting - **Severity**: IMPORTANT