· 5 min read ·

Building Security Guardrails Into Your AI Coding Workflow

Source: martinfowler

The speed at which AI coding assistants can scaffold applications has created a new category of security problem. When you prompt Claude, Copilot, or Cursor to build something quickly, the generated code often takes shortcuts that would make a security engineer wince. The VibeSec Reckoning article from Thoughtworks documents this pattern: developers at the consulting firm noticed that AI agents consistently recommended privileged Docker containers, overly permissive CORS policies, and disabled security headers in their marketing application builds.

The velocity gains from AI-assisted coding are real, but they expose a fundamental tension. Language models are trained on vast amounts of public code, much of which was written for tutorials, proof-of-concepts, or by developers learning. This training data favors configurations that work over configurations that are secure. When you ask an AI to “make this work,” it reaches for the patterns that have the highest probability of immediate success.

The Configuration File Approach

One practical defense is a security context file that lives in your project repository. Tools like Claude Code support CLAUDE.md files that inject project-specific instructions into every AI interaction. The Thoughtworks team recommends treating this as a security policy document.

Here’s what a basic security context might look like:

# Security Requirements

## Docker
- Never use privileged: true
- Always run as non-root user with USER directive
- Explicitly set read-only root filesystem where possible
- Use specific base image tags, never :latest

## API Security  
- CORS: whitelist specific origins, no wildcards
- Always require authentication middleware before routes
- Rate limiting required on all public endpoints
- Content-Security-Policy header mandatory

## Dependencies
- Lock file must be committed
- No packages with known high/critical CVEs
- Automated dependency updates via Dependabot or Renovate

The file works because it changes the context window. Instead of the AI choosing between all possible implementations, it now has explicit constraints. When you ask it to containerize an application, the instruction “never use privileged: true” is sitting right there in the prompt.

This approach has limitations. AI models can still ignore instructions, especially when the request conflicts with the constraint. If you ask it to do something that requires elevated privileges, it might recommend privileged mode despite the rule. The context file is a guardrail, not a guarantee.

Permission Gating

Another layer involves controlling what the AI can actually execute. Research from Stanford on AI code security found that one of the highest-risk moments is when a coding assistant requests permission to run shell commands or modify security-sensitive files.

Modern AI coding tools implement permission systems. Claude Code asks before running bash commands. GitHub Copilot Workspace requires approval for file changes. The pattern that helps is treating these permission requests as security reviews, not interruptions.

When an AI asks to run npm install or modify a Dockerfile, pause and check:

  • Does the command match what you asked for?
  • Are there unexpected flags (like --ignore-scripts or --force)?
  • Is it touching files outside the expected scope?
  • Are any credentials or secrets being passed as arguments?

The Thoughtworks piece emphasizes being particularly cautious with requests that disable security features. If the AI wants to add --no-verify to a git commit or --insecure to a curl command, that’s a red flag worth investigating.

Secure-by-Default Templates

The third approach is shifting left further by providing the AI with secure starter templates. Instead of asking it to build something from scratch, you give it a hardened baseline.

For example, rather than prompting “create a Dockerfile for this Node app,” you maintain a template:

FROM node:20.14.0-alpine AS base
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY --chown=nodejs:nodejs . .
USER nodejs
EXPOSE 3000
CMD ["node", "server.js"]

Then you prompt: “adapt this Dockerfile template for my Express application.” The AI now modifies a secure baseline rather than generating from scratch. It preserves the non-root user, the specific base image tag, and the production-only dependencies because they’re already there.

OWASP’s guidance on container security aligns with this template approach: explicit user switching, minimal base images, and no credential copying are easier to maintain than audit.

The same pattern applies to other configuration files. Keep hardened templates for nginx configs, GitHub Actions workflows, Terraform modules, or whatever your stack uses. Version them in a shared repository. When you need the AI to generate one, start from the template.

Daily Security Intelligence

The Thoughtworks team also recommends creating a security intelligence feed. This matters because the threat landscape changes faster than AI training data. A model trained six months ago doesn’t know about the vulnerability disclosed last week.

Practical implementation:

The workflow becomes: AI generates code, automated SAST tool scans it, results feed back to the developer before merge. Tools like Semgrep can run in CI and block PRs that introduce patterns like hardcoded secrets or SQL injection vectors.

The Broader Pattern

What makes this challenge interesting is that it inverts traditional application security. Usually you secure the application; now you also need to secure the process that creates the application. The AI is part of your build pipeline, and build pipelines need security controls.

The approaches here stack. A security context file sets policy, permission gating enforces human review at critical moments, templates provide secure defaults, and scanning catches what slips through. No single layer is sufficient, but together they reduce the surface area.

The tradeoff is friction. Every guardrail slows down the prototyping speed that made AI coding attractive in the first place. The balance depends on context. A weekend side project and a healthcare application processing PHI require different levels of rigor. The key is making the friction intentional rather than discovering the security gaps in production.

Current AI models will likely improve at security over time as training data includes more hardened examples and model builders add safety fine-tuning. Until then, treating AI coding assistants as junior developers who need code review remains the pragmatic approach. You wouldn’t merge a junior’s PR without review; the same applies to AI-generated code, regardless of how confident the model sounds.

Was this interesting?