Skip to main content
Version: 2026.1

Tool Security

Tool security is the set of runtime controls that decide which SDK tools an agent can invoke, and with which arguments. It is enforced in a single hook registered on every Copilot SDK session, and it is mechanism-only on this page - for the catalog of tools and which are safe to enable, see Configuration → Tool Security Reference.

The pre-tool-use hook

Every SDK session is configured with a PreToolUseHook. It fires before any SDK built-in tool is invoked and has four layers of defence, in order:

  1. Always-denied tools. bash, list_bash, read_bash, write_bash, stop_bash, task. Rejected unconditionally; no configuration can enable them.
  2. Whitelist check. The excludedTools list is computed from the agent's configuration - everything not in the agent's allowed set is excluded - and passed to the SDK as a session-level block list.
  3. Path sandboxing. For view, grep, glob, create, edit, the hook resolves the path argument, neutralises ../ traversal, and checks it against the session's allowed directories (/app/uploads/{chatSessionId}/{uploaded,staged}). Reads against /tmp/* are permitted on specific files (for large MCP tool outputs) but directory listings are denied.
  4. Audit log. Every denial is recorded via logger.audit() with the request kind, tool name, and session id.

The hook is wired in the Copilot adapter and cannot be disabled per session - a session without it will not be created.

MCP tools are not governed by this hook

The hook is only about SDK tools (tools built into the Copilot SDK itself). MCP tools - the ones the agent reaches through /pimcore-mcp/* or an external MCP server - use a different mechanism:

  • Internal MCP tools run on the Pimcore PHP side. Permission is enforced per call by Pimcore's standard permission system, using the user's session cookie forwarded by the agent-server. An agent never has more access than the logged-in user. Which groups an agent can reach at all is controlled by pimcoreMcpServers / pimcoreMetaGroups in its YAML.
  • External MCP tools use whatever auth is configured in the agent's mcpServers entry. No user-cookie forwarding, no Pimcore permission check.

In short: SDK tools are gated by this hook; internal MCP tools are gated by Pimcore; external MCP tools are gated by their own auth.

Agent-level run permission gates using an agent

Using a specific agent additionally requires the run level on that agent, when the agent defines a permissions block, on top of the global pimcore_agent_use permission. The run check is enforced at every point an agent can be used, before the pre-tool-use hook or any MCP-level check comes into play: starting a chat session with the agent, switching an existing session to it, and listing agents in the chat selector and the switch-suggestion prompt. The agent-server fetches the per-user runnable set from a Pimcore endpoint gated by pimcore_agent_use, so the permission evaluation stays authoritative in Pimcore. See Configuration → Agents → Permissions for the full per-agent permission model.

Execution user and information disclosure

An agent configuration can optionally set executionUser, a Pimcore username the whole session runs as instead of the chat initiator (see Configuration → Agents → Execution user). When it is set, the effective user resolved at session creation, described in Authentication → Execution user resolution, owns every tool call, MCP call, and permission check for that session - not the person who typed the message.

This is a deliberate escalation path and needs to be treated as one. The execution user can hold more permissions than the users who chat with the agent, so the agent's responses can surface information (object content, listings, search results, proposal values) that the chatting users cannot access directly. HITL proposals created during such a session are computed with the execution user's permissions as well, so an approver may see proposed values derived from data outside their own visibility.

Only administrators can set, change, or clear executionUser; the server rejects a changed value coming from a non-admin request, and Pimcore Studio shows the field read only to non-admins. The recommended mitigation for the information-disclosure risk above is to combine an execution user with the agent's own run permission, so only an intended audience can start sessions with that agent at all.

Task-session tool overrides

A headless agent task runs its turns with two overrides layered on top of whatever the agent's own configuration allows, applied by the agent-server for every turn dispatched against a task-origin session (never a regular chat session):

  • The pimcore-task MCP tool group - the finalize_task tool - is force-injected regardless of the agent's pimcoreMcpServers / pimcoreMetaGroups configuration. It is the only way a task-session turn ends with a machine-readable result, so every task-origin session needs it whether or not the agent was configured with it in mind. It is never injected into a regular chat session.
  • The ask_user SDK tool (see Configuration → Tool Security Reference) is force-excluded, even for an agent whose YAML lists it under includeSdkTools. An unattended task has no human to answer a mid-turn question; the automatic pauseAfter continue/stop checkpoint is the only steering mechanism a task turn has.
  • The pimcore_switch_agent rich chat widget is never offered, regardless of the running agent's allowAgentSwitch setting (see Configuration → Agents). Agent switching is a human-confirmed, one-click action; a task has no human present to confirm one, and a switch can need to mint a fresh MCP access token for a different execution identity, something only Pimcore PHP can do at session-create time, not mid-turn from the agent-server. See Features → Agents and Switching for the chat-side behavior.

These overrides are applied server-side, at dispatch time, from the session's origin column - an agent configuration cannot opt out of any of them for its own task runs. See Architecture → Agent Tasks → Running the turn for where these overrides are applied and Features → Agent Tasks for the consumer-facing feature.

Further reading