Skip to content
Back to Blog
Agentic AI7 min read

Claude Code Security: Writing Secure Code with AI Assistance

How Claude Code helps write secure code — input validation, authentication patterns, secret management, OWASP coverage, and security-focused CLAUDE.md configurations.

Security in the Age of AI-Generated Code

AI coding tools generate code faster than any human can review it. This speed creates a security challenge: if your AI assistant writes insecure code, it writes a lot of insecure code very quickly. Claude Code addresses this through its training emphasis on secure coding patterns, its permission model, and its ability to perform security-focused reviews.

But AI-generated security is not automatic. You need to configure Claude Code properly, provide security guidelines in your CLAUDE.md, and understand both where it excels and where it has blind spots.

How Claude Code Handles the OWASP Top 10

The OWASP Top 10 represents the most critical web application security risks. Here is how Claude Code performs against each category.

A01: Broken Access Control

Claude Code generates authentication middleware and authorization checks when prompted, but it does not add them automatically to every endpoint. You must explicitly specify your access control requirements.

CLAUDE.md security section:

## Access Control Rules
- All API endpoints require authentication by default
- Use requireAuth middleware on every route
- Admin routes use requireRole("admin")
- Users can only access their own resources unless they are admins
- Always check resource ownership: if (resource.userId !== currentUser.id) throw 403

With these instructions, Claude Code will include access control in every endpoint it generates:

router.get("/orders/:id", requireAuth, async (req, res) => {
  const order = await orderService.findById(req.params.id);
  if (!order) return res.status(404).json({ error: "Order not found" });

  // Ownership check — Claude adds this because of CLAUDE.md instructions
  if (order.userId !== req.user.id && req.user.role !== "admin") {
    return res.status(403).json({ error: "Forbidden" });
  }

  res.json({ success: true, data: order });
});

A02: Cryptographic Failures

Claude Code knows to use bcrypt or argon2 for password hashing, TLS for transport, and secure random generators for tokens. It will not suggest MD5 or SHA-1 for password storage.

# Claude Code generates secure password handling by default
from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")

def hash_password(password: str) -> str:
    return pwd_context.hash(password)

def verify_password(plain: str, hashed: str) -> bool:
    return pwd_context.verify(plain, hashed)

A03: Injection

Claude Code consistently generates parameterized queries instead of string concatenation. This is one of its strongest security behaviors.

# Claude Code always generates parameterized queries
result = await db.execute(
    select(User).where(User.email == email)  # SQLAlchemy ORM — safe
)

# Even with raw SQL, it uses parameters
result = await db.execute(
    text("SELECT * FROM users WHERE email = :email"),
    {"email": email}
)

However, if your codebase has existing patterns that use string interpolation, Claude Code might follow those patterns unless your CLAUDE.md explicitly prohibits it:

## Security: SQL
- NEVER use f-strings or string concatenation in SQL queries
- ALWAYS use parameterized queries or ORM methods
- When reviewing code, flag any string interpolation in SQL

A04: Insecure Design

This category is about architectural security — and it is where Claude Code needs the most human guidance. Claude Code does not know your threat model, your compliance requirements, or your business-specific security needs.

Document security requirements in CLAUDE.md:

## Security Architecture
- All PII must be encrypted at rest (use application-level encryption for email, phone)
- API rate limiting: 100 requests per minute per IP for public endpoints
- Session tokens expire after 24 hours
- Password reset tokens expire after 1 hour
- Failed login attempts: lock account after 5 failures for 15 minutes

A05: Security Misconfiguration

Claude Code generates secure defaults for framework configurations:

// Express security middleware — Claude Code includes these by default
import helmet from "helmet";
import cors from "cors";
import rateLimit from "express-rate-limit";

app.use(helmet());  // Sets security headers
app.use(cors({
  origin: process.env.ALLOWED_ORIGINS?.split(",") || [],
  credentials: true,
}));
app.use(rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
}));

A06: Vulnerable and Outdated Components

Claude Code can identify outdated dependencies:

Review package.json for outdated dependencies with known vulnerabilities.

However, it does not have real-time CVE data. For production vulnerability scanning, use dedicated tools like npm audit, Snyk, or Dependabot alongside Claude Code.

A07: Identification and Authentication Failures

Claude Code generates strong authentication patterns:

// JWT with proper configuration
const token = jwt.sign(
  { userId: user.id, role: user.role },
  process.env.JWT_SECRET!,
  {
    expiresIn: "24h",
    issuer: "myapp",
    audience: "myapp-api",
  }
);

// Token verification with all checks
const decoded = jwt.verify(token, process.env.JWT_SECRET!, {
  issuer: "myapp",
  audience: "myapp-api",
  algorithms: ["HS256"],
});

A08: Software and Data Integrity Failures

Claude Code adds integrity checks when prompted:

# Webhook signature verification
import hmac
import hashlib

def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

A09: Security Logging and Monitoring Failures

Add logging requirements to CLAUDE.md:

## Security Logging
- Log all authentication events (login, logout, failed attempts)
- Log all authorization failures (403 responses)
- Log all input validation failures
- Never log passwords, tokens, or PII
- Use structured logging format: { timestamp, level, event, userId, ip, details }

A10: Server-Side Request Forgery (SSRF)

Claude Code knows to validate URLs before making server-side requests:

from urllib.parse import urlparse
import ipaddress

BLOCKED_HOSTS = {"localhost", "127.0.0.1", "0.0.0.0", "169.254.169.254"}

def validate_url(url: str) -> bool:
    parsed = urlparse(url)
    if parsed.hostname in BLOCKED_HOSTS:
        return False
    try:
        ip = ipaddress.ip_address(parsed.hostname)
        if ip.is_private or ip.is_loopback or ip.is_link_local:
            return False
    except ValueError:
        pass  # Not an IP address — hostname will be resolved
    return parsed.scheme in ("http", "https")

Security-Focused CLAUDE.md Template

# Security Guidelines

## Input Validation
- Validate ALL inputs with zod (TypeScript) or Pydantic (Python)
- Set maximum lengths for all string inputs
- Whitelist allowed characters for usernames, slugs
- Reject requests that fail validation with 422 status code

## Authentication
- Use bcrypt (cost=12) or argon2id for password hashing
- JWT tokens expire after 24 hours
- Refresh tokens expire after 30 days
- Invalidate all tokens on password change
- Rate limit login attempts: 5 per minute per IP

## Authorization
- Every endpoint must check resource ownership
- Use middleware for role-based access control
- Never trust client-side role/permission claims

## Data Protection
- Never return password hashes in API responses
- Exclude sensitive fields from list endpoints
- Use select() to fetch only needed columns
- Sanitize error messages — never expose stack traces

## Secrets
- Never hardcode secrets, API keys, or credentials
- Access secrets only through environment variables
- Use process.env.SECRET_NAME pattern
- Never log secrets or include them in error messages

Claude Code's Permission Model as a Security Feature

Claude Code's permission system is itself a security measure:

  • Bash commands require approval — Claude Code cannot run arbitrary shell commands without your permission
  • Write operations require approval — File creation and modification need confirmation
  • Tool restrictions — You can limit Claude Code to read-only tools for review tasks
{
  "permissions": {
    "allow": [
      "Bash(npm test*)",
      "Bash(npx tsc --noEmit)"
    ],
    "deny": [
      "Bash(rm -rf*)",
      "Bash(curl*)",
      "Bash(wget*)"
    ]
  }
}

Security Review Workflow

A comprehensive security review with Claude Code:

1. Review all API endpoints for authentication and authorization gaps
2. Check all database queries for injection vulnerabilities
3. Verify all user inputs are validated before use
4. Check for sensitive data exposure in API responses
5. Review error handling — ensure no stack traces or internal details are exposed
6. Check for hardcoded secrets or credentials
7. Verify CORS configuration is restrictive
8. Check rate limiting on public endpoints

Claude Code can execute this entire checklist against your codebase, reading every relevant file and reporting findings with specific line numbers and fix suggestions.

Conclusion

Claude Code is a strong ally for writing secure code, particularly for injection prevention, authentication patterns, and input validation. Its effectiveness increases dramatically when you provide security requirements in CLAUDE.md. However, it is not a substitute for dedicated security tooling (SAST, DAST, dependency scanning) or professional security audits. Use Claude Code as your first line of defense — catching common vulnerabilities during development — while maintaining a comprehensive security program for production systems.

Share this article
N

NYC News

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.