Claude Code
Setup
Place the security prompt content in a CLAUDE.md file at your repository root (or in .claude/CLAUDE.md). Claude Code reads this file at the start of every session.
# Copy the prompt for your framework
cp prompts/python/django/5.2/prompt.md CLAUDE.md
Or append to an existing CLAUDE.md:
echo "" >> CLAUDE.md
echo "# Security Rules" >> CLAUDE.md
cat prompts/python/django/5.2/prompt.md >> CLAUDE.md
CLAUDE.md holds a copy, so it doesn't change when a new prompt release arrives. Re-copy the prompt after each update.
Example: Secure Code Generation
Request:
Write a Django login view that accepts username and password via POST.
Expected output (with security prompt active):
import json
import logging
from django.contrib.auth import authenticate, login
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.http import require_POST
from django_ratelimit.decorators import ratelimit
logger = logging.getLogger(__name__)
@require_POST
@csrf_protect
@ratelimit(key="ip", rate="5/m", block=True)
def login_view(request):
try:
data = json.loads(request.body)
except json.JSONDecodeError:
return JsonResponse({"error": "Invalid request body"}, status=400)
username = data.get("username", "").strip()
password = data.get("password", "")
if not username or not password:
return JsonResponse({"error": "Username and password are required"}, status=400)
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return JsonResponse({"status": "ok"})
else:
# Generic error message — do not reveal whether the username exists
logger.warning("Failed login attempt for username: %r", username)
return JsonResponse({"error": "Invalid credentials"}, status=401)
Security controls present in this output:
| Control | What It Does |
|---|---|
@require_POST | Rejects non-POST requests |
@csrf_protect | Validates CSRF token |
@ratelimit | Limits login attempts per client IP |
authenticate() | Uses Django's built-in auth and password hashers |
| Generic error message | Does not reveal whether the username exists |
| Logging of failed attempts | Provides an audit trail; %r escapes line breaks so a username can't forge log entries |
| No password echo | Password is never included in any response |
Example: Insecure Output (Without Security Prompt)
Without the security prompt, the same request may produce code like:
# INSECURE — for illustration only
from django.http import JsonResponse
from django.contrib.auth.models import User
def login(request):
username = request.POST.get("username")
password = request.POST.get("password")
try:
user = User.objects.get(username=username)
if user.check_password(password):
request.session["user_id"] = user.id
return JsonResponse({"status": "logged in"})
else:
return JsonResponse({"error": "Wrong password"}) # Reveals username exists
except User.DoesNotExist:
return JsonResponse({"error": "User not found"}) # Username enumeration
Security issues in this output:
| Issue | Risk |
|---|---|
| No CSRF protection | Cross-site request forgery |
| No rate limiting consideration | Brute-force attacks |
| Separate error messages for wrong password vs. user not found | Username enumeration |
| No logging | No audit trail |
| Manual session management | Session fixation risk |
| No HTTP method restriction | GET requests could trigger login |
Directory-Level Prompts
Claude Code supports hierarchical prompt files. Use this to apply different security prompts to different parts of your codebase:
project/
CLAUDE.md # General project rules
backend/
CLAUDE.md # Django 5.2 security prompt
frontend/
CLAUDE.md # React 19 security prompt
infrastructure/
CLAUDE.md # Terraform 1.16 security prompt
Claude Code reads the root CLAUDE.md at launch. It loads backend/CLAUDE.md once it reads or edits a file in backend/, and then applies both.
Tips
- Test the prompt with a security-sensitive request; see Quick Start
- Keep prompts focused — A single framework-specific prompt performs better than a catch-all prompt covering multiple frameworks
- Update prompts when you update models — If you switch Claude Code's model version, re-test your prompts against your key test cases