All Posts

Stopping a production database wipe

Coding agents can reach live systems when a workspace exposes database credentials, shell access, or deployment access. The issue is permission placement. A model may propose a destructive command. The tool wrapper decides whether that command reaches the database driver.

Destructive actions

A destructive action removes data, removes access, stops a service, or makes rollback hard. For database work, examples include DROP DATABASE, DROP TABLE, TRUNCATE, and bulk delete.

AgentTrust ID treats destructive actions as a separate effect class. The current classifier marks action names containing delete, drop, destroy, purge, terminate, remove, or truncate as destructive. Server operators can also set an effect override when registering MCP tools.

How the failure happens

A coding agent may start with a review task:

  • inspect the schema
  • write a migration plan
  • run tests
  • prepare a deployment note

That workspace may contain production credentials. If the tool wrapper sends every model-selected command straight to the shell or database driver, the first boundary is the production system.

That boundary is too late. The authorization check belongs directly in front of the tool call.

Python example

This example assumes the MCP server is registered with the scope ceiling db.schema.read, db.query.read, and db.migration.plan. The session inherits that ceiling. A request for db.drop_database is denied before SQL execution because the action is outside the session scope.

from agenttrustid import AgentTrustClient

client = AgentTrustClient.from_env()

agent = client.agents.create(
    name="migration-planner",
    framework="custom",
    capabilities=["db.schema.read", "db.query.read", "db.migration.plan"],
)

# Use the server ID returned by MCP server registration.
server_id = "mcp-server-id-from-dashboard"
session = client.sessions.init_session(
    agent_id=agent.id,
    server_id=server_id,
)

read = client.actions.check(
    agent_id=agent.id,
    session_id=session.session_id,
    tool_name="db.schema.read",
    tool_input_summary="Inspect accounts table columns.",
    action_effect="read",
)

drop = client.actions.check(
    agent_id=agent.id,
    session_id=session.session_id,
    tool_name="db.drop_database",
    tool_input_summary="DROP DATABASE production",
    action_effect="destructive",
)

assert read.allowed is True
assert drop.allowed is False
print(drop.reason)

The model can still write DROP DATABASE production. The wrapper should treat that string as a request. It should not treat it as authority.

Guarding the call

Put the check in the function that reaches production.

def run_database_tool(agent_id: str, session_id: str, tool_name: str, sql: str, effect: str):
    decision = client.actions.check(
        agent_id=agent_id,
        session_id=session_id,
        tool_name=tool_name,
        tool_input_summary=sql,
        action_effect=effect,
    )

    if not decision.allowed:
        raise PermissionError(decision.reason)

    return database.execute(sql)

The authorization check has to run before the driver opens a connection. Logging the failure after execution is incident response.

Business impact

Production data loss becomes a customer incident. Teams lose time on restore work, customer messaging, compliance review, and root-cause analysis.

The next problem is that people stop trusting the agent with work. A coding assistant that cannot be bounded stays in a sandbox.

Prevention

Do not give planning agents destructive tools. Register separate tools for read, plan, write, deploy, and delete. Give each tool an effect class.

Use read-only sessions for review and planning. Use scoped sessions when the tool set is limited. Require approval for tools that can delete data, drop schema, deploy to production, or grant access.

Fail closed for destructive actions. In AgentTrust ID, destructive and admin actions pass Fast Guard first and then the Guardian path. If that path is missing or unavailable, the unified checker denies the action.

Solving this with AgentTrust ID

AgentTrust ID checks action name, effect, session ID, agent ID, and scope before execution. Session scope denies actions outside the registered tool ceiling. Read-only mode turns mutating and destructive requests into approval requests. The Guardian path reviews destructive and admin effects when the tool is in scope.

This puts a decision point between the model and production. The model can plan. The wrapper asks AgentTrust ID before it acts.

To check production tool calls before they run, start with the SDK guide. To talk through destructive-action controls, join the waitlist.