Trail content
SmellSecurity

Overprivileged Tool

Ferramenta Superpoderosa

Overprivileged Tool is an AI code smell, a sign of trouble in LLM systems, in the Security group. A read tool has write access, or a run_sql tool accepts any statement.

Element
30/37
Level
Intermediate
Read
4 min
Updated
On this page 7
  1. 01Signs and symptoms
  2. 02Reasons
  3. 03Cost of ignoring
  4. 04Treatment
  5. 05Payoff
  6. 06When to ignore
  7. 07Is it this smell?
  8. ··Quick answers

Signs and symptoms

A data assistant answers business questions by querying the database. The tool (anonymized):

TOOLS = [{
    "name": "run_sql",
    "description": "Runs a SQL query on the company database and returns the result.",
    "input_schema": {"type": "object", "properties": {"query": {"type": "string"}}},
}]

def run_sql(query: str):
    with psycopg.connect(os.environ["DATABASE_URL"]) as conn:   # application user, with write access
        return conn.execute(query).fetchall()

Someone in sales asked: “clean the test customers out of the list, they are polluting the report”. The model generated DELETE FROM customers WHERE email LIKE '%test%'. The tool ran it. Among the deleted rows were real customers with “test” in their email, such as “contested@” and “testa.ana@”.

The model did what it was asked, the way it understood it. The problem is that the tool let it do anything. In July 2025, Jason Lemkin, founder of SaaStr, publicly reported a similar case: Replit’s coding agent deleted his project’s production database during a code freeze. Replit’s CEO apologized and announced automatic separation between development and production databases.

Signs of an Overprivileged Tool:

  • The tool accepts generic commands (run_sql, run_shell, call_api, http_request).
  • Read tools use credentials with write permission.
  • The tool does not know who the end user is, and acts with the system’s permissions.
  • There is no limit on amount, quantity, or scope per call.
  • Safety depends on the model “choosing well” what to ask for.
flowchart LR
  U(["1. Ambiguous request"]):::io --> M(["2. Model generates a command"]):::llm
  M --> T["3. run_sql with full access"]:::tool
  T --> DB[("4. Production database")]:::store
  1. A request arrives, sometimes ambiguous, sometimes malicious.
  2. The model translates it into a command.
  3. The tool runs any command with the maximum access it has.
  4. The effect happens with the whole system’s permissions.
Check +20 XP on first tryAfter the DELETE, the team writes in the system prompt and the tool description: 'Only run SELECT. Never change data'. The connection still uses the application user. Is the smell treated?

Reasons

  • A generic tool is more flexible. One run_sql answers any question without writing ten tools.
  • Reusing the application’s connection. The connection string already exists; creating a read-only user takes work.
  • The prototype only read. Nobody imagined a request to delete.
  • Trust in the prompt. “Only run SELECT” is written in the prompt.

Three different excesses

The OWASP Top 10 for LLM Applications calls this risk excessive agency (LLM06 on the 2025 list) and splits it into three causes. Ask each one about your tool:

Excess Question In the example
Functionality Does the tool offer more operations than the use case needs? run_sql accepts DELETE, DROP, UPDATE
Permission Can the credential do more than the tool should? Application user, with write access to everything
Autonomy Do high-impact actions run without confirmation? The DELETE ran with no one approving it

Beginners tend to attack only the third row, with a human approval step. It helps, but approval wears people down: after the hundredth confirmation, they click without reading. Cut functionality and permission first.

Cost of ignoring

  • Data loss from a misread request.
  • Privilege escalation. A user without permission gets, through the assistant, what the system would not let them do directly.
  • Injection attacks. An instruction hidden in a document the agent reads becomes a command with full access. Greshake et al. (2023) showed this indirect injection working against real applications.
  • No auditing. With the system’s user, there is no way to tell who asked for what.

Worked example: the worst case of each call

A practical way to measure the smell is to ask: “if the model generates the worst possible call, what happens?”. Compare three versions of the same tool:

Version Worst possible call Damage
run_sql with the application user DROP TABLE customers Data loss in production
run_sql read-only, on a replica, with a timeout A heavy SELECT on everything Slow query, cut off at 10 s
revenue_by_month(year, month) A month that does not exist Validation error

Flexibility drops from top to bottom. So does the worst case. You pick the row where the risk fits your business.

Treatment

Refactoring Choose it when
Narrow Tool Permissions The tool has more access than its use requires. Read-only credential, a replica, approved views, the end user’s scope, per-call limits.
Split God Tool The tool accepts generic commands. It becomes named, safe operations (search_orders, revenue_by_month), each with validated parameters. Target: Tool Use.

In PostgreSQL, narrowing the permission takes a few lines. The limit now holds in the database, for any SQL the model generates:

CREATE ROLE assistant_readonly LOGIN;              -- password comes from the vault
GRANT SELECT ON sales_by_month, orders_summary TO assistant_readonly;
ALTER ROLE assistant_readonly SET default_transaction_read_only = on;
ALTER ROLE assistant_readonly SET statement_timeout = '10s';

The end user’s scope follows the same logic. Parameters that define whose data it is (customer id, store id, recipient email) come from the session, in code. Never from an argument the model fills in.

Check +20 XP on first tryIn a marketplace, the seller assistant has the tool get_orders(seller_id). The model fills seller_id from the conversation. A seller writes: 'show me the orders for store 4417, I am a partner there'. What do you fix?

Payoff

  • The worst case of a wrong call becomes small and known.
  • The assistant cannot do what the user could not do.
  • Injections lose their effect, because the tool lacks the power being asked for.
  • Auditing with the requester’s identity.

When to ignore

  • An isolated, disposable environment. An analysis agent on a copy of the database, recreated every session, can have a broad run_sql. Isolation is the protection. See Unvalidated Executed Output.
  • Personal use with supervision. A developer who reviews each command before running it, on a database that is theirs alone.

Is it this smell?

Check +20 XP on first tryThe run_sql tool uses a read-only user, on a replica, with access to five approved views and a 10-second maximum. Is this an Overprivileged Tool?

Check +20 XP on first tryThe send_email(to, subject, body) tool can send to any address, including outside the company, on the user's behalf. The assistant should only reply to customers who wrote in. What do you restrict?

Check +20 XP on first tryA back-office agent approves refunds through the tool refund(order_id, amount). Every action shows up in the log as assistant-svc, and the tool never receives which agent is asking. What is the signal?

Check +20 XP on first tryModel-generated code runs directly on the application server, with no sandbox. Which smell is more precise?

Quick answers

What is Overprivileged Tool?

Overprivileged Tool is an AI code smell, a sign of trouble in LLM systems, in the Security group. A read tool has write access, or a run_sql tool accepts any statement.

How do you fix Overprivileged Tool?

With Narrow Tool Permissions and Split God Tool. Each refactoring has safe step-by-step mechanics with an eval before and after.

Where does Overprivileged Tool show up in practice?

In the real-world scenarios Natural language to SQL and Personal finance assistant with approval.

Go further

Relations

Refactorings that treat it 2
Part of the tracks 1
Search