About Portfolio Cases Services Blog Contact 🎙 Talk to AI
EN DE RU
🎙 Talk to AI
November 7, 2026 · 5 min read

Stop giving AI agents production keys: new control planes and approval gates for irreversible actions

I’m Denis Shokhirev, an Agentic AI Systems Architect based in Freiburg im Breisgau, Germany, and at DennisCraft AI Studio I ship production AI systems for DACH B2B clients on Claude, Supabase, n8n, Doppler, and self-hosted Postgres. The ugly production moment is not when an agent writes a mediocre answer; it’s when the same agent holds a real production key and is one tool call away from deleting records, emailing customers, changing access, or triggering a payout. If your agent runtime has dir

Denis Shokhirev
Denis Shokhirev
Agentic AI Systems Architect
Telegram LinkedIn

I’m Denis Shokhirev, an Agentic AI Systems Architect based in Freiburg im Breisgau, Germany, and at DennisCraft AI Studio I ship production AI systems for DACH B2B clients on Claude, Supabase, n8n, Doppler, and self-hosted Postgres. The ugly production moment is not when an agent writes a mediocre answer; it’s when the same agent holds a real production key and is one tool call away from deleting records, emailing customers, changing access, or triggering a payout.

If your agent runtime has direct access to production secrets, you collapsed reasoning and authority into one component. That is the core design mistake. Teams usually notice it late: the demo looks good, the agent can “do things,” and then everyone starts adding warnings to the system prompt. But prompts are not enforcement. An LLM can propose actions; it should not automatically own the credentials for irreversible ones.

The real problem is authority, not intelligence

LLMs are very good at selecting plausible next steps from context. They are not policy engines, and they do not naturally understand legal finality, financial exposure, or operational blast radius. OWASP’s LLM Top 10 2025 explicitly calls out excessive agency and insecure output handling as production risks when model output is allowed to trigger real actions: https://genai.owasp.org/llm-top-10/

I also recommend reading Anthropic’s documentation on tool use and safe system design. The consistent pattern is clear: keep tool permissions narrow, validate outside the model, and treat the model as a planner rather than the final authority. Source: Anthropic Docs, 2025, https://docs.anthropic.com/

Where direct keys fail in practice

Action classExampleWhy it hurtsSafer pattern
Database mutationUPDATE or DELETE in PostgresData loss, broken audit trailSigned action + approval gate
Customer communicationOutbound email or ticket closureContract and reputation riskPreview + human approval
Privilege changesRole or scope updateAccess escalationPolicy service only
Financial operationsRefund, invoice, payoutMoney movement is hard to reverseTwo-step approval

The pattern is simple: give the agent the ability to suggest an action, not the authority to execute it directly in production.

A practical control plane for agent actions

The most useful design shift is to separate your system into three planes.

1. Reasoning plane

This is where Claude or another model reads context, selects tools, and proposes an action. It can access read-only data, schemas, and approved action definitions. It should not hold long-lived production secrets.

2. Policy and approval plane

A separate service receives a proposed action, normalizes it to a known schema, scores its risk, and decides one of three outcomes: auto-approve, require human review, or deny. The decision can depend on environment, amount, record count, target resource, reversibility, and user identity.

3. Execution plane

This is the only layer allowed to hold short-lived credentials and call production APIs. It does not execute arbitrary text from the model. It executes a typed action contract after validation, idempotency checks, and audit logging.

from dataclasses import dataclass
from typing import Literal

@dataclass
class ProposedAction:
    action_type: Literal["send_email", "run_sql", "issue_refund"]
    payload: dict
    reason: str
    actor_id: str
    environment: Literal["staging", "prod"]

def approval_required(action: ProposedAction) -> bool:
    if action.environment == "prod":
        return True
    if action.action_type in {"run_sql", "issue_refund"}:
        return True
    if action.action_type == "send_email" and action.payload.get("recipient_count", 1) > 5:
        return True
    return False

This is not overengineering. It is the same separation of duties you already apply to payments, infrastructure, and database administration.

Approval gates need data, not vibes

A common anti-pattern is a natural-language rule such as “if the action looks risky, ask a human.” That fails because “looks risky” is not machine-enforceable. The model must produce a structured intent, and the gate must evaluate it against explicit policy rules.

Minimum fields for a production gate

I want at least these fields on every proposed action: action_type, target_resource, environment, initiator, expected impact, reversibility, idempotency_key, and a human-readable diff. For SQL, estimate affected rows. For email, include recipients and final body preview. For config changes, include before/after values.

approval_rules:
  - action_type: run_sql
    environment: prod
    require_human: true
  - action_type: send_email
    environment: prod
    recipient_count_gt: 5
    require_human: true
  - action_type: issue_refund
    amount_eur_gt: 0
    require_human: true
  - action_type: update_user_role
    environment: any
    require_human: true

This can live in Postgres or Supabase and be called from n8n without a huge platform effort. In regulated environments, the audit trail matters as much as the action itself.

What to put around the agent today

You do not need a mythical vendor product to improve this. A stable setup can be built with standard tools.

Secrets isolation

Use Doppler or another secret manager so only the execution service can read production credentials. The model runtime should never hold the keys that can mutate production directly.

Static analysis and secret scanning

Use semgrep, bandit, and gitleaks in CI. bandit catches insecure Python patterns. gitleaks finds leaked credentials. semgrep is useful for custom policy checks in glue code, especially around unsafe SQL execution and permissive tool handlers.

python -m pip install bandit
bandit -r app/

docker run --rm -v "$PWD:/repo" semgrep/semgrep semgrep \
  --config=p/security-audit /repo

gitleaks detect --source . --verbose

Database role separation

In Postgres, split roles aggressively: read_only_agent, action_executor, and human_admin. The agent only gets read access. Any write path goes through a stored procedure or an execution service with policy checks and logging.

What counts as irreversible in real B2B systems

Many teams only think about DELETE statements. That is too narrow. In enterprise systems, irreversibility is often legal, financial, or procedural. Sending a customer-facing email with the wrong promise is not fixed by a database rollback. Changing a KYC status, closing an operations incident, exporting personal data, or editing a retention policy can all create obligations far beyond the original API call.

That is why I treat “reasoning traces” and “audit records” as different artifacts. The model’s chain of thought is not your accountability layer. Your accountability layer is a signed action request, a policy decision, an approval record, and an execution log.

FAQ

Is human-in-the-loop enough?

Not by itself. Human review only works when the reviewer sees a structured action with a clear diff, target, and impact. Free-form summaries from the agent are not a reliable approval surface.

Can I allow write access in staging?

Yes. Staging autonomy is often useful. Just do not let that become an excuse to blur the boundary between staging and production authority.

What if the action is reversible?

Then you may auto-approve more of them, but only if reversibility is defined at the system level and backed by idempotency, logging, and a tested rollback path. Do not let the model decide what “reversible” means.

Do small teams need a separate policy service?

Yes, even if it starts as a thin Python service with a Postgres table of rules. The key is architectural separation, not organizational size.

What is the first fix for an existing agent?

Inventory every action the agent can trigger today, label irreversible ones, and remove production secrets from the agent runtime first. Then add an execution layer and approval gate around those actions.

Which stage in your LLM pipeline catches the most issues in production today: static analysis, runtime sandboxing, or human approval before execution? I’d genuinely like to compare notes.

I run a free 30-min stack audit for DACH founders building AI in regulated markets. DM me on LinkedIn or write to @ger_dennis_ai.

For your business

I build agents like this for businesses in Germany and the EU.

Tell me in two sentences what eats your team’s time – reply within 24 hours.

Custom AI agents (German page) →
Continue reading
Your AI agent hits a wall without web access: why teams need one MCP gateway instead of 20 fragile integrations
Computer-use agents break on pixels: how to switch to stable UI refs via accessibility trees and stop fixing flaky desktop automation
A compromised Cursor marketplace extension tried to plant SSH backdoors: how to stop AI tooling from owning developer machines
Your agent breaks production not because it hallucinates, but because it cannot see the UI: why runtime perception for web and desktop is becoming mandatory
All articles →
Where this is applied
Services — what we build
Talk to the voice agent
Case studies
Ready to build?

Turn your process into an AI system

Production quality. DACH B2B focus.

Start a project → ← All articles