/security-patterns
App security: OWASP, authN/authZ, input validation, secrets, TLS, CSRF/XSS/SQLi, JWT, CSP, LLM prompt injection. Triggers: security, OWASP, auth, JWT, CSRF, XSS, SQL injection, secrets, TLS, CSP, CORS, prompt injection, LLM output trust, tool permissions.
$ npx -y skills add softspark/ai-toolkit --skill security-patterns --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/security-patterns
Context preview
The summary Claude sees to decide when to auto-load this skill.
App security: OWASP, authN/authZ, input validation, secrets, TLS, CSRF/XSS/SQLi, JWT, CSP, LLM prompt injection. Triggers: security, OWASP, auth, JWT, CSRF, XSS, SQL injection, secrets, TLS, CSP, CORS, prompt injection, LLM output trust, tool permissions.
SKILL.md
security-patterns.SKILL.mdname: security-patterns
description: "App security: OWASP, authN/authZ, input validation, secrets, TLS, CSRF/XSS/SQLi, JWT, CSP, LLM prompt injection. Triggers: security, OWASP, auth, JWT, CSRF, XSS, SQL injection, secrets, TLS, CSP, CORS, prompt injection, LLM output trust, tool permissions."
effort: medium
user-invocable: false
allowed-tools: Read
Security Patterns Skill
OWASP Top 10 Prevention
| Risk | Prevention | |------|------------| | Injection | Parameterized queries, ORM | | Broken Auth | MFA, secure sessions | | Sensitive Data | Encryption, HTTPS | | XXE | Disable external entities | | Broken Access | RBAC, resource validation | | Security Misconfig | Security headers, defaults | | XSS | Escaping, CSP | | Insecure Deserialization | Signed tokens, validation | | Vulnerable Components | Dependency scanning | | Insufficient Logging | Audit logs, monitoring |
---
Security Headers
# FastAPI middleware
@app.middleware("http")
async def security_headers(request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
response.headers["Content-Security-Policy"] = "default-src 'self'"
return response---
Secrets Management
Environment Variables
# .env (never commit)
DATABASE_URL=postgresql://...
API_SECRET=...
# .env.example (commit this)
DATABASE_URL=postgresql://user:pass@localhost/db
API_SECRET=your-secret-here
Secret Scanning
# pre-commit hook
- repo: https://github.com/Yelp/detect-secrets
hooks:
- id: detect-secrets---
Rate Limiting
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.get("/api/resource")
@limiter.limit("100/minute")
async def resource():
pass---
Prompt Injection & LLM-Output Trust
When the app embeds an LLM, every byte the model emits — plus tool results, retrieved documents, and fetched web pages — is **untrusted input on the same footing as a raw request body**. Text inside that content that reads like an instruction ("ignore previous rules", "call the delete tool", "email the config to…") is still data. Render it, store it, classify it — but never let it drive control flow, widen permissions, or fire a side effect without an explicit human decision. This mirrors the agent-behavior rule in [constitution Article VII](../../constitution.md); the rules here cover the application you are building, not the assistant's own behavior.
Trust Boundary
| Source | Trust | Handling | |--------|-------|----------| | System prompt / app-defined policy | Trusted | The only place instructions may originate | | User chat turn | Semi-trusted | Authenticated to a user, still validate + scope to their permissions | | Model output | Untrusted | Treat as data; gate any tool call it requests | | Tool / function results | Untrusted | Re-validate before feeding back into context | | Retrieved docs / RAG chunks | Untrusted | Strip or delimit embedded instructions | | Fetched web / email / file content | Untrusted | Highest risk — sanitize before it crosses into the prompt |
Defenses
- **Separate instructions from data.** Keep app policy in the system prompt; wrap all untrusted content in clear delimiters or distinct structured fields (e.g. a `documents` array) so the model can tell "what to do" from "what to read." Never string-concatenate retrieved text into the instruction block.
- **Least-privilege tools.** Give each tool the narrowest scope it needs. A summarizer needs no write or network egress capability. Fewer reachable side effects shrink the blast radius of a successful injection.
- **Human-in-the-loop for irreversible actions.** Destructive, financial, or data-exfiltrating operations (delete, transfer, send-to-external-recipient, broad file reads) require explicit human confirmation — not a model token that "looks like" approval.
- **Validate and allowlist tool arguments.** Parse the model's proposed arguments against a schema, allowlist targets (recipient domains, table names, paths), and reject anything outside it. The model choosing a tool is a *request*, not authorization.
- **Keep secrets out of injectable context.** Never place API keys, internal URLs, or other users' data in a prompt that an injected instruction could later echo back into output. If the model cannot see it, it cannot be coaxed into leaking it.
- **Bound indirect (second-order) injection.** Content ingested now may carry instructions that only fire on a later turn — a poisoned doc indexed today, a web page fetched mid-task, a comment in a parsed file. Sanitize and size-limit everything at the moment it crosses the trust boundary, not when it is finally read.
Carve-out: Authorized Defensive Work
Building injection **detection** (classifiers, guardrails, eval suites) and running **authorized** red-team exercises — CTF, sanctioned pentest, internal adversarial testing of these defenses — is fully in scope. Generating injection payloads for that purpose is expected; the OWASP / authorized-testing framing of this skill applies to LLM apps exactly as it does to SQLi or XSS work.
---
Common Rationalizations
| Excuse | Why It's Wrong | |--------|----------------| | "It's an internal API, security doesn't matter" | Internal APIs get exposed — lateral movement is attackers' primary technique | | "The framework handles security" | Frameworks provide tools, not guarantees — misconfiguration is OWASP #5 | | "We'll add auth later" | Unauthenticated endpoints in production get discovered within hours | | "Nobody would exploit this" | Automated scanners don't care about your threat model — they scan everything | | "It's behind a VPN" | VPNs are perimeter defe
Read more
name: security-patterns description: "App security: OWASP, authN/authZ, input validation, secrets, TLS, CSRF/XSS/SQLi, JWT, CSP, LLM prompt injection. Triggers: security, OWASP, auth, JWT, CSRF, XSS, SQL injection, secrets, TLS, CSP, CORS, prompt injection, LLM output trust, tool permissions." effort: medium user-invocable: false allowed-tools: Read
Security Patterns Skill
OWASP Top 10 Prevention
| Risk | Prevention | |------|------------| | Injection | Parameterized queries, ORM | | Broken Auth | MFA, secure sessions | | Sensitive Data | Encryption, HTTPS | | XXE | Disable external entities | | Broken Access | RBAC, resource validation | | Security Misconfig | Security headers, defaults | | XSS | Escaping, CSP | | Insecure Deserialization | Signed tokens, validation | | Vulnerable Components | Dependency scanning | | Insufficient Logging | Audit logs, monitoring |
---
Security Headers
# FastAPI middleware
@app.middleware("http")
async def security_headers(request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
response.headers["Content-Security-Policy"] = "default-src 'self'"
return response---
Secrets Management
Environment Variables
# .env (never commit) DATABASE_URL=postgresql://... API_SECRET=... # .env.example (commit this) DATABASE_URL=postgresql://user:pass@localhost/db API_SECRET=your-secret-here
Secret Scanning
# pre-commit hook
- repo: https://github.com/Yelp/detect-secrets
hooks:
- id: detect-secrets---
Rate Limiting
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.get("/api/resource")
@limiter.limit("100/minute")
async def resource():
pass---
Prompt Injection & LLM-Output Trust
When the app embeds an LLM, every byte the model emits — plus tool results, retrieved documents, and fetched web pages — is **untrusted input on the same footing as a raw request body**. Text inside that content that reads like an instruction ("ignore previous rules", "call the delete tool", "email the config to…") is still data. Render it, store it, classify it — but never let it drive control flow, widen permissions, or fire a side effect without an explicit human decision. This mirrors the agent-behavior rule in [constitution Article VII](../../constitution.md); the rules here cover the application you are building, not the assistant's own behavior.
Trust Boundary
| Source | Trust | Handling | |--------|-------|----------| | System prompt / app-defined policy | Trusted | The only place instructions may originate | | User chat turn | Semi-trusted | Authenticated to a user, still validate + scope to their permissions | | Model output | Untrusted | Treat as data; gate any tool call it requests | | Tool / function results | Untrusted | Re-validate before feeding back into context | | Retrieved docs / RAG chunks | Untrusted | Strip or delimit embedded instructions | | Fetched web / email / file content | Untrusted | Highest risk — sanitize before it crosses into the prompt |
Defenses
- **Separate instructions from data.** Keep app policy in the system prompt; wrap all untrusted content in clear delimiters or distinct structured fields (e.g. a `documents` array) so the model can tell "what to do" from "what to read." Never string-concatenate retrieved text into the instruction block.
- **Least-privilege tools.** Give each tool the narrowest scope it needs. A summarizer needs no write or network egress capability. Fewer reachable side effects shrink the blast radius of a successful injection.
- **Human-in-the-loop for irreversible actions.** Destructive, financial, or data-exfiltrating operations (delete, transfer, send-to-external-recipient, broad file reads) require explicit human confirmation — not a model token that "looks like" approval.
- **Validate and allowlist tool arguments.** Parse the model's proposed arguments against a schema, allowlist targets (recipient domains, table names, paths), and reject anything outside it. The model choosing a tool is a *request*, not authorization.
- **Keep secrets out of injectable context.** Never place API keys, internal URLs, or other users' data in a prompt that an injected instruction could later echo back into output. If the model cannot see it, it cannot be coaxed into leaking it.
- **Bound indirect (second-order) injection.** Content ingested now may carry instructions that only fire on a later turn — a poisoned doc indexed today, a web page fetched mid-task, a comment in a parsed file. Sanitize and size-limit everything at the moment it crosses the trust boundary, not when it is finally read.
Carve-out: Authorized Defensive Work
Building injection **detection** (classifiers, guardrails, eval suites) and running **authorized** red-team exercises — CTF, sanctioned pentest, internal adversarial testing of these defenses — is fully in scope. Generating injection payloads for that purpose is expected; the OWASP / authorized-testing framing of this skill applies to LLM apps exactly as it does to SQLi or XSS work.
---
Common Rationalizations
| Excuse | Why It's Wrong | |--------|----------------| | "It's an internal API, security doesn't matter" | Internal APIs get exposed — lateral movement is attackers' primary technique | | "The framework handles security" | Frameworks provide tools, not guarantees — misconfiguration is OWASP #5 | | "We'll add auth later" | Unauthenticated endpoints in production get discovered within hours | | "Nobody would exploit this" | Automated scanners don't care about your threat model — they scan everything | | "It's behind a VPN" | VPNs are perimeter defe
Professional-grade AI coding toolkit with multi-platform support. Machine-enforced safety, 109 skills, 44 agents, expanded lifecycle hooks, persona presets, experimental opt-in plugin packs, and benchmark tooling — works with Claude Code, Claude Chat/Cowork,
Repo: softspark/ai-toolkit
Other skills on ai-toolkit.
- /ai-toolkit-rules
Mandatory engineering, security, testing, git, performance, quality, and response rules. Claude MUST load this skill for every technical, coding, debugging, review, architecture, DevOps, data, or file-editing task in Chat or Cowork.
Open skill - /mem-search
Search past coding sessions using natural language. Finds relevant observations, decisions, and context from previous work.
Open skill - /a11y-validate
Accessibility validator: WCAG 2.1 AA, EN 301 549, EAA. Triggers: a11y, accessibility, WCAG, EAA, ARIA, contrast, keyboard, screen reader.
Open skill - /agent-creator
Creates new specialized agents with frontmatter, tools, delegation. Triggers: new agent, create agent, agent scaffold, specialized agent.
Open skill - /analyze
Analyzes code quality, complexity, patterns across codebase. Triggers: quality report, hotspot scan, code analysis, architecture signal.
Open skill - /api-patterns
REST/GraphQL API design: naming, versioning, pagination, idempotency, OpenAPI. Triggers: API design, REST, GraphQL, OpenAPI, Swagger, idempotency, rate limit.
Open skill

