You visit Entra twice, and the order is not optional. Step 2 creates the
application so you have its ID; step 4 comes back to add the credential. They
cannot be done in one pass, because the credential encodes an endpoint the
collector only produces once it knows the application ID.
Before you start
1. Copy the threat detection endpoint
Open the collector and read the Connection tab. The Threat detection endpoint is unique to this collector:2. Register the client application in Microsoft Entra ID
In Microsoft Entra ID → App registrations, create a single-tenant application. Copy two values:Two applications are involved, and you create only one of them. This one is
the client: it is the identity Copilot Studio authenticates as, it holds the
federated credential from step 4,
and its Application (client) ID is what you paste into Power Platform.The other is the audience — the application that claims your endpoint’s origin
as its Application ID URI, so Entra knows who the token is for. That one is
NeuralTrust’s, and it cannot be yours: Entra only accepts an Application ID
URI on a domain verified in the tenant that owns the application, and the
endpoint is on our domain. Its own client ID is never entered anywhere. If it is
not present in your tenant, step 5
fails with
AADSTS500011 — contact us rather than trying to register it
yourself.3. Store the tenant and application IDs on the collector
Back on the Connection tab, paste both values and press Save. Separate several Application IDs with commas if more than one application will call. The status changes from Waiting for your tenant and application to Ready.4. Add the federated identity credential
The Connection tab now shows a Federated credential subject identifier. Copy it. In your Entra app registration, open Certificates & secrets → Federated credentials → Add credential and fill the form:On the audience application’s Expose an API page, only the first line matters.
Scopes defined by this API and Authorized client applications stay empty, as
do App roles and API permissions. They exist for APIs where a user or an admin
consents to permissions; here nothing consents to anything — the token is issued
against a federated credential, machine to machine. Defining scopes builds
something that is never evaluated.
By this point you are handling five identifiers that look alike. Mixing them
up is the most common setup error, and none of the portals warns you:
The rule that avoids all four confusions: if a Microsoft portal asks for the
value, it comes from Microsoft or from the collector’s Connection tab — never
from the address bar of the NeuralTrust console.
5. Turn on threat detection in Power Platform admin center
Open the environment → Security → Threat detection → Additional threat detection and protection for Copilot Studio agents, then enter the endpoint from step 1 and the Application (client) ID from step 2.The provider list is empty until you type in the filter. It loads on search,
so a blank list is the normal starting state and not a sign that anything is
wrong — search for your provider by name.
{"isSuccessful": true, "status": "OK"}.
6. Assign a policy
On the collector’s Policies tab, assign a default policy. Start it in Observe so findings are recorded without stopping any tool, check Agent Runtime → Activity, then switch to Enforce. Because the delivery is a planner snapshot rather than a chat turn, the choice of detector decides what is actually read:If you are protecting against a poisoned document, ticket, or API response, use
Indirect Prompt Injection. Prompt rules do not read tool output on this path,
so a policy built only from them stays quiet while the injection goes through.
If your agent uses workflows
Add one from Tools → + → Workflows. The flow needs the When an agent calls the workflow trigger — an ordinary Power Automate cloud flow cannot be used as an agent tool, and Copilot Studio says so on the picker. Two more things are worth knowing before you write a policy against a workflow, because neither is visible until you try. Give every input parameter a short, readable description. Power Automate names them after their type —text, text_1, text_2 — and that is what
arrives, whatever you type in the name field. Renaming a parameter in Power
Automate changes its description, not its name; the name reaches TrustGuard as
text_N regardless. Confirmed against live traffic: a flow whose four
parameters were named destinatario, asunto, cuerpo and copia_oculta
delivered them as text, text_1, text_2, text_3, carrying those words as
the descriptions.
So the description is the only place a readable name exists, and it does two
jobs. It tells the model what to put in the field — without it the model leaves
the field empty. And TrustGuard offers it as a dimension of its own whenever it
reads like a label rather than a sentence, so a policy can target
tool.arguments.copia_oculta instead of tool.arguments.text_3. Write a label,
not a paragraph: a long description stays a description and you are left with
the number.
That matters more than it sounds: reordering a workflow’s fields changes which
parameter text_3 refers to, and a condition on an attribute that no longer
exists matches the empty string rather than failing. A policy pinned to
text_N breaks silently the day someone adds a field.
Tool names arrive without spaces. A flow shown as Enviar respuesta in
Copilot Studio reaches TrustGuard as Enviarrespuesta, so a condition on
tool.name typed the way the tool appears on screen never matches. Copy the
name from Agent Runtime → Activity rather than from the Copilot Studio
canvas.
Confirm it blocks
Assigning a policy is not evidence that it fires. This is the smallest test that produces some, and it takes one conversation. It needs two tools, not one. Threat detection is called once per tool, just before it runs. With a single tool there is nothing to see: the injection is not in the request, it is in the response, which arrives afterwards. It is only observable in the gap between two calls — the first returns the poisoned content and the second carries it along.- Give the agent a tool that returns text you control, and a second tool that acts on it — reading a record and sending a message is the usual pair.
- Put an instruction that does not belong in the content the first tool returns, alongside some ordinary text. Something the agent would have to obey to be compromised, such as sending a summary to an outside address.
- Assign a policy with Indirect Prompt Injection in the Input direction, set to block.
- Remove every other tool and Knowledge source while you test. With three possible paths and one measured, a clean trace proves nothing — it may only mean there was an easier route.
- Publish, then ask the agent to do the work end to end in one turn.
Read the blocked call in Agent Runtime → Activity before moving on, because
it is the point of the whole path. In a real run of this test the proposed call
was impeccable — a correct recipient, an ordinary subject, a well-written body,
and the model had not obeyed the injection at all — and it was blocked anyway.
Nothing in the call itself was objectionable. The evidence was entirely in what
the previous tool returned, which is why a policy that reads only prompts or
only arguments lets this exact case through.
Reference
What Copilot Studio sends to threat detection
Each delivery carries the planner context (the user message, chat history and previous tool outputs), the definition of the tool about to run with its input and output parameters, the input values being passed to it, and conversation metadata — agent, user, trigger, conversation and message ids, channel, and the incoming client IP. Earlier tool output arrives underplannerContext.previousToolsOutputs, one
entry per tool that already ran in the turn, each carrying the calling tool’s
name and its output values with the role tool. The values are verbatim — the
platform does not truncate or summarise them — which is what makes a poisoned
result visible before the agent acts on it. On the turn’s first tool call the
list is empty, so that delivery has no earlier output to evaluate.
The contract also defines a thought field for the planner’s reasoning, and
planId / planStepId for the step being executed. All three have arrived
empty in every delivery observed so far, so nothing should be built on them
until Copilot Studio starts populating them.
Every field is treated as optional, so a Copilot Studio API version that adds or
drops one does not break evaluation.
The verdict contract
Threat detection answers with a single decision:blockAction is the whole contract. That is why this path cannot redact:
there is no field in which to return rewritten content.
The person using the agent does not see your
reason. Copilot Studio shows
its own message when a tool is blocked — “This action was blocked by threat
detection tools. Please contact your administrator if you believe this is an
error.” — and appends an instruction telling the agent to relay that text
verbatim rather than paraphrase it. Your reason and diagnostics are for your
logs and for Activity, so do not plan end-user wording around them.In the maker’s trace the blocked call carries a different, more useful pair:
errorCode: "pre-tool-blocked" with “This action was blocked before the tool
could run.” That is the one to look for when diagnosing, and it distinguishes a
block from every other reason a tool call can fail.Failure behavior
Troubleshooting
Related
- Microsoft Copilot Studio: scope, coverage, and the choice between both paths
- Governed tool access: the other integration path
- TrustGate and TrustGuard: collector, policy, verdict, and failure behavior
- Entra ID: Entra applications and credentials
- Microsoft Copilot Studio documentation: Microsoft reference