Dapr 如何限制提示詞注入對智能體工具調用的影響?
How Do I Stop Prompt Injection From Reaching My Tools?
作者示範以 Dapr Workflow 管理智能體工具調用,透過工作流程權限、參數白名單及人手審批限制可執行操作。模型只提供建議標籤,倉庫和 issue 編號則取自已驗證的 GitHub webhook。這套方法不能阻止提示詞注入影響模型,但可限制模型能觸發的操作及傳入的標籤。
You can't stop untrusted text from reaching a model. If your agent reads public GitHub issues, anyone can put instructions into the text it reads. The model might follow them, even when you've told it not to.
What you can control is what happens afterwards. Which tools the agent can call, what arguments they accept, and whether the model gets to make the decision to execute them at all.
Take an agent that reads GitHub issues and applies labels. It needs to understand the issue, decide on a label and update GitHub. It doesn't need permission to close issues, merge pull requests or read repository secrets.
Here's how I'd build this with Dapr.
Put the agent inside a workflow
I'd use a Dapr Workflow to manage the issue triage process, rather than letting the model decide which actions to take.
The workflow receives a verified GitHub webhook, passes the issue text to an agent and gets back a suggested label. It then checks that label before calling GitHub.
The important part is what the agent doesn't control. It doesn't choose the repository, issue number or which GitHub operation to run. Those come from the workflow and the original verified event.
The model is deciding how to classify the issue, not what it's allowed to do with GitHub.
Treat MCP tools as workflows too
Dapr has an MCPServer resource which lets you declare a connection to an MCP server. When Dapr loads it, it discovers the available tools and registers a durable workflow for each one.
So if our GitHub MCP server exposes add_label and close_issue, Dapr registers workflows named:
dapr.internal.mcp.github.CallTool.add_label
dapr.internal.mcp.github.CallTool.close_issue
The agent doesn't need to manage the MCP connection itself. The application can invoke those workflows, and Dapr handles the MCP call.
For example, the resource on our github-tools application could look like this:
apiVersion: dapr.io/v1alpha1
kind: MCPServer
metadata:
name: github
spec:
endpoint:
streamableHTTP:
url: https://github-mcp.internal/mcp
scopes:
- github-tools
The URL and tool names here are examples; you'd use those exposed by your own MCP server.
Now we need to decide which applications can invoke those tool workflows.
Enforce permissions outside the model
A list of permitted tools in a system prompt isn't a security control. The model can be convinced to ignore it.
With Dapr, you can use a WorkflowAccessPolicy to control which App IDs are allowed to schedule particular workflows on another application.
For our example:
apiVersion: dapr.io/v1alpha1
kind: WorkflowAccessPolicy
metadata:
name: github-tools-policy
namespace: default
scopes:
- github-tools
spec:
rules:
- callers:
- appID: triage-workflow
workflows:
- name: dapr.internal.mcp.github.CallTool.add_label
operations: [schedule]
This allows triage-workflow to invoke add_label on github-tools. It doesn't grant access to close_issue, or any of the other tools the MCP server might expose.
The workflow access policy is enforced by Dapr, using the calling application's verified identity. The model doesn't get to override it.
There are two details worth knowing here. You need a policy loaded for deny-by-default behaviour, and the MCP server workflows need to run under a separate App ID. Dapr always allows an application to schedule its own workflows, so you shouldn't rely on this policy to isolate tools running under the same App ID as the caller.
Check the arguments before calling GitHub
Being allowed to call add_label doesn't mean every argument should be accepted.
A poisoned issue could convince the model to suggest a label like security-approved, or try to make it update a different issue.
I'd have the agent return a label, then check it in the workflow before calling GitHub. Something like this, using the Dapr Python Workflow SDK:
import dapr.ext.workflow as wf
wfr = wf.WorkflowRuntime()
ALLOWED_LABELS = {
"bug", "feature", "docs",
"question", "needs-triage"
}
@wfr.workflow(name="triage_issue")
def triage_issue(ctx: wf.DaprWorkflowContext, issue: dict):
# classify_issue is a registered activity that calls the model
suggestion = yield ctx.call_activity(
"classify_issue",
input=issue["body"]
)
label = suggestion["label"]
if label not in ALLOWED_LABELS:
return {"status": "rejected"}
return (yield ctx.call_child_workflow(
workflow="dapr.internal.mcp.github.CallTool.add_label",
app_id="github-tools",
input={
"arguments": {
"owner": issue["owner"],
"repo": issue["repo"],
"issue_number": issue["number"],
"label": label
}
}
))
This is the core of the workflow, with the activity implementation and runtime startup left out. The tool arguments will depend on your MCP server.
Notice that the model only supplies the label. The repository and issue number come from the verified webhook that started the workflow.
I'd also validate arguments where the tool runs. Dapr's MCPServer resource supports beforeCallTool hooks, which are themselves workflows. You can use one to reject labels outside the allow-list before the call reaches the MCP server.
That way the check isn't only happening in the application that called the tool.
Use a separate workflow for anything destructive
Adding a label is one thing. Closing an issue, deleting something or deploying a release is another.
For those operations, I'd use a separate workflow that waits for human approval.
Dapr Workflows can wait for an external event, so the workflow can request approval, stop executing and resume when an authorised user responds. There's no need to keep a process running while someone makes the decision.
The approval needs to be verified by your application, not accepted as something the model says it received.
You can then give the review workflow its own App ID and grant it access to close_issue, without giving that permission to the triage workflow.
The same applies to any other tool where a bad decision is difficult to undo.
What this doesn't fix
None of this stops prompt injection from influencing the model. A malicious GitHub issue might still persuade it to suggest the wrong label.
But the model doesn't have permission to close the issue, the workflow won't accept a label outside the allowed set, and the repository and issue number aren't under the model's control.
That's a much smaller problem than giving an agent access to every tool on the MCP server and relying on a system prompt to keep it in line.
You still need to think about prompt injection. You just shouldn't be relying on the model to enforce the limits of what it's allowed to do.
Dapr documentation:
來源:DEV Community · dev.to