Safeguard
Supply Chain Security•

Spec-Driven Development with AI Coding Agents: Specs, Tasks, Security

Spec-driven development has an AI agent write requirements, design and task files before code. How it works, where security goes, and how to review it.

Safeguard Security Team
45 min read

Spec-driven development means you and an AI coding agent write down what to build before any code exists: a requirements file with testable acceptance criteria, a design file, and a task list the agent then works through. Unlike direct prompting, every step leaves a reviewable file. Put security requirements, allowed dependencies and test tasks in those files, not in chat.

Moving intent out of a chat window and into files next to the code also creates a new thing to secure: a spec is an input the agent trusts and acts on, just like a prompt. This guide covers how the main workflows structure specs, how EARS notation makes acceptance criteria testable, where security requirements belong, how agents should pick dependencies, and what can go wrong. It ends with a worked example: an avatar upload spec with OWASP ASVS references, an approved dependency list, and a CI job that runs tests and a scan.

Key takeaways

  • A spec-driven workflow splits work into three kinds of file: requirements (what and why), design (how), and tasks (the ordered steps). The agent writes drafts of each; a human reviews each before the next phase starts.
  • GitHub's open source Spec Kit produces spec.md, plan.md and tasks.md per feature through /speckit.* commands. Kiro produces requirements.md, design.md and tasks.md. Claude Code's plan mode is a lighter version: the agent proposes a plan and makes no edits until you approve it.
  • EARS (Easy Approach to Requirements Syntax), published by Alistair Mavin and colleagues from Rolls-Royce at the IEEE Requirements Engineering conference in 2009, gives each requirement a fixed shape such as "When [trigger], the [system] shall [response]". That shape maps cleanly onto a test case.
  • Security requirements belong in every layer: project principles (constitution or steering files), requirements with ASVS identifiers, threat notes in the design, and explicit tasks for tests, dependency review and the SBOM update.
  • Treat the dependency list as part of the spec. Name approved packages with pinned versions and licences, make "update the SBOM" a task, and have a human approve any new package before the agent installs it.
  • The main risks are conceptual and manageable: a spec can carry injected instructions, specs drift from code, and agents can mark tasks done without a passing test. Each has a concrete control, covered below.
  • Map the workflow to NIST SSDF practices (PO.1, PW.1, PW.4, PW.7, PW.8, PS.3) with evidence you can point to, not just a table in a policy document.

What is spec-driven development with coding agents?

Spec-driven development (SDD) is a way of working with an AI coding agent where the first output is not code but a set of structured documents. You describe a feature in plain language. The agent turns that into a requirements document, you correct it, the agent proposes a technical design, you correct that, and only then does the agent break the design into tasks and start writing code against them.

GitHub's Spec Kit, an open source toolkit, describes the process as defining "what to build and why", then turning the specification into a plan, tasks and working code. Its methodology document goes further and argues that the specification, not the code, should be the primary artifact that teams maintain. Kiro's documentation describes specs as "structured artifacts that formalize the development process", with three files and a three-phase workflow. The vocabulary differs between tools, but the shape is the same: requirements, then design, then tasks, then implementation, with review gates in between.

How is it different from prompting the agent directly?

With direct prompting, the specification exists only in your head and the chat transcript. The agent infers what you meant and starts editing. If it guesses wrong about authentication, error handling or which library to use, you find out by reading the diff, and the reasoning is gone when the session ends.

Spec-driven development changes four things:

  1. Intent is written down before code, in a form a reviewer can read in five minutes.
  2. Ambiguity is forced into the open. Spec Kit's templates tell the agent to mark unknowns with [NEEDS CLARIFICATION: ...] rather than guess; its methodology document's example is a login system where the agent must ask which authentication method to use.
  3. Each phase has a review gate. You approve requirements before design and design before tasks.
  4. The files persist. Kiro's best-practices page says specs are "designed to be version-controlled", so the next person or agent session starts from the same written intent.

The cost is time up front. The benefit is that review happens on a page of requirements instead of a thousand-line diff, and security requirements have an obvious home.

What goes in the requirements, design and tasks files?

The three files answer different questions and should be reviewed by different people where you can.

FileQuestion it answersTypical contentsWho should review itSecurity content that belongs here
Requirements (requirements.md in Kiro, spec.md in Spec Kit)What must the feature do, and why?User stories, acceptance criteria, out of scope items, open questionsProduct owner, security championASVS requirement references, abuse cases written as "If ... then ... shall" criteria, data classification, compliance constraints
Design (design.md in Kiro, plan.md plus research.md, data-model.md and contracts/ in Spec Kit)How will it be built?Architecture, data model, interfaces, sequence of calls, error handling, test strategyTech lead, security reviewerTrust boundaries, threat model notes, chosen libraries with pinned versions and licences, where validation and authorisation happen
Tasks (tasks.md in both)In what order, in what steps?Numbered, dependency-ordered tasks, each traceable to a requirementTech leadTasks for security tests, the dependency review, the SBOM update and the CI scan, each with a done condition
Project principles (Spec Kit constitution, Kiro steering files, AGENTS.md, CLAUDE.md)What rules apply to every feature?Coding standards, testing rules, stack choicesEngineering leadership, securityDefault security rules, the approved registry, the "no new dependency without approval" rule

The fourth row matters as much as the first three. Feature specs inherit from project principles, and that is where rules you do not want to repeat in every feature should live.

How do open source and vendor tools structure specs?

The descriptions below come from each tool's own documentation as fetched in October 2026. These tools change quickly, so check the current docs before you rely on a specific file name or command.

Spec Kit (open source)

Spec Kit is an open source toolkit from GitHub that adds structured processes and templates to an existing coding agent. Its README says it needs Python 3.11 or later, the uv tool, and a supported coding agent on Linux, macOS or Windows. Installation and project setup look like this:

uv tool install specify-cli
specify init my-project --integration copilot
cd my-project

The --integration value selects which agent the commands are installed for. After that, you run Spec Kit's commands inside the agent's chat, not in the terminal. The command reference lists the core order as:

/speckit.constitution -> /speckit.specify -> /speckit.clarify -> /speckit.plan
-> /speckit.checklist -> /speckit.tasks -> /speckit.analyze -> /speckit.implement
-> /speckit.converge

The documentation notes that invocation syntax varies by agent: some agents in skills mode use /speckit-specify, and some use $speckit-specify. What each command does, according to the reference:

  • /speckit.constitution sets project principles that every later phase is evaluated against. The methodology document describes the constitution (memory/constitution.md) as nine articles, including a test-first article, and leaves Articles IV to VI for each project to define, with security and access boundaries given as one example.
  • /speckit.specify writes the feature specification, focused on what and why, not the tech stack.
  • /speckit.clarify asks up to five targeted questions about underspecified areas and writes the answers into spec.md.
  • /speckit.plan generates design artifacts such as plan.md, research.md, data-model.md and contracts/ under a specs/[branch-name]/ folder. This is where you name the stack.
  • /speckit.checklist generates what the docs call "unit tests for your requirements". The reference says custom checklists are reviewer-owned and implementation must not self-approve them.
  • /speckit.tasks writes a dependency-ordered tasks.md in phases: Setup, Foundational, one per user story, then Polish.
  • /speckit.analyze is a read-only consistency check across spec.md, plan.md and tasks.md, reporting gaps such as a task with no matching requirement.
  • /speckit.implement executes the tasks, and asks before proceeding if any checklist item is unchecked.
  • /speckit.converge compares the implementation against the artifacts. Its only possible write is appending tasks to tasks.md; you repeat implement and converge until it reports converged.

Two parts matter for security teams. Presets can enforce organisational or regulatory standards, such as traceability in plans. And the README warns that community catalog listings "are not audits or endorsements", so review extension source code before installing it, as you would any dependency.

Kiro specs

Kiro's documentation says every spec generates requirements.md (or bugfix.md for bug fixes), design.md and tasks.md, stored under .kiro/specs/. Feature specs come in a Requirements-First variant and a Design-First variant; the docs recommend Design-First when the system must meet strict non-functional requirements such as latency, throughput or compliance. A Quick Spec mode generates all three files without approval gates between phases.

Kiro writes requirements in EARS notation, WHEN [condition/event] THE SYSTEM SHALL [expected behavior], and an Analyze Requirements option checks them for inconsistencies, ambiguities, conflicting constraints and gaps before design. When you run all tasks, Kiro builds a dependency graph from tasks.md and runs independent tasks concurrently in waves. A Sync Files action creates new tasks when requirements change. Bugfix specs record unchanged behaviour as WHEN [condition] THEN the system SHALL CONTINUE TO [existing behavior], and Kiro generates property-based tests for both the fix and the preserved behaviour.

Project-wide guidance lives in steering files under .kiro/steering/ or ~/.kiro/steering/. The docs suggest a security-policies.md alongside the product.md, tech.md and structure.md foundation files, say Kiro also reads AGENTS.md files, and warn: "Never include API keys, passwords, or sensitive data."

Plan mode in Claude Code

Claude Code does not ship a three-file spec format, but its plan mode gives you the core idea: a written plan and a gate before edits. The documentation says plan mode "tells Claude to research and propose changes without making them". Claude reads files and runs shell commands to explore, and edits stay blocked until you approve the plan (the docs note an exception for interactive sessions where bypass permissions are available). Enter it with Shift+Tab, by prefixing a prompt with /plan, or at startup:

claude --permission-mode plan

You can approve the plan and choose how edits proceed, or keep planning; Ctrl+G opens the plan in your text editor first. Setting defaultMode to plan in .claude/settings.json makes it the default for a project's terminal sessions.

Plan mode suits changes too small for a full spec, but it does not produce a persistent requirements file on its own. Ask Claude to save the approved plan in the repository if you want one. Claude Code's memory docs say CLAUDE.md can import files with @path/to/import syntax, and that Claude can read a repository's AGENTS.md in place of CLAUDE.md.

AGENTS.md and project instruction files

AGENTS.md is an open format described at agents.md as "a README for agents": a predictable place for build steps, test commands and conventions. It is not a spec format, but it is where project-wide rules that every spec inherits can live, and many agents read it.

OpenAI's Codex documentation explains how Codex discovers these files. It reads a global file from the Codex home directory, then walks from the project root down to the current directory, taking at most one file per directory and checking AGENTS.override.md before AGENTS.md. Files closer to the working directory appear later in the combined prompt, so they take precedence. Codex stops adding files once the combined size reaches project_doc_max_bytes, which the docs give as 32 KiB by default. That limit is worth remembering: a long instruction file can push a security rule past the cut-off. Our earlier post on how Codex discovers AGENTS.md instructions covers the discovery rules in detail, and Agent Skills explained covers the skill format that some spec toolkits now install.

Side by side

AspectSpec KitKiro specsClaude Code plan modeAGENTS.md alone
Requirements artifactspec.mdrequirements.md (EARS)Plan text in session; save to a file yourselfNone
Design artifactplan.md, research.md, data-model.md, contracts/design.mdPart of the planNone
Task artifacttasks.md (phased, dependency-ordered)tasks.md (run in waves)Plan stepsNone
Project-wide rulesConstitution, presetsSteering files, AGENTS.mdCLAUDE.md, imports, AGENTS.mdAGENTS.md
Review gatesOptional clarify, checklist and analyze gates; implement asks if checklists are uncheckedApproval between phases; Quick Spec skips themApprove the plan before editsNone built in
Consistency check/speckit.analyze (read-only), /speckit.converge (append-only)Analyze Requirements, Sync FilesYour reviewNone
Where it livesspecs/ folder in the repo.kiro/specs/ in the repoSession, unless savedRepo root and subfolders

How does EARS make acceptance criteria testable?

Most requirement problems are language problems. "The upload should be secure" cannot be tested. "Files must be small" cannot be tested either, because nobody wrote down how small. EARS fixes this by constraining the sentence shape.

Where EARS comes from

EARS stands for Easy Approach to Requirements Syntax. Alistair Mavin's EARS page says he and colleagues at Rolls-Royce developed it while analysing airworthiness regulations for a jet engine's control system, and that the notation was first published in 2009. The paper is "Easy Approach to Requirements Syntax (EARS)" by Alistair Mavin, Philip Wilkinson, Adrian Harwood and Mark Novak, in the proceedings of the 17th IEEE International Requirements Engineering Conference (RE 2009), pages 317 to 322 (DOI 10.1109/RE.2009.9).

The generic EARS structure, from the EARS page, is a fixed clause order: optional preconditions, an optional trigger, one system name and one or more responses. The ruleset says a requirement has zero or many preconditions, zero or one trigger, one system name and one or many system responses.

The five patterns

PatternKeywordTemplateSecurity example
UbiquitousnoneThe [system] shall [response]The upload service shall store files under server-generated names.
State drivenWhileWhile [precondition], the [system] shall [response]While an account is suspended, the upload service shall reject all upload requests with HTTP 403.
Event drivenWhenWhen [trigger], the [system] shall [response]When a user uploads an avatar, the upload service shall verify that the file content matches the declared image type.
Optional featureWhereWhere [feature is included], the [system] shall [response]Where image resizing is enabled, the upload service shall reject images wider or taller than 4,096 pixels before decoding.
Unwanted behaviourIf, thenIf [trigger], then the [system] shall [response]If an upload exceeds 2 MB, then the upload service shall reject it with HTTP 413 and write a security log entry.

Complex requirements combine keywords, for example "While the user is authenticated, when the user uploads an avatar, the service shall ...". Kiro's documented form, WHEN ... THE SYSTEM SHALL ..., is the event-driven pattern.

Why the shape makes tests easy

Each EARS clause maps to one part of a test:

  • The precondition (While) becomes the test's setup or fixture.
  • The trigger (When, or If) becomes the action under test.
  • The response (shall) becomes the assertion.

For the oversized upload example, the test almost writes itself: send a payload one byte over 2 MB as an authenticated user, assert HTTP 413, assert nothing reached storage, assert one security log entry. If a requirement cannot become a setup, an action and an assertion, it is not finished.

Security teams get two extra benefits. The unwanted behaviour pattern is a natural home for abuse cases, so a threat model turns into acceptance criteria. And the fixed shape makes gaps visible: a success requirement with no matching "If ... then" rows for oversized, wrong-type or unauthorised input stands out. EARS does not make a requirement correct, since a precise requirement can still name the wrong limit, but it makes it checkable.

Where do security requirements belong in a spec?

Short answer: at every layer, each with a different job. Putting everything into one "Security" heading at the bottom of the requirements file is the most common way security gets skimmed.

Project principles: the rules every feature inherits

The constitution, steering files or AGENTS.md should carry rules you never want to restate: allowed registries, no new dependency without human approval, one test per requirement, no secrets in code or specs, the target ASVS level and allowed licences. Step 1 below has a copyable version.

The OpenSSF Security-Focused Guide for AI Code Assistant Instructions, published on 1 August 2025, recommends keeping such instructions "concise, specific, and actionable", and warns that irrelevant rules can lead the assistant to add code for attacks that cannot happen. Codex's 32 KiB default cap and Claude Code's advice to keep each CLAUDE.md under 200 lines are further reasons to stay short.

Requirements: reference ASVS by versioned identifier

OWASP's Application Security Verification Standard (ASVS) is a catalogue of testable security requirements for web applications and services. The current stable version is 5.0.0, which the project page says was published on 30 May 2025. ASVS 5.0 is organised into 17 chapters, from V1 Encoding and Sanitization to V17 WebRTC, and each requirement is tagged with a level from 1 to 3.

The ASVS project asks that references include the version, in the form v5.0.0-5.2.1, because identifiers can change between versions. Do that in your specs. "Complies with ASVS 5.2.1" means nothing in two years; "v5.0.0-5.2.1" stays precise.

For each feature, list the ASVS requirements that apply and turn each into one or more EARS acceptance criteria. ASVS requirements say what to verify; EARS criteria say exactly how this feature behaves. For an avatar upload, the relevant ASVS 5.0.0 requirements include:

ASVS 5.0.0 IDLevelWhat it asks you to verify (paraphrased)
v5.0.0-5.1.11Documentation defines permitted file types, extensions and maximum size for each upload feature
v5.0.0-5.2.11The application only accepts files of a size it can process without loss of performance
v5.0.0-5.2.21The file extension matches an expected extension and the content matches the type it claims
v5.0.0-5.2.63Images with a pixel size larger than the maximum are rejected
v5.0.0-5.3.11Uploaded files stored in a public folder are not executed as server-side code
v5.0.0-5.3.21File paths are built from internally generated or trusted data, not user-submitted filenames
v5.0.0-8.2.21Data-specific access is restricted to consumers with explicit permission (to prevent IDOR and BOLA)
v5.0.0-16.3.22Failed authorisation attempts are logged
v5.0.0-15.1.22An inventory such as an SBOM is maintained for all third-party libraries
v5.0.0-15.2.11Components have not breached the documented update and remediation time frames

Note the first row. ASVS v5.0.0-5.1.1 is a documentation requirement: the spec itself is where file types and size limits must be defined. In a spec-driven workflow, the requirements file can be the evidence for that control.

Design: threat model notes next to the architecture

The design file is where trust boundaries become visible: browser to API, API to storage, API to an image library. Beside each boundary, note what crosses it, what could go wrong (conceptually, such as "a user requests another user's avatar by ID") and which requirement covers it. If a threat has no requirement, the spec is incomplete. NIST SSDF practice PW.1.1 calls for risk modelling such as threat modelling during design; a threat notes table in design.md is a light way to show it.

Data classification

State what data the feature touches and how your policy classifies it. An avatar is usually personal data. Classification drives retention, what may be logged, and whether data can go to an external service. Agents cannot infer it from code, so write it down.

Allowed dependencies and licences

The design file names every third-party package the feature may use, with exact version and licence, and says any other package needs approval. The next section covers how.

Mapping the workflow to NIST SSDF

NIST SP 800-218, the Secure Software Development Framework (SSDF) version 1.1, was published in February 2022. A draft version 1.2 (SP 800-218 Rev. 1) was published for comment on 17 December 2025; check its status on the CSRC page before citing it. SP 800-218A (July 2024) adds an SSDF Community Profile for generative AI. Version 1.1 maps onto a spec-driven workflow like this:

SSDF 1.1 practiceWhat it asks forWhere it shows up in a spec-driven workflowEvidence you can point to
PO.1 Define security requirementsIdentify and document security requirements for software and infrastructureConstitution or steering rules; ASVS references and EARS criteria in requirementsThe committed requirements file and its review history
PW.1 Design software to meet security requirementsUse risk modelling; track security requirements and risksThreat notes and trust boundaries in the design fileThe design file with requirement IDs beside each threat
PW.4 Reuse existing, well-secured softwareAcquire well-secured components; verify them, including checking for known vulnerabilitiesApproved dependency list with pinned versions; dependency review taskThe approved list, the review approval, the scan results
PW.7 Review and analyse codeReview code for vulnerabilitiesHuman pull request review plus automated analysis tasksPull request reviews; scan output attached to the build
PW.8 Test executable codeTest to find vulnerabilities and verify compliance with requirementsOne test per acceptance criterion, run in CICI test reports linked to requirement IDs
PS.3 Archive and protect each releaseCollect and share provenance data, such as an SBOM (PS.3.2)"Update the SBOM" as a task; SBOM stored with the releaseThe SBOM file for each release

How should agents choose dependencies under a spec?

Dependency choice is the decision an agent makes most often without being asked. Under a spec, the agent proposes and a human approves.

Start from an approved list

The design file, or an approved-dependencies.txt beside it, lists each package the feature may use with an exact version, its licence and a one-line reason. The OpenSSF guide suggests telling assistants to prefer well-known, community-trusted libraries and the official package manager. It also cites a study that found 19.7% of packages proposed by code-generating models did not exist, names attackers can try to register. A short list of named, pre-approved packages means the agent does not need to remember a package name at all.

Pin versions and use frozen installs

The build should install exactly what the lockfile says. npm's documentation says npm ci requires an existing lockfile, exits with an error if it disagrees with package.json, and never writes to either. For Python, pip's hash-checking mode (--require-hashes) is all or nothing: once one requirement has a hash, every requirement needs one. Either way, a CI run cannot quietly change a resolved version.

Make the SBOM update a task

Every feature that changes dependencies gets a task to regenerate the SBOM. ASVS v5.0.0-15.1.2 asks for an inventory such as an SBOM, and SSDF PS.3.2 asks for provenance data such as an SBOM to be collected and shared. CISA, NSA, the FBI and international partners published the 2026 Minimum Elements for a Software Bill of Materials on 29 July 2026, replacing the 2021 NTIA minimum elements. An npm project can generate a CycloneDX SBOM itself:

npm sbom --sbom-format cyclonedx > sbom.cdx.json

Human review of the dependency diff

In every pull request an agent opens, check three things:

  1. The manifest diff. A direct dependency not on the approved list is a stop: update the list through review or remove the dependency.
  2. The lockfile diff. A large, unexplained lockfile change on a feature that added nothing needs an explanation.
  3. The registry. Resolved URLs should point at the registry your principles allow. ASVS v5.0.0-15.2.4 asks you to verify components come from the expected repository, with no risk of dependency confusion.

A CI check can enforce the first point; Step 7 below includes one.

What are the risks of spec-driven development?

Spec-driven development reduces some risks of agent coding and introduces others. These are concept-level risks with concept-level controls; none needs exotic tooling.

Specs as prompt injection carriers

A spec is text an agent reads and acts on, which makes it a prompt. The OWASP Top 10 for LLM Applications describes indirect prompt injection as an LLM accepting input from external sources, such as websites or files, that alters its behaviour in unintended ways. A spec pasted from an issue tracker, imported through an MCP connection, or contributed from outside the team can carry instructions nobody meant the agent to follow. The same applies to constitution files, steering files, AGENTS.md and community presets.

Controls: require code owner review on specs/, .kiro/ and instruction files, the same as on source. Read imported requirements before an agent acts on them. Review community extensions before installing them. Keep the agent's permissions tight while it implements; Claude Code's security documentation recommends not piping untrusted content directly into the agent, and an agent that must ask before running commands gives you a chance to notice when a spec has steered it somewhere odd.

Specs drifting from code

A spec that no longer matches the code is worse than none, because people and agents trust it. Drift happens when someone fixes a bug directly in code, when an agent changes behaviour without updating the spec, or when requirements change and nobody regenerates tasks. Make "update the spec" part of done for any behaviour change, and use the workflow's consistency tools, such as /speckit.analyze, /speckit.converge or Kiro's Sync Files.

Agents marking tasks done without tests

A ticked box in tasks.md is an assertion, not proof. Agents can write a test that passes trivially, skip a failing one, or tick a task after a partial change. Define done as "the linked test passes in CI", and review tests against the acceptance criteria. We cover this in can you trust tests an AI coding agent wrote.

Skipping the gates

Kiro's Quick Spec skips approval gates, Spec Kit's clarify, checklist and analyze steps are optional, and approving a plan can switch straight into a mode with no further prompts. That is fine for low-risk work. For authentication, file handling, payments or personal data, skipping the gates removes the review that made the approach worth using.

Too much text, too little signal

Long instruction files cost context and can be truncated: Codex stops adding files at its byte limit, and Claude Code's docs note that imports do not reduce context cost. A security rule on line 600 may never reach the model. Put the few rules that matter at the top.

For a broader view of agent risks beyond specs, see AI coding agent security risks and controls.

Direct prompting, plan mode, spec-driven or test-driven: which fits?

ApproachWhat gets reviewedReviewabilityUp-front costDrift riskSecurity fitBest for
Direct promptingThe final diffLow: intent lives in chat and is lost after the sessionLowestHigh: no written intent to drift from, so nothing catches itWeak: security depends on what the prompt remembered to sayThrowaway scripts, small fixes, exploration
Plan modeA written plan, then the diffMedium: plan is readable but usually not keptLowMedium unless the plan is saved to the repoFair: you can check the plan for risky steps before editsSmall to medium changes in a known codebase
Spec-driven workflowRequirements, design, tasks, then the diffHigh: each phase is a file with review historyHigher: more text to write and reviewLow if spec updates are part of done; high if notStrong: security requirements, threat notes and dependency lists have a homeNew features, anything touching auth, data, files or new dependencies
Test-driven workflowTests first, then the code that makes them passHigh for behaviour, lower for design intentMediumLow for tested behaviour; untested behaviour can still driftStrong for behaviour you thought to test; weak for requirements nobody wrote downLogic with clear inputs and outputs; bug fixes

These are not exclusive. For security-sensitive work, the strongest combination is a spec-driven workflow whose tasks are written test-first: each EARS criterion becomes a failing test before the agent writes code. Spec Kit's methodology document includes a test-first article for this reason.

Step by step: a short spec with security acceptance criteria

The example below builds an avatar upload feature in a Node.js service. It works with any of the tools above. File names follow a plain specs/ layout; adapt them to Spec Kit's or Kiro's folders if you use one. Package names in the dependency list are placeholders: replace them with the packages your team actually approves.

Step 1: put project-wide security rules in the instruction file

Add a short section to AGENTS.md (or your constitution or steering file) so every feature inherits it:

## Security rules for all features

- Target OWASP ASVS 5.0.0 Level 2. Reference requirements as v5.0.0-<chapter>.<section>.<req>.
- Every acceptance criterion needs at least one automated test. A task is done only when its test passes in CI.
- Do not add, remove or upgrade a dependency unless it is listed in the feature's approved-dependencies.txt.
  If you need a package that is not listed, stop and ask.
- Install only from the project's configured npm registry. Use npm ci in CI.
- Never put secrets, tokens or real personal data in code, specs, tests or fixtures.
- When behaviour changes, update the spec in the same pull request.

Keep it short. This file is loaded into every session.

Step 2: write the requirements with EARS and ASVS references

Create specs/004-avatar-upload/requirements.md:

# Feature 004: Avatar upload

## User story
As a signed-in user, I want to upload a profile picture so other team members recognise me.

## Data classification
Avatar images are personal data (internal: confidential). Retain until the user deletes
the account or replaces the avatar. Do not send images to any external service.

## Acceptance criteria

REQ-1 (v5.0.0-5.1.1, v5.0.0-5.2.2)
When a signed-in user uploads a file, the upload service shall accept it only if the
content is a PNG or JPEG image and the extension is .png, .jpg or .jpeg.

REQ-2 (v5.0.0-5.2.1)
If an upload is larger than 2 MB, then the upload service shall reject it with HTTP 413
before writing anything to storage.

REQ-3 (v5.0.0-5.2.6)
If an image is wider or taller than 4096 pixels, then the upload service shall reject it
with HTTP 422 without fully decoding it.

REQ-4 (v5.0.0-5.3.2)
The upload service shall store each avatar under a server-generated random name and
shall ignore the client-supplied filename for storage paths.

REQ-5 (v5.0.0-5.3.1)
The upload service shall serve avatars from storage that never executes uploaded content.

REQ-6 (v5.0.0-8.2.2)
If a user requests to replace or delete another user's avatar, then the upload service
shall reject the request with HTTP 403.

REQ-7 (v5.0.0-16.3.2)
When the upload service rejects a request under REQ-6, the upload service shall write a
security log entry with user ID, target user ID, time in UTC and reason, and no image data.

REQ-8 (v5.0.0-15.1.2)
When this feature changes dependencies, the build shall produce an updated CycloneDX SBOM.

## Out of scope
Animated images, SVG, image editing, avatars for service accounts.

## Open questions
[NEEDS CLARIFICATION: should admins be able to remove another user's avatar?]

Every criterion has an ID, an ASVS reference and a shape that maps to setup, action and assertion. The open question stays open until a human answers it; an agent should not resolve it by guessing.

Step 3: write the design with threat notes and the dependency list

Ask the agent to draft specs/004-avatar-upload/design.md, then review and edit it. The security-relevant parts should look like this:

## Trust boundaries and threat notes

| Boundary | What crosses it | Threat (concept) | Covered by |
|---|---|---|---|
| Browser to API | Multipart upload, user session | Non-image content with an image extension | REQ-1 |
| Browser to API | Multipart upload | Oversized or very high resolution file exhausts memory | REQ-2, REQ-3 |
| API to storage | File bytes, storage key | Client filename used to build a path | REQ-4 |
| Storage to browser | Image bytes | Stored content executed or served with the wrong type | REQ-5 |
| API to API | User ID in request | User acts on another user's avatar | REQ-6, REQ-7 |

## Dependencies
See approved-dependencies.txt. No other package may be added for this feature.

And specs/004-avatar-upload/approved-dependencies.txt:

# name                     exact-version   licence      reason
example-image-probe        3.1.0           MIT          read image dimensions from the header without full decode
example-multipart-parser   2.4.2           MIT          streaming multipart parsing with a size limit

The two package names are placeholders. Your reviewer fills in real packages, checks each licence against your licence policy, and checks each version against known vulnerabilities before approving.

Step 4: have the agent produce tasks, and check them

Ask the agent to generate tasks.md from the requirements and design, in plan mode or with your spec tool's tasks command. Then check that the list includes tasks like these, each tied to a requirement:

- [ ] T1 Write failing tests for REQ-1 to REQ-7 (one test file per requirement group)
- [ ] T2 Add approved dependencies at the exact versions listed; run npm install once, commit package-lock.json
- [ ] T3 Implement size limit in the multipart parser config (REQ-2)
- [ ] T4 Implement header-only dimension check (REQ-3)
- [ ] T5 Implement content type check and extension allowlist (REQ-1)
- [ ] T6 Implement server-generated storage keys (REQ-4)
- [ ] T7 Configure storage and response headers so avatars are served as images only (REQ-5)
- [ ] T8 Implement ownership check and security log entry (REQ-6, REQ-7)
- [ ] T9 Regenerate SBOM with npm sbom and commit sbom.cdx.json (REQ-8)
- [ ] T10 Run the full test suite and the dependency scan in CI; attach results to the pull request
- [ ] T11 Update requirements.md and design.md for any behaviour that changed during implementation

If a requirement has no task, or a task has no requirement, fix the spec before implementation starts. Spec Kit's /speckit.analyze reports exactly that kind of gap.

Step 5: review the dependency list before implementation

Before the agent runs T2, a human approves approved-dependencies.txt by asking: is each package needed, is it the package you think it is (check the name and publisher on the registry yourself), is the licence allowed, and does the pinned version have known vulnerabilities? For the last question, Gold Open Source at gold.safeguard.sh gives free CVE intelligence with affected and fixed versions, with no login.

Step 6: implement with the agent in a mode that asks before changes

In Claude Code, approving the plan with "Yes, manually approve edits" keeps per-edit review. In Spec Kit, /speckit.implement can be scoped to one phase at a time, and the reference recommends validating each stage before continuing. Whatever the tool, stop any install command that does not match the approved list.

Step 7: run tests, a dependency check and a scan in CI

The CI job below runs on every pull request. It installs from the lockfile, runs tests, fails if a direct dependency is not on the approved list, generates the SBOM, and runs a Safeguard scan of the working tree. Pin third-party actions to full commit SHAs in production; tags are shown here for readability.

name: spec-checks
on:
  pull_request:

permissions:
  contents: read

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Install exactly what the lockfile says
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Fail on unapproved direct dependencies
        run: |
          jq -r '((.dependencies // {}) + (.devDependencies // {})) | keys[]' package.json | sort -u > declared.txt
          cat specs/*/approved-dependencies.txt project-approved-dependencies.txt 2>/dev/null \
            | awk '!/^#/ && NF {print $1}' | sort -u > approved.txt
          unapproved=$(comm -23 declared.txt approved.txt)
          if [ -n "$unapproved" ]; then
            echo "Dependencies not on an approved list:"
            echo "$unapproved"
            exit 1
          fi

      - name: Generate SBOM
        run: npm sbom --sbom-format cyclonedx > sbom.cdx.json

      - name: Scan with Safeguard CLI
        run: |
          curl -fsSL https://cli.safeguard.sh/install | bash
          set +e
          safeguard scan --dir . --output output
          code=$?
          set -e
          if [ "$code" -ne 0 ]; then
            echo "Scan did not complete (exit $code)"
            exit 1
          fi

      - uses: actions/upload-artifact@v4
        with:
          name: spec-evidence
          path: |
            sbom.cdx.json
            output/

Notes from the Safeguard CLI documentation: safeguard scan writes JSON results such as vuln.json and license.json under the output folder. It does not fail on findings; it exits 0 when the scan ran, 1 when the command failed, and 2 when results were written but the vulnerability scan did not run, which is why the job treats any non-zero exit as a failure. On a fresh CI runner, the docs say to put the scanner tools the CLI relies on on the PATH or point TOOLS_DIR at them. Gating merges on findings is done by policy gates in the Safeguard platform for repositories connected to it, not by this CLI step, which produces evidence.

project-approved-dependencies.txt holds packages the project already uses, so the check does not fail on dependencies that predate the feature.

Step 8: update the spec

Compare the code against the spec one last time with /speckit.converge, Kiro's Sync Files or a plain review. If a limit changed during implementation, the requirement changes in the same pull request. Close the open question and commit sbom.cdx.json. The spec, tests, SBOM and scan output are the feature's evidence trail.

Common mistakes

  • Specs with no non-functional requirements. If the spec does not state size limits, timeouts, rate limits, logging and retention, the agent picks defaults and you find out in production. ASVS v5.0.0-15.1.3 asks documentation to identify resource-demanding functionality; the spec is the place.
  • Letting the agent edit the spec silently. If the agent can rewrite requirements.md to match what it built, the spec stops being a check. Spec changes must show in the pull request diff and get human review.
  • No traceability from requirement to test. Put requirement IDs in test names so a reviewer can see which criteria have no test.
  • Security in one paragraph at the end. A generic "Security considerations" heading gets skimmed. Write security as acceptance criteria with ASVS IDs and as threat notes.
  • Approving the dependency list after implementation. By then the agent has already written code against whatever it installed. Review the list before the install task runs.
  • Copying a long security instruction file from the internet. Long, generic files cost context, may be truncated, and push the agent toward defences for attacks that cannot happen.
  • Mapping to NIST SSDF only on paper. A table that says "PW.8: yes" is not evidence. Evidence is the test report linked to requirement IDs, the reviewed dependency list, the release SBOM and the scan output. Asked for proof of PO.1 for one feature, you should be able to hand over its requirements file and review history.
  • Never closing the loop. Incidents found after release should become new requirements or constitution rules, or the same mistake returns in the next feature.

FAQ

What is spec-driven development in AI coding?

It is a workflow where an AI coding agent helps you write a requirements document, a design document and a task list before writing code, and then implements the tasks. Each document is reviewed by a person before the next phase starts, and all of them stay in the repository.

Is spec-driven development the same as plan mode?

No, but they are related. Plan mode, as Claude Code documents it, makes the agent research and propose a plan without editing files until you approve it. A spec-driven workflow adds separate, persistent requirements and design files with review between phases. Plan mode is a lighter option for smaller changes.

What files does Spec Kit create?

According to its documentation, Spec Kit creates a feature folder under specs/ with spec.md for requirements, plan.md and supporting design files such as research.md, data-model.md and contracts/, and tasks.md. Project principles live in a constitution file created with /speckit.constitution.

What files does Kiro create for a spec?

Kiro's documentation says each spec generates requirements.md (or bugfix.md for bugs), design.md and tasks.md, stored under .kiro/specs/. Project-wide guidance goes in steering files under .kiro/steering/.

What is EARS notation?

EARS, the Easy Approach to Requirements Syntax, is a way of writing requirements with a fixed clause order and a few keywords (While, When, Where, If and then). It was developed at Rolls-Royce and first published in 2009 by Alistair Mavin and colleagues. It makes requirements easier to read and to turn into tests.

How do I stop an AI agent adding unapproved dependencies?

Name the allowed packages with exact versions in the spec, tell the agent in its instruction file to stop and ask before adding anything else, install from the lockfile in CI with a command like npm ci, and add a CI step that fails when a direct dependency is not on the approved list. A human approves changes to the list.

Can a spec file contain a prompt injection?

Yes. A spec is text the agent reads and follows, so instructions hidden in a spec, an imported requirement or a community preset can steer the agent. Review spec and instruction file changes like code, be careful with imported text, and run the agent with permissions that make it ask before changing things.

Does spec-driven development satisfy NIST SSDF?

It can produce evidence for several SSDF practices, including PO.1 (security requirements), PW.1 (secure design), PW.4 (reusing well-secured components), PW.8 (testing) and PS.3 (provenance such as SBOMs). It does not satisfy them automatically. You need the artifacts, reviews and test results, not just the workflow.

Where Safeguard fits

Safeguard does not write specs or decide whether a requirement is right. The fit is the dependency and verification side of the workflow.

The approved dependency list in Step 3 needs a vulnerability check before a human signs it off, and the CI job in Step 7 needs a scan of what was actually installed. safeguard scan --dir . builds an SBOM for a directory, matches it against vulnerability databases and writes JSON results, including license results, that you can attach to the pull request. safeguard scan --sbom sbom.cdx.json scans an SBOM you already produced. In the platform, policies and gates decide what happens when a finding matches a rule: a gate can Block, Warn or Notify, and approved deviations go through exceptions rather than switching the gate off. The platform also shows which projects contain a given component and version, which helps when one approved package turns out to be vulnerable across several features. Reachability analysis ranks findings by whether your code calls the vulnerable path; how much that narrows the list depends on the codebase, so measure it during evaluation.

If you use the Safeguard CLI's own assistant to implement tasks, its /permissions modes (Ask, Accept edits, Plan, Auto, which is the default, and Strict) give the same "propose, then approve" control this guide recommends, and safeguard exec runs one non-interactive turn in CI with Strict as its default. Safeguard does not replace the human review of the spec text or of the dependency list.

Spec-driven development makes dependency choice visible, but the packages an agent installs are still ordinary open source with ordinary vulnerabilities. Once a vulnerable version sits on an approved list, the question is how quickly every feature using it moves to a fixed version, and what to do when no fix exists yet.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.

3. Gold Registry: start from components that are already fixed

Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingSafeguard policies and gates in CI
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The first demo is a real Safeguard CLI session. It is asked to fix the lodash CVE in a repository, reads the finding and advisory, asks before any command that changes something, edits package.json to lodash 4.17.21, runs npm install and npm test with approval, prints a summary and pushes nothing, then shows /permissions, /model and /scan .. That is the implement step of a spec-driven workflow in miniature: a bounded task, a dependency change you can see, tests run before anything is called done, and a scan at the end.

Click through it at your own pace, or open it full screen.

The second demo sets up the Safeguard runner on your own machine, approves it with its device code, and scans from the terminal. Teams can use the same flow to scan a feature branch locally after the agent finishes its tasks, before the pull request and its spec go up for review.

Click through it at your own pace, or open it full screen.

The third demo connects Claude to the Safeguard MCP server with OAuth and shows how you choose which Safeguard tools Claude can use. If you run a spec workflow with Claude, this is how the agent can look up findings for the packages on your approved list while it plans, with tool access you decided up front.

Click through it at your own pace, or open it full screen.

You can download the apps at safeguard.sh/download and read the CLI documentation at docs.safeguard.sh/docs/cli.

Quick check

An agent finishes a spec task and ticks it in tasks.md, but no test covers the requirement it implemented. Is the task done?

No. A ticked box is the agent's claim, not proof. Define done as "the test linked to this requirement passes in CI", add the missing test, and check that the test actually asserts the response written in the requirement.

Why reference ASVS requirements as v5.0.0-5.2.1 instead of just 5.2.1?

The OWASP ASVS project says identifiers can change between versions and asks that references include the version. A versioned identifier keeps the spec precise after the standard is updated.

Sources

Last reviewed: 25 October 2026. Spec tools and coding agents change quickly; check each tool's own documentation for current file names, commands and defaults before you rely on them.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.