plugins/smedjen/skills/api-security/SKILL.md
Rate limiting, input validation, CORS, security headers, API keys, and request sanitization.
npx skillsauth add hjemmesidekongen/ai api-securityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Defense-in-depth: rate limiting stops abuse, validation stops bad data, headers stop browser-based attacks, sanitization stops injection.
Token bucket — users accumulate tokens over time. Good for bursty traffic. Sliding window — rolling time window, Redis-backed with ZADD/ZCOUNT. More uniform enforcement.
Apply at multiple levels: per-IP (unauthenticated), per-user (authenticated), per-endpoint (login, OTP, password reset). Return 429 with Retry-After header.
Validate at the API boundary before touching business logic. zod (TypeScript): type-safe schemas, infers TS types, preferred. joi (JS): runtime-only, battle-tested. class-validator (NestJS): decorator-based DTOs with class-transformer.
Validate: shape, types, string formats, numeric ranges, enum membership, array length. Reject unknown fields. Return structured 400 with field-level error details.
Explicit allowlist only — never * with credentials. Match origin against the list; set Access-Control-Allow-Origin to the matched origin, not *. Set Access-Control-Max-Age (e.g., 86400) to reduce preflights. Separate dev/staging/production origins in config, not in code.
helmet() sets 11 headers by default. Critical: Content-Security-Policy, Strict-Transport-Security (1yr + includeSubDomains), X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer. CSP requires per-project tuning — start with default-src 'self'.
SQL injection — parameterized queries or ORM always. XSS — sanitize HTML with sanitize-html (server) or DOMPurify (client) when storing user HTML. Path traversal — normalize paths, never build file paths from raw user input. NoSQL injection — strip MongoDB operators from user input ($where, $gt).
Body size limits (tune from Express's 100kb default). HTTPS enforced at the load balancer. IP allowlisting for admin/internal routes. Structured logging on all 4xx/5xx; alert on anomalous error rates.
No rate limiting on auth endpoints, wildcard CORS with credentials, raw SQL concatenation, logging request bodies with credentials, HTTP in production, missing body size limits.
See references/process.md for Redis rate limiter, zod middleware, Helmet config, CORS setup, sanitization helpers, API key management, and NestJS guard patterns.
development
Creates a brand from scratch through market research and interactive sparring. Runs competitive research via Perplexity, then guides the user through positioning, audience, voice, values, and content pillars. Produces the full brand guideline set at .ai/brand/{name}/. Use when building a new brand, defining brand strategy for a product, or when /våbenskjold:create is invoked.
testing
Loads brand guidelines from .ai/brand/{name}/ and makes them available to the current context. Progressive disclosure: L1 confirms brand exists, L2 loads summary, L3 loads specific files on demand. Use when a downstream skill or user needs brand context, or when /våbenskjold:apply is invoked.
documentation
Guided reinvention of an existing brand guideline. Loads current brand from .ai/brand/{name}/, identifies what to keep vs change, and walks the user through targeted evolution. Preserves brand equity while updating positioning, voice, or values. Use when refreshing a brand or when /våbenskjold:evolve is invoked.
development
Codifies an existing brand from materials, samples, and references. Analyzes provided content to extract voice patterns, values, and positioning. Produces the same guideline format as brand-strategy. Use when a brand already exists but isn't documented, or when /våbenskjold:audit is invoked.