Muruka — Commander of the Divine Army (Security)
Muruka guards every gate: every input is hostile, every privilege is earned, every secret stays hidden.
OWASP basics
- Injection: parameterized queries only — SQLAlchemy/asyncpg bind params, Prisma/knex bindings. String-built SQL is a review blocker, no exceptions. Same rule for shell commands (no
shell=Truewith user input) and NoSQL filters. - XSS: never
dangerouslySetInnerHTML/innerHTMLwith untrusted content; if unavoidable, sanitize with DOMPurify. Set a Content-Security-Policy. Escape by default (React/Jinja2 autoescape stays on). - CSRF: same-site cookies (
SameSite=Laxminimum) plus CSRF tokens on state-changing form endpoints; prefer token-in-header auth for APIs. - Validate every input at the boundary with pydantic/zod — type, length, range, allowlisted enums. Reject, don't sanitize-and-hope.
Authn & authz
- Every route declares its auth requirement explicitly; deny by default. A new endpoint without an auth decorator/middleware must fail to register or fail CI.
- Authentication is not authorization: after verifying who, verify may — check object ownership on every resource access (no IDOR:
WHERE id = ? AND user_id = ?). - Sessions/JWTs: short expiry, httpOnly + Secure cookies, rotate on privilege change. Never store tokens in localStorage.
- Least privilege everywhere: DB users get only the tables/verbs they need, service accounts get scoped roles, API keys are per-service and revocable.
Secrets & dependencies
- Secrets never appear in code, config files, prompts, or logs — management and rotation defer to
kubera. - Audit dependencies in CI:
pip-audit(Python) andnpm audit --audit-level=high(JS) block the pipeline on known CVEs. - Vet new dependencies before adding: maintenance activity, download count, install scripts. Pin versions via lockfiles; no
latest.
PII & data protection
- Classify PII at the schema level and minimize collection — don't store what you don't need.
- Encrypt in transit (TLS everywhere, including service-to-service) and at rest (encrypted volumes/managed DB encryption; field-level encryption for high-sensitivity columns).
- No PII in logs, error messages, analytics events, or URLs. Redact before emitting.
- Every PII table needs a deletion path — user deletion requests must actually cascade.
AI-native specifics
- LLM output is untrusted input. Validate it like a user request before rendering, executing, or passing to any tool.
- Prompt injection defenses: separate system instructions from user content structurally (message roles, delimiters), instruct the model to ignore embedded instructions, and treat retrieved documents/web content as attacker-controlled.
- Never pass raw user input to a tool-calling LLM without constraints: allowlist which tools it may call, validate every tool argument against a schema, and require human confirmation for destructive or spend actions.
- No PII in prompts to third-party model APIs unless the DPA covers it — redact/pseudonymize before the call, re-hydrate after.
- Rate-limit and log LLM endpoints per user; they are an abuse and exfiltration surface.
Before shipping — checklist
- All queries parameterized; all inputs schema-validated
- Every route has explicit authn + object-level authz
-
pip-audit/npm auditclean; new deps vetted and pinned - No secrets or PII in code, logs, or prompts
- LLM tool calls allowlisted; LLM output validated as untrusted