Your SKILL.md Is Not a Security Policy

Share
A glowing document on a desk with three concentric boundary rings showing the gap between skill instructions and platform enforcement.

A SKILL.md file is a Markdown file with YAML front matter and some instructions. You write it in any text editor, upload it to your agent, and the orchestration runtime decides when to activate it.

The barrier to entry is low. The barrier to safety is not.

The problem is not that skills are inherently risky. The problem is that they look like documentation and behave like behaviour. A maker reads a skill and thinks it is guidance. The runtime reads the same skill and treats it as executable instructions. The gap between those two interpretations is where production incidents start.

What a skill actually does (and does not do)

In the new agent experience for Copilot Studio, a skill is a reusable capability defined by a name, a description, and Markdown instructions. The orchestration runtime activates it when a user request matches the skill's purpose. Skills can work alongside tools and knowledge. They are portable as Markdown files or ZIP packages and can be shared across agents.

That is what a skill does.

What it does not do is enforce permissions, validate data, or guarantee deterministic behaviour. A skill is model-interpreted guidance. It tells the agent how to handle a specific type of task. It does not replace a workflow for sequencing, a connector for identity, or a data policy for access control.

The most common mistake is writing a skill as if it were a workflow.

A weak version

Here is a plausible skill that a busy maker might upload:

---
name: customer-support
description: Handles customer support requests.
---

Resolve the customer's issue.
Use any available tools when useful.
Update customer records and send a reply when appropriate.

It is short, clear, and looks reasonable. It is also a production risk.

The description is broad enough that the runtime might activate it for any message containing the word "problem". The instructions collapse drafting, data modification, and message delivery into one responsibility. There is no input requirement, no failure path, and no boundary between what the agent should propose and what it should actually do.

Use any available tools when useful delegates capability selection to the model with zero constraints. If the agent has a connector that modifies Dataverse records and a connector that sends email, this skill gives the model permission to use both without checking whether the maker intended that combination.

Why it fails in production

Three things go wrong:

Activation is too broad. The runtime matches the description against the user's message. "Handles customer support requests" could match a question about pricing, a complaint about delivery, or a request to reset a password. Each of those needs different tools, different data, and different boundaries.

Side effects are unbounded. The skill says "update customer records and send a reply". In a production agent with real connectors, that means the model can modify data and send messages based on its interpretation of what "appropriate" means. There is no approval step, no human-in-the-loop, and no way to roll back.

No failure handling. What happens when a required fact is missing? What if the tool call returns an error? The skill says nothing, so the model improvises. It might invent a refund amount, guess a delivery date, or send a response based on incomplete information.

A safer version

---
name: draft-customer-response
description: >
  Draft a customer-support response from facts supplied in the conversation.
  Use when a user asks for a reply draft, not when they ask to send a message
  or modify customer records.
---

# Purpose

Draft a clear customer-support response using only the facts supplied by the
user and approved reference material.

# Required inputs

Before drafting, identify:

- The customer's reported issue.
- The verified facts available in the conversation.
- The requested resolution or next step.

If a required fact is missing, ask for it or mark it as a visible placeholder.
Do not invent order details, policy outcomes, refunds, dates, or commitments.

# Workflow

1. Summarise the issue internally in one sentence.
2. Separate verified facts from assumptions.
3. Draft a concise response with acknowledgement, explanation, and next step.
4. Check the draft against the boundaries below.

# Boundaries

- Do not send the response.
- Do not call tools that modify customer records.
- Do not promise a refund, deadline, or policy exception unless the user
  supplied an approved decision.
- Do not expose internal notes or confidential reference material.

# Output

Return only the proposed response and a short list of unresolved placeholders,
when any remain.

What changed and why

Every change in the safer version addresses a specific failure mode:

The description is narrow and exclusionary. It says what the skill does AND what it does not do. The runtime is less likely to activate it for unrelated requests, and when it does activate, the scope is clear.

Required inputs are explicit. The skill is designed so the model should not proceed without them. If a fact is missing, the model must ask or flag it rather than inventing something. This alone eliminates the most common hallucination path.

The workflow is sequential. Numbered steps give the model a structure to follow rather than a blank canvas. It does not guarantee deterministic execution, but it does reduce the space of possible behaviours.

Boundaries are negative constraints. Instead of saying "use tools when useful", the skill says what NOT to do. Negative constraints are more reliable than positive ones because they are easier for the model to check.

Output is scoped. The skill returns a draft, not a sent message. The actual sending happens elsewhere, in a workflow or a human review step.

Package structure and supporting files

Copilot Studio accepts two formats: a standalone Markdown file or a ZIP package. The package can include supporting files such as reference documents, templates, and scripts.

A useful structure looks like this:

draft-customer-response/
├── SKILL.md
├── references/
│   └── response-policy.md
└── templates/
    └── response-outline.md

The reference document contains approved language, policy boundaries, and escalation paths. The template provides a consistent response structure. Neither executes automatically. They are read by the model when the skill is active.

This is important: including a script in the package does not mean Copilot Studio will execute it. The skill instructions must explicitly reference the file and describe how to use it. A package is a container, not a runtime.

The four boundaries you must separate

When reviewing a skill, ask four questions in this order:

Behavioural influence: What does the skill instruct the model to do? This is the Markdown content itself. It shapes how the agent interprets a task and which available capability it attempts to use.

Capability: What tools, connectors, and data sources are technically available to the agent? A skill can reference tools, but the tools exist independently of the skill.

Permission: Which identity performs the action? What do data policies allow? A skill should not grant permissions that the platform has not already configured.

Enforcement: Where do business rules actually execute? If a refund must be approved by a manager, that approval belongs in a workflow, not in a skill.

The skill owns the first boundary. The platform owns the other three. Confusing them is the root cause of most skill-related incidents.

How to test your skills

Testing a skill is not the same as testing an agent. You need to verify three things:

Activation accuracy. Send messages that should trigger the skill and messages that should not. If the skill activates for "what is your return policy?" when it should only activate for "draft a response to customer X", the description is too broad. Try variations: formal language, informal language, questions in different languages if your agent supports them, and messages that are adjacent but distinct.

Boundary compliance. Test the negative constraints. Ask the agent to do something the skill explicitly forbids. If it sends a message when the skill says "do not send", the boundary is not strong enough. Test with escalating pressure: first a polite request, then a direct command, then a scenario that makes the forbidden action seem like the obvious choice.

Missing data handling. Remove one required input and verify the skill asks for it or flags it as a placeholder rather than inventing a value. Test with partial data, contradictory data, and data in an unexpected format.

Run these tests in the Preview tab before publishing. Refine the description and instructions based on what you observe. A skill that passes on the first try is usually a skill that has not been tested hard enough.

Where skills belong in your architecture

Skills work best when they sit between the agent's general instructions and the deterministic workflows. Think of them as specialised modes the agent can enter when a particular type of task arrives.

A skill for drafting responses is different from a skill for analysing sentiment, which is different from a skill for generating a summary. Each one has a narrow purpose, clear inputs, and defined boundaries.

When a task requires sequencing, retries, human approval, or data modification, use a workflow. Skills can reference tools, and workflows can include AI nodes, but the ownership boundary should be clear: the skill guides the model's approach, the workflow enforces the process.

How data policies interact with skills

Copilot Studio supports data loss prevention and data policies that govern what agents can do. These policies control knowledge sources, actions, connectors, skills, HTTP requests, and publication to channels. A data policy can restrict which skills are available in which environments.

This means your skill design should account for the data policies that will apply in production. A skill that works in a development environment with permissive policies might behave differently when deployed to an environment with tighter controls. Test with the actual data policies that will be in place, not with the default configuration.

Skills versus workflows: where the binary breaks

The cleanest boundary is straightforward: skills guide the model, workflows enforce the process. But the reality is messier.

Workflows in Copilot Studio can include AI nodes that perform reasoning. Skills can reference tools that have side effects. The distinction is not absolute. What matters is which layer owns the authoritative decision.

If a refund must be approved by a manager, that approval belongs in a workflow with a human step. If a response must follow a specific template, that guidance belongs in a skill. If data must be validated against a business rule, that validation belongs in a workflow or a system of record.

The composition is intentional, not accidental. Design each layer to do what it does best and let them work together.

The production checklist

Before deploying a skill, verify:

  • The description is narrow enough to prevent accidental activation but broad enough to cover the intended scenarios.
  • Required inputs are listed and the skill is designed so the model should not proceed without them.
  • Negative constraints are explicit: what the skill must NOT do.
  • The skill does not promise side effects it cannot enforce.
  • Supporting files are reviewed and contain no sensitive data.
  • The skill has been tested with messages that should and should not activate it.
  • A workflow or human step handles any action the skill deliberately defers.
  • The skill is versioned in source control, not just in Copilot Studio.

Bonus: Keep the portable file and the source repository

Skills are portable by design. You can author them in any text editor and upload them to multiple agents. But portability means nothing without version control.

Keep your SKILL.md files in a Git repository alongside the rest of your agent configuration. Use branch policies for review. Tag releases when a skill moves from test to production. When a skill causes an issue, you need to know which version was active and what changed since the last working version.

Copilot Studio does not track skill history the way it tracks agent versions. Source control fills that gap.

One scenario, three layers

Consider a sales organisation that wants an agent to handle lead qualification. The agent receives a lead from a web form, checks whether the lead meets certain criteria, and either creates an opportunity or returns the lead to marketing for further nurturing.

The skill owns the qualification logic: what questions to ask, what criteria to apply, and how to assess the lead. It guides the model through a structured evaluation.

The workflow owns the side effects: creating the opportunity record in Dataverse, updating the lead status, and sending a notification to the sales team. It enforces the sequence and handles retries if a service is temporarily unavailable.

The system of record owns the authoritative rules: what constitutes a qualified lead, which fields are required, and which business units can own the resulting opportunity. These rules live in Dataverse, not in the skill.

If you put the qualification rules in the skill, they become model-interpreted guidance. If you put them in Dataverse, they become enforced business logic. Both have value, but they serve different purposes. The skill tells the agent how to think about the lead. The system of record tells the organisation what a qualified lead actually is.

The better question

The question is not whether your skill works in the preview pane. The better question is which layer should own the behaviour, the business rule, the context, and the execution.

A skill is excellent at telling an agent how to approach a specific type of task. It is not a substitute for a workflow, a data policy, or a human approval step. Write it with that distinction in mind and you will save yourself from the kind of incident that starts with "it worked in preview" and ends with "we need to roll back".

Sources and further reading

Read more