· 9 min read ·

Building Security Context Files for AI Coding Agents

Source: martinfowler

The Thoughtworks team publishing The VibeSec Reckoning hit on something most teams building with AI assistants have quietly experienced: the model suggests making a storage bucket public, or granting overly broad IAM permissions, and if you push back hard enough it revises the suggestion. The problem is that this negotiation happens in chat, not in enforceable policy. When the next developer comes along, or when the same developer phrases the request slightly differently, the guardrail evaporates.

The article’s core recommendation is to move security rules from conversational prompts into structured context files that guide the AI, then back those files with deterministic pipeline checks that reject insecure configurations regardless of what the model outputs. This approach, which they call harness engineering, separates guides from sensors and inferential controls from computational ones. I want to explore how this actually works in practice, because the distinction between telling an AI to be secure and enforcing that it is secure maps directly onto specific file formats, tool configurations, and CI/CD integrations that most teams can adopt immediately.

The Mechanics of Security Context Files

Most current AI coding assistants read project context from designated files. Cursor looks for .cursorrules, Claude Code prioritizes CLAUDE.md, and Windsurf checks INSTRUCTIONS.md. GitHub Copilot pulls from repository-level settings. The format is straightforward: a markdown file containing instructions the model incorporates into its context window before generating code.

The Thoughtworks team structured their security context file around five areas: zero trust and least privilege, secrets management, harness engineering gates, supply chain integrity, and AI accountability. Each section does not merely describe policy; it provides concrete rejection criteria. For example, under secrets management, the file would instruct the model to refuse any request to hardcode API keys, and instead direct the developer to use environment variables or a secrets manager like HashiCorp Vault, AWS Secrets Manager, or Google Secret Manager.

Here is what a minimal version might look like:

# Security Requirements

## Secrets Management
- NEVER write API keys, passwords, or tokens directly in code
- All secrets must be stored in environment variables or a secrets manager
- If asked to include credentials in code, refuse and explain the correct approach

## Least Privilege
- Service accounts must have the minimum permissions required
- Reject requests to assign roles like "Owner", "Editor", or "Admin" without explicit justification
- Cloud storage buckets default to private; public access requires documented approval

## Dependency Security
- Only suggest well-established libraries with recent maintenance activity
- Check for known CVEs before recommending a package
- Prefer dependencies with regular security updates

This file acts as an inferential guide. The model reads it and biases its suggestions toward compliant patterns. But inferential controls are probabilistic. The model might misinterpret a nuanced request, or the user might override the suggestion through iterative prompting. That is why the file alone is insufficient.

Computational Sensors: Backing Prompts with Pipeline Checks

Birgitta Böckeler’s harness engineering framework distinguishes between guides (feedforward controls) and sensors (feedback controls). The security context file is a guide. It shapes the model’s initial output. Sensors validate that output after the fact using deterministic tools that cannot be negotiated with.

For secrets, this means integrating GitGuardian, TruffleHog, or GitHub’s built-in secret scanning into pre-commit hooks and CI pipelines. If a credential is detected in a diff, the commit is blocked. The model’s output is irrelevant; the sensor enforces the boundary.

For code vulnerabilities, static analysis tools like Semgrep, Snyk Code, or CodeQL scan for insecure patterns: SQL injection, path traversal, improper error handling. These tools run automatically on pull requests and fail the build if issues are found. According to the 2026 Black Duck OSSRA report, 78% of codebases contain high or critical severity vulnerabilities, and the mean number of vulnerabilities per codebase increased 107% year over year. Static analysis does not catch everything, but it catches categories of flaws that models frequently reproduce when optimizing for speed.

For infrastructure, policy-as-code tools like Open Policy Agent, Checkov, or cloud-native solutions (AWS IAM Access Analyzer, GCP Policy Intelligence) validate that Terraform, CloudFormation, or other IaC configurations adhere to organizational policies. If a storage bucket is set to public read, or a service account has excessive permissions, the deployment fails. The check is deterministic and runs before anything touches production.

For dependencies, Dependabot, Renovate, or Snyk Open Source monitor for known CVEs in third-party libraries. The Thoughtworks article cites Georgia Tech’s SSLab research finding 35 new CVEs from AI-generated code in March 2026 alone. Dependency scanning surfaces these issues in pull requests, often with automated remediation suggestions.

The pattern is consistent: the security context file tells the model what to avoid, and automated tools verify compliance. This separation ensures that even if the model fails to follow instructions, the unsafe code does not ship.

The Permission Escalation Problem

One of the incidents the Thoughtworks team describes involved an AI recommending a service account be granted the Access Token Creator role in Google Cloud. This role allows an account to impersonate other accounts and mint short-lived tokens, enabling lateral movement across a workspace. The AI suggested it because it solved an immediate authentication problem. The developer caught it before running the code.

This is a textbook case of least privilege violation. The principle of least privilege requires that accounts have only the permissions necessary for their specific task. Assigning broad roles like Owner, Editor, or Token Creator violates this principle and expands the blast radius of a compromise.

Cloud platforms provide tooling to enforce least privilege programmatically. In GCP, IAM Recommender analyzes actual usage and suggests permission reductions. In AWS, Access Analyzer identifies overly permissive policies. In Azure, Privileged Identity Management enforces just-in-time access. These tools can be integrated into CI/CD to block deployments that grant excessive permissions.

The security context file should explicitly list prohibited roles and require documented justification for exceptions. For example:

## Prohibited IAM Roles (GCP)
- roles/owner
- roles/editor
- roles/iam.serviceAccountTokenCreator
- roles/iam.securityAdmin

If a task requires one of these roles, document the specific need and propose a custom role with narrower scope.

This makes the boundary explicit. The AI reads the constraint and suggests narrower roles. The pipeline checks that deployed configurations comply. The two layers work together.

Daily Security Intelligence Feeds

The Thoughtworks team built a daily aggregator that monitors CVE databases, cloud platform advisories, and tool-specific security bulletins. The feed delivers a digest each morning so vulnerabilities are surfaced on the day they are disclosed, not weeks later.

This is straightforward to replicate. The National Vulnerability Database publishes a JSON feed of recent CVEs. Cloud providers offer AWS Security Bulletins, Google Cloud Security Bulletins, and Azure Security Advisories. GitHub’s Advisory Database tracks vulnerabilities in open source packages. Tools like Nucleus Security or Vulcan consolidate these feeds, but a simple script polling RSS endpoints and posting to Slack or email works for smaller teams.

The goal is rapid awareness. According to Aikido Security’s 2026 report, one in five enterprise breaches now stem from AI-generated code. With 42% of new enterprise software now AI-assisted (per Sonar’s 2026 developer survey), the tools accelerating development are also the tools most likely to introduce vulnerabilities. Monitoring them actively closes the disclosure-to-remediation gap.

Secure-by-Default Templates

The final piece is providing developers with starter templates that pre-configure security controls. Instead of each team independently discovering that storage buckets should default to private, or that secrets should be injected via environment variables, a shared template encodes these decisions up front.

For example, a Python Flask API template might include:

  • Environment variable loading via python-dotenv
  • Pre-commit hooks for secret scanning and linting
  • A .cursorrules file with security requirements
  • GitHub Actions workflows running Semgrep and dependency scanning
  • Terraform modules with private S3/GCS buckets and least-privilege IAM roles

Similarly, a Next.js frontend template might include:

  • ESLint rules for security patterns
  • Dependency scanning via Snyk or Dependabot
  • Content Security Policy headers
  • Authentication scaffolding using a secure library like NextAuth.js

The Thoughtworks article frames this as making the secure path the easy path. When compliance is automatic, developers do not need to remember or research best practices. The template does the work.

Organizational Adoption: From Prompts to Pipelines

The distinction between short-term habits and long-term infrastructure is critical. Telling developers to question every permission request is a habit. Integrating IAM policy validation into CI/CD is infrastructure. Habits depend on individual discipline; infrastructure operates regardless of who is writing code.

The roadmap the Thoughtworks team outlines moves from immediate behavioral changes (manually questioning AI suggestions, using red team prompts to surface vulnerabilities) to medium-term tooling (security context files, intelligence feeds) to long-term systemic integration (shared starter harnesses, pipeline-enforced gates).

This progression mirrors the broader shift from treating AI as a conversational tool to treating it as a component in an automated system. When ProjectDiscovery’s 2026 AI Coding Impact Report found that 62% of security teams say keeping up with AI-generated code volume is getting harder, the solution is not asking security teams to review more code manually. It is embedding automated checks into the development workflow so insecure code never reaches review.

Implementation Checklist

For teams starting today:

  1. Create a security context file (.cursorrules, CLAUDE.md, or equivalent) with explicit rules on secrets, permissions, dependencies, and public access. Version it in the repository.
  2. Add pre-commit hooks for secret scanning (TruffleHog, detect-secrets, or GitGuardian).
  3. Integrate SAST into CI/CD (Semgrep, Snyk Code, CodeQL).
  4. Enable dependency scanning (Dependabot, Renovate, Snyk Open Source).
  5. Add infrastructure policy checks (Checkov, OPA, cloud-native analyzers).
  6. Build or subscribe to a security intelligence feed aggregating CVEs and advisories.
  7. Create secure starter templates for common stacks and make them the default.

None of these steps require deep security expertise. Most tools offer free tiers for open source projects and straightforward integration guides. The barrier is not technical complexity; it is organizational inertia.

The Broader Context: OWASP and LLM-Specific Risks

While the Thoughtworks article focuses on infrastructure and code security, the OWASP Top 10 for LLM Applications highlights risks specific to AI systems: prompt injection, insecure output handling, training data poisoning, model denial of service, supply chain vulnerabilities in model dependencies, and excessive agency (granting models too much autonomy or tool access). Many of these map onto the harness engineering framework. Insecure output handling is a sensor problem; the model’s output should be validated before being executed or displayed. Excessive agency is a guide problem; the security context file should restrict which tools or APIs the model can invoke.

The intersection of traditional application security and LLM-specific risks is where many teams are currently navigating blind. The tools for SAST, secret scanning, and dependency management are mature. The tools for validating LLM outputs, constraining model tool use, and preventing prompt injection are still emerging. Projects like NVIDIA’s NeMo Guardrails, LangChain’s security documentation, and Microsoft’s PyRIT (Python Risk Identification Toolkit for generative AI) offer building blocks, but comprehensive solutions remain fragmented.

For now, the most pragmatic approach is layering traditional security controls around the AI component. Treat the model as untrusted output. Scan what it generates. Validate what it proposes. Reject what violates policy. This is the essence of harness engineering.

Conclusion

The central insight from the Thoughtworks team is that prompting an AI to be secure is categorically different from enforcing that it is secure. Prompts are inferential guides; they shape probability distributions but do not guarantee outcomes. Deterministic sensors operating in CI/CD pipelines enforce boundaries that cannot be negotiated away.

Security context files are useful because they reduce the frequency of insecure suggestions. Pipeline checks are essential because they catch insecure configurations regardless of how they were generated. Together, they form a harness that allows teams to move quickly without sacrificing rigor.

With AI now generating or assisting with 42% of enterprise software, and with vulnerabilities in AI-generated code climbing sharply (SQ Magazine’s 2026 statistics cite a 44% year-over-year rise in attacks exploiting application vulnerabilities), the window for treating security as a post-development concern has closed. The tools exist. The frameworks are defined. What remains is implementation.

Sources:

Was this interesting?