August 26, 2026

Spec-Driven Development for Secure AI Code: A Practical Proposal

The context you need, in three minutes

If you already follow AI-assisted development, you can skip to the security section. If not, here is the minimum to follow the argument.

Spec-Driven Development (SDD) is a spec-first way of working with AI coding agents. Instead of writing a prompt and letting the model infer your intent, you write down the intent first, in a structured specification, and the agent implements against it. As Microsoft’s developer blog frames it, the spec becomes the shared source of truth for humans and AI across the whole lifecycle. The economic logic, laid out in Will Torber’s analysis on dev.to, is that AI has collapsed the cost of producing code, so the expensive part is now making sure the AI builds what you actually need. Spec is the source of truth; code is the build output.

Several frameworks implement this idea, and they differ mostly in weight and intent:

  • GitHub Spec Kit is the most prescriptive: a seven-stage pipeline (constitution, specify, clarify, plan, tasks, implement, validate) that shines on new projects where a full process is valuable.
  • BMAD-METHOD simulates an entire agile team (Analyst, PM, Architect, Dev, QA) with versioned artifacts at every handoff; powerful for enterprise and audit, heavy for a two-person startup.
  • Superpowers is a skill framework that forces the AI through brainstorming, planning, TDD, and code review; it governs how to build.
  • OpenSpec is the lightweight, brownfield-first option: a small CLI (MIT license) that tracks what changed rather than re-describing the whole system.

The evidence that this is more than hype is still thin but real. The most controlled public comparison is Ran Isenberg’s evaluation at Palo Alto Networks: same real feature, same codebase, same IDE and model, run through four workflows. OpenSpec scored highest overall on developer experience, review checkpoints, and parallel work, and his raw measurements put the lightweight workflows in the same cost ballpark while the heavy multi-agent one took six days. Hashrocket’s hands-on post ran the same task on the same commit with OpenSpec and Spec Kit and found OpenSpec’s artifacts about three times more compact and faster to review (roughly 250 lines versus 800 for the same change).

OpenSpec in one page

OpenSpec is built by Fission AI, written in TypeScript, and installed via npm (Node.js 20.19.0 or newer):

npm install -g @fission-ai/openspec@latest
cd your-project
openspec init

openspec init asks which AI assistant you use and creates only two files: openspec/project.md and openspec/AGENTS.md. Supported tools include Claude Code, Cursor, Codex, GitHub Copilot, Gemini CLI, and more than twenty others, through native slash commands or a shared AGENTS.md file.

The design decision that separates OpenSpec is what happens to the spec after the code is written. The spec-compare research describes three maturity levels: spec-first (the spec precedes coding but is discarded), spec-anchored (specs persist and evolve in the repository), and spec-as-source (only the spec is edited and code is regenerated). OpenSpec sits deliberately in the middle. Durable specs of the current system live under openspec/specs/, organized by capability, while every proposed change lives under openspec/changes/ as a proposal, a design, a task list, and a set of spec deltas marked ADDED, MODIFIED, or REMOVED. When the change ships, /opsx:archive merges the deltas into the durable specs, so the documentation grows with the code instead of evaporating in a chat window.

The workflow is three slash commands:

  • /opsx:propose creates the planning artifacts for a change.
  • /opsx:apply implements the tasks against those artifacts.
  • /opsx:archive closes the change and updates the durable specs.

The practical value is not the command syntax. It is the pause between “I want this feature” and “the agent is editing files”. A proposal can expose missing acceptance criteria, unclear scope, and contradictory requirements while they are still cheap to fix.

That is the state of the art. Now the part nobody has really tested yet.

The security problem with AI-generated code

The starting point is uncomfortable but well documented. In the first large-scale controlled user study on the topic, “Do Users Write More Insecure Code with AI Assistants?” (Stanford, published at ACM CCS 2023), 47 participants solved security-relevant programming tasks with and without an AI assistant. The result was twofold: participants with the assistant produced less secure code, and at the same time they were more confident that their code was secure. That combination, worse output and higher confidence, is the exact failure mode that matters for product security.

Industry data points in the same direction. Veracode’s 2025 GenAI Code Security Report tested code from more than 100 large language models across 80 curated tasks in Java, Python, C#, and JavaScript, and found that 45% of AI-generated code samples failed security tests, introducing OWASP Top 10 vulnerabilities. A Cloud Security Alliance research note from April 2026 calls this the “vibe coding security debt”: vulnerabilities generated at scale, faster than they are reviewed. LLMs reliably emit broken authorization, business-logic gaps, and hardcoded secrets, as catalogued in this analysis of security bugs LLMs introduce.

The reason is structural. A language model pattern-matches against the most common code in its training data, and the most common code is not the most secure code. When you ask for “a login endpoint”, the model produces the statistically typical login endpoint, not the one that survives your threat model.

Where SSDLC and SDD naturally meet

The Secure Software Development Lifecycle has always been about moving security earlier: threat modeling at design time, security requirements before implementation, verification gates before release. SDD moves intent earlier for the same reason. The two share the same core insight: the cheapest place to fix a problem is before the code exists.

The NIST Secure Software Development Framework (SP 800-218) organizes secure development into four practice groups, and its AI-specific extension, SP 800-218A (finalized July 2024), adds tasks that map almost one-to-one onto an SDD workflow: document intended use and risk tolerance, protect training data and artifacts with the same rigor as source code, threat-model the inference path including prompt injection, test against adversarial inputs, and monitor for behavior drift in production. A Safeguard analysis of SP 800-218A adoption in 2026 describes teams maintaining an AI threat model artifact per system, refreshed at major releases, with red-team evaluation logs mapped to that threat model.

Applying OpenSpec to security: a worked proposal to test

This is where we move from what is documented to what is plausible but unproven. The idea: take a real feature and write its OpenSpec artifacts with security requirements embedded from the start, so the agent executes against them. What follows is a concrete proposal you can run yourself, with the actual files shown in full. It has not been validated by a controlled study; whether it works is something you will discover by testing it on your own codebase. The reasoning behind each piece is grounded in the sources cited above.

The feature: “remember me” on login

Take the same example used in OpenSpec’s own documentation: adding a “remember me” checkbox that extends the session to 30 days. Without security thinking, the spec delta says only “the system shall support configurable session expiration”. A security-aware OpenSpec change writes four artifacts, and each one is shown below.

1. The Project.md, the project constitution carries the non-negotiables. This is the file every change inherits, the place for rules the agent must never break, each with its why, because the EPAM case study showed models follow rationale better than bare prohibitions:

## Security guardrails

- All session cookies are HttpOnly, Secure, SameSite=Lax.
  Why: a readable cookie is exfiltrable via any XSS; SameSite limits CSRF.

- Persistent tokens are opaque, high-entropy, stored hashed at rest.
  Why: a database leak must not leak usable credentials.

- Sensitive actions (email/password change) always require fresh authentication.
  Why: a stolen persistent cookie must not become full account takeover.

- All SQL is parameterized through the ORM; no string-concatenated queries.
  Why: injection is the default failure mode of hand-built queries.

2. openspec/changes/add-remember-me/specs/auth-session/spec.md the spec delta carries the security requirements, referencing OWASP ASVS categories so each line is verifiable:

### Requirement: Extended session via "remember me"

The system SHALL offer an optional extended session of 30 days when the user
explicitly checks "remember me" at login.

#### Scenario: Extended session cookie is hardened (ASVS V3)
- GIVEN a user checks "remember me"
- WHEN the persistent cookie is issued
- THEN it is marked HttpOnly, Secure, and SameSite=Lax
- AND the token is opaque, high-entropy, and stored hashed at rest

#### Scenario: Sensitive actions still require fresh authentication (ASVS V2)
- GIVEN a user holds an extended session
- WHEN they attempt to change email or password
- THEN the system requires a fresh password entry before proceeding

#### Scenario: No implicit privilege on extended sessions
- GIVEN a user holds an extended session
- WHEN they access any protected resource
- THEN the authorization context is identical to a normal session

3. openspec/changes/add-remember-me/design.md the design document carries a lightweight threat model, because that is what the agent that implements the tasks will read. NIST SP 800-218A names the threat categories that belong here:

## Threat model: extended session

Assets: user account, session token, persistent cookie.

Trust boundaries: browser to server; token store; credential store.

Threats and mitigations:
- Token theft via XSS or network interception
  → HttpOnly + Secure + SameSite=Lax cookie; TLS only.
- Database leak exposing usable tokens
  → tokens stored hashed; revocation on password change.
- Stolen cookie used for account takeover
  → fresh authentication required for sensitive actions;
    user-visible list of active sessions with revoke.

4. openspec/changes/add-remember-me/tasks.md the task list carries the verification steps, so the same workflow that builds the feature also checks it:

## Tasks

- [ ] Add remember_me checkbox to login form
- [ ] Issue 30-day persistent cookie with HttpOnly, Secure, SameSite=Lax
- [ ] Store persistent token hashed; add revocation on password change
- [ ] Require fresh authentication for email/password change on extended sessions
- [ ] Test: cookie flags asserted on issuance
- [ ] Test: sensitive action on extended session triggers re-auth
- [ ] Run dependency scan and SAST in CI; treat new findings as blocking

Each of these artifacts is a file a reviewer can read in the proposal and an instruction the agent can execute against in the implementation. None of them requires a new tool. All of them are the difference between a feature that matches the spec and a feature that survives an incident review.

Why this is worth testing, and what to watch for

The mechanism is sound on paper: the agent reads the spec, so a requirement written in the spec has a better chance of surviving into the implementation than a checklist in a wiki. The constitution is inherited by every change, so the guardrails do not depend on someone remembering to paste them into a prompt. And the archived change becomes a dated, reviewable record of what was required, designed, and implemented, which doubles as audit evidence.

The honest caveats are the ones the evidence already documented. In Isenberg’s controlled comparison, every tool tested had gaps in the feature’s authorization design, and none flagged the most security-relevant question during planning. An agent can also produce a polished, confident, and incomplete spec, the same failure mode the Stanford study found for code. And no published study has yet measured whether embedding security requirements in the spec actually reduces the 45% vulnerable-code rate Veracode found. That is the hypothesis this proposal lets you test on your own repository.

Where existing frameworks plug in

None of this requires a new vendor, but it composes cleanly with what you may already run. The CIS Benchmarks sit one level up from the feature spec: an SDD workflow that provisions infrastructure can reference a CIS-hardened baseline in its project guardrails, so generated Terraform or Kubernetes manifests start from a compliant posture. The OWASP Top 10 for LLM Applications becomes acceptance criteria when the product itself embeds an LLM: prompt injection, sensitive information disclosure, and excessive agency turn into spec requirements rather than afterthoughts. And the existing gates, SAST, DAST, dependency scanning, penetration testing, stay exactly where they are. The spec feeds them; it does not replace them.

The honest answer

Does any of this make a product more secure? The documented part is narrow: structured spec-first workflows produce artifacts a reviewer can check for security coverage before code exists, and that check is cheaper than finding the flaw in production. The plausible-but-unproven part is the worked proposal above: the mechanism is coherent, the references are solid, and the validation is now on your side of the screen. The clearly false part is the marketing version, where installing a framework removes the need for security judgment. Every credible source, from NIST to the Stanford researchers to the framework authors themselves, points the same way: the spec is where security intent lives, but the intent is still yours.

If you test the proposal on a real feature, the result worth reporting is simple: did the agent’s implementation pass the security checks you wrote into the spec, or did it drift from them? That answer, measured on your codebase, is worth more than any vendor claim.

Sources

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *