Panelica keeps an AI agent safe on a production server the same way it keeps any API consumer safe: scoped API keys with nothing preselected, HMAC-SHA256 request signing with a secret that never leaves the client machine, IP whitelisting and expiry, tiered rate limits, and a risk label on every one of the 404 available tools so a client can ask before anything destructive runs.
What Is the Threat Model of Giving an AI Agent Server Access?
An AI assistant with API access to a hosting panel introduces a specific, nameable set of risks — not a vague new category of danger, but four familiar problems that any credential-issuing system has to answer.
Over-broad tokens
A single all-powerful token handed to an assistant means every mistake, every misunderstood instruction and every unexpected model behavior carries the full blast radius of root access. The fix is not trusting the model more; it is never handing out more authority than the task in front of it requires.
Destructive actions taken without a human noticing
Deleting a database, removing a backup or suspending an account are all legitimate operations — the danger is a client executing one of them as a side effect of a broader instruction, without anyone realizing it happened until later. The fix is making the danger visible at the protocol level, before the call executes, not after.
Prompt injection through content the assistant reads
An assistant that reads log files, DNS TXT records, file contents or webhook payloads as part of its work is reading attacker-controlled text sometimes. If that text can talk the model into calling a tool it otherwise would not, the credential behind the session is what limits the damage — not the model's judgment, which an injected instruction is specifically trying to defeat.
Runaway loops and rate exhaustion
An assistant that retries aggressively, or fans out many calls while investigating something, can behave like a low-grade denial-of-service against its own panel, or simply burn through an API budget faster than intended. The fix is a hard ceiling the assistant cannot negotiate its way past.
Panelica answers all four with the same layer: the scoped, signed API key described below, plus a set of instructions the assistant itself is told to follow before it treats a tool as safe to call.
How Do I Create a Properly Scoped Key?
expires_in days) so the key stops working on its own once the task is done.How Do Scoped API Keys Limit What an Assistant Can Do?
When you generate an API key in the panel for an AI assistant to use, it starts with zero permissions. You search across 50 distinct scopes and add only what the task in front of you actually requires — nothing is granted by default, and nothing is preselected in the create-key dialog.
| Area | Scopes |
|---|---|
| Accounts | accounts:read, accounts:write, accounts:delete |
| Domains & subdomains | domains:read, domains:write, domains:delete |
| Databases | databases:read, databases:write, databases:delete |
| DNS | dns:read, dns:write, dns:delete |
email:read, email:write, email:delete | |
| FTP | ftp:read, ftp:write, ftp:delete |
| SSL | ssl:read, ssl:write |
| Backups & snapshots | backups:read, backups:write, backups:restore |
| File Manager | files:read, files:write, files:delete |
| Cloudflare | cloudflare:read, cloudflare:write, cloudflare:delete |
| Docker & app templates | docker:read, docker:write, docker:delete |
| App hosting (Laravel / Node.js / Python) | apps:read, apps:write, apps:delete |
| Git & deploy | git:read, git:write, git:delete |
| Logs & audit | logs:read, logs:write |
| Security (antivirus, firewall, IP blocks) | security:read, security:write, security:delete |
| Server & infrastructure | server:read, server:write |
| Service control | services:restart, services:start, services:stop |
| Plans | plans:read, plans:write |
| Webhooks | webhooks:read, webhooks:write, webhooks:delete |
| Bandwidth | bandwidth:read |
| License | license:read |
| Migrations (panel-to-panel) | migrations:read |
| Terminal | terminal:access |
| Full access | *:* |
Every family also accepts its own wildcard — domains:* grants read, write and delete on domains in one grant — and action-level wildcards work across families too: *:read grants read access everywhere, *:write everywhere a write scope exists, *:delete everywhere a delete scope exists, and *:* grants everything. The grid below shows a representative slice of that catalogue as a read/write/delete matrix.
A representative slice of the 50-scope catalogue — each family accepts its own read/write/delete grant independently, plus a family wildcard and the global *:* grant not shown here. The full 24-family table above is exhaustive.
A key intended purely to read metrics and restart a stuck service needs server:read plus services:restart; it does not need delete access to backups or write access to DNS, and nothing forces you to grant either. Service control deliberately keeps its own action scopes separate from server:write for exactly this reason — a metrics-only server:read key cannot stop MySQL.
*:* grants everything — every read, every write, every delete, across every family, with no further check. Reserve it for a genuinely trusted, well-understood automation running from a controlled environment, not as a default shortcut to avoid picking scopes.
How Do Roles Interact With Scopes?
Scopes sit on top of Panelica's existing role hierarchy, they do not replace it. An API key inherits the role of the account that created it — ROOT, ADMIN, RESELLER or USER — and every call the key makes is still filtered through that role's normal visibility rules. A key created under a USER account only ever sees that account's own domains, databases and files, no matter how broad its scopes are; a scope like domains:read on a USER key cannot see another customer's domains, because the role boundary applies first. Some routes are restricted further still, to ROOT or ADMIN accounts specifically — access logs are one example — regardless of what scopes a lower-role key holds. An assistant connected through a RESELLER-owned key is boxed in by that reseller's own customer set before scopes are even evaluated.
How Does HMAC-SHA256 Request Signing Work?
Every request the MCP server — or any other External API client — sends to the panel is signed over METHOD + PATH + QUERY + TIMESTAMP + BODY using the API secret, producing a signature sent as the X-Signature header alongside X-API-Key and X-Timestamp. The panel recomputes that signature server-side and rejects the request if it does not match, and separately rejects any request whose timestamp has drifted more than five minutes from the panel's own clock — which closes the door on replaying a captured request later, since a signature captured today is useless against tomorrow's timestamp check.
The part that matters most for an AI workflow specifically: the secret itself never travels. It lives in the environment of whatever machine is running the MCP client — your laptop, a CI runner, a container — and is used locally only to compute the signature. It is never logged, never sent to any third party, and never written to disk by the MCP server. If that machine is compromised, the signing key is exposed the same way any local secret would be; but nothing about the AI layer adds a new place for the secret to leak, because it never leaves the one place it started.
How Do IP Whitelisting, Expiry and Instant Revocation Add Defense in Depth?
Scoping controls what a key can do; these three controls limit where, how long, and until when. A key can be restricted to a specific IP address or range at creation time, so a stolen key is useless from anywhere else. A key can be given an expiry in days at creation time (expires_in), so a temporary integration — a one-off migration script, a contractor's session — stops working on its own instead of relying on someone remembering to revoke it. And any key, at any time, can be revoked instantly from the panel: the very next request using it fails immediately, with no grace period and no cached authorization lingering on the panel side.
What Do Rate Limits Protect Against?
Rate limits exist specifically for the runaway-loop and resource-exhaustion case: an assistant that fans out many calls while investigating a problem, or retries aggressively after a transient failure, hits a hard ceiling instead of degrading the panel for everyone else using it. Every key carries a tier set at creation time:
| Tier | Requests per minute |
|---|---|
| Starter | 60 |
| Professional | 300 |
| Business | 1,000 |
| Enterprise | Unlimited |
Responses carry X-RateLimit-Remaining-Minute and X-RateLimit-Reset-Minute headers, and a 429 response reports the exact reset time. The default starter tier is easy for an assistant to exhaust if it is doing wide, exploratory investigation across a large panel — create the assistant's key at a higher tier deliberately if you see repeated 429 RATE_LIMIT_EXCEEDED responses rather than treating the limit as something to route around.
How Do MCP Annotations Let a Client Decide When to Ask for Confirmation?
Every one of the 404 tools in the catalogue carries a safety annotation derived from its HTTP method: readOnlyHint on every GET, destructiveHint on every DELETE. As measured today, that breaks down to 180 read-only tools, 178 mutating tools and 46 destructive tools. Clients that respect these annotations — Cursor and Codex CLI among them — use them to decide, without asking the model, when a call is safe to run automatically and when a human should confirm first. A tool that lists domains runs without friction; a tool that deletes a database is flagged so the client can put a person in the loop before it executes, independent of how confidently the model believes the action is correct.
| Annotation | Example tools | What it means |
|---|---|---|
| Read-only | List domains, get SSL status, tail logs | Safe to run without confirmation; cannot change server state |
| Mutating | Create a database, deploy an application, restart a service | Changes state but is generally reversible or expected as routine |
| Destructive | Delete a domain, drop a database, remove a backup | Irreversible or high-impact; clients should confirm before executing |
How Do Server Instructions Stop an Assistant From Acting Outside Its Scope?
Annotations tell the client how to behave; the server instructions sent at connection time tell the model itself the same thing, in its own context. Those instructions describe every scope family, state the safety rule for mutating and destructive tools directly, and — because the MCP server probes GET /v1/me at startup — name the exact key the session is holding, its scopes, its tier and its expiry before the first tool call happens. A read-only key is announced as read-only from message one.
This is not a client-side guess about politeness — it is the model reading, in its own instructions, exactly what the credential in front of it can and cannot do, and what to do about each error class. This is verbatim output from panelica-mcp 0.5.1, and matches the same behavior observed in a real session driven by OpenAI Codex CLI: asked to attempt an action outside its granted scope, it declined and named the missing scope, without attempting the call itself.
What Changed When Scope Documentation Moved From Hand-Written to Code-Derived?
On newer panels, the scopes shown in every tool's description are pulled directly from the middleware chain that actually enforces them at runtime — including "one of scope A or B" rules and role restrictions like ROOT/ADMIN-only routes — instead of a separately maintained document that can drift out of sync with the code. During the work that produced this documentation, that code-derived pass found and corrected 32 places where the hand-written scope docs disagreed with what the middleware actually required: for example, /v1/search turned out to need no scope at all, while API key management itself requires *:*. The practical effect is that a tool's stated scope requirement is no longer a claim someone wrote down once — it is read from the same code path that will reject the request if the claim is wrong.
How Is Every Action an Assistant Takes Logged and Traced?
Every request made through an API key — whether it originates from an AI client, a script, or any other integration — passes through the panel's normal audit logging and RBAC exactly as if it had come from the dashboard. An action taken by an assistant is indistinguishable, from the audit log's point of view, from any other authenticated API call, and it can always be traced back to the specific key that performed it. If an assistant's session did something unexpected, the audit trail answers "what happened and under which key" without needing to reconstruct the conversation that led to it.
What Other Guardrails Exist Beneath the API Layer?
Scoping, signing and rate limits govern who can call what and how often; a few checks inside individual endpoints close off specific abuse paths regardless of scope. DNS record creation rejects private and reserved IP addresses for A and AAAA records, which blocks a class of server-side request forgery where a DNS entry is used to redirect internal traffic. FTP account home directories are fenced to the owning account's home, so an FTP-scoped key cannot be used to reach outside the account boundary it belongs to. Passwords generated or accepted through the API carry a minimum length of 8 characters. None of these depend on the calling client behaving well — they hold regardless of whether the caller is an AI assistant, a script, or a person.
Four Scoped Key Recipes for Common AI Workflows
Read-only auditor key
Grant *:read (or, on panels that predate the wildcard, the individual <area>:read scopes for whichever areas matter) and nothing else. This key can answer any "what is the current state of X" question — list domains, check certificate expiry, summarize server metrics, tail logs — and cannot change anything no matter how it is instructed. It is the safest possible key to hand to a new AI client on a production panel for the first time.
DNS operator key
Grant dns:read and dns:write, plus domains:read so the assistant can resolve a domain name to the id a DNS call needs. This key can list, add and update DNS records but cannot delete a domain, touch billing, or reach into databases, email or backups — a natural fit for an assistant whose job is exactly "manage DNS records," no more.
Full automation key
Grant the specific write and delete scopes a trusted, well-understood automation actually exercises — commonly domains, DNS, SSL, databases and server service control together — rather than reaching for *:* by default. Reserve *:* for a genuinely trusted embedded agent operating from a controlled environment, and prefer the narrower explicit grant everywhere else; a full-automation key is still worth an expiry and, where the calling environment has a stable IP, an IP whitelist.
Per-client key with expiry
Generate a separate key for every distinct MCP client or automation rather than sharing one key across all of them, and set expires_in at creation time for anything that is not meant to run indefinitely — a one-off migration assistant, a contractor's temporary access, an evaluation of a new AI tool. A distinct key per client also means the audit log tells you which client did what, and revoking access to one client never touches any other.
How Does This Compare to Handing Someone SSH Access?
An SSH key with shell access is effectively unscoped: whoever holds it can do close to anything the underlying Linux user can do, and there is no per-action risk label anywhere in that path — a destructive command looks exactly like a harmless one until it has already run. A Panelica API key used by an AI assistant is narrower by construction on every axis that matters here: it is limited to the External API's documented endpoints, each one gated by its own permission scope, every one individually labeled by risk class, every request individually signed and logged, and revocable in one action without touching any other credential. Scoped, signed, labeled and logged access compares favorably to a shared SSH key — the AI layer does not make the comparison worse, and done properly it makes it considerably better.
Frequently Asked Questions
Is it safe to give an AI assistant access to a production server?
It is safe in proportion to how the API key behind it is scoped, signed, time-limited and monitored — the same standard that applies to any other automated credential. Panelica's controls are designed so that answering "how scoped is this key" honestly is enough to reason about the risk.
What is the minimum scope I should grant to a brand-new AI client I have not evaluated yet?
Start with *:read (or the equivalent individual read scopes) and nothing else. A read-only key can answer questions and diagnose problems, and cannot change anything regardless of how it is prompted.
Can a scoped key see other customers' data on a multi-account panel?
No. Scopes govern which categories of action a key can perform; the key's inherited role (ROOT, ADMIN, RESELLER or USER) governs which records it can see at all, and that role boundary is enforced first, independent of scope.
What happens the instant I revoke a key?
The very next request made with that key fails immediately. There is no cached authorization and no grace period on the panel side.
Does scoping protect against a destructive call I explicitly authorized?
No — scoping limits what a key is allowed to attempt, not whether a specific authorized call within that scope is a good idea. A key with legitimate backups:restore access will still execute a restore if the client proceeds without confirmation; the destructive-tool annotation exists specifically so capable clients pause and ask before that happens.
Can a compromised MCP client host expose my panel's data to a third party?
The MCP server itself emits no telemetry and contacts no third party — it only talks to your own panel over the signed connection. If the machine running it is compromised, the exposure is limited to what the API key on that machine is scoped to do, which is exactly why narrow scoping and short expiries matter for any client running somewhere less trusted than your own workstation.
How does the panel stop a replayed request from an intercepted signature?
The HMAC signature is computed over the request's timestamp as well as its method, path and body, and the panel rejects any request whose timestamp has drifted more than five minutes from its own clock. A signature captured today cannot be replayed successfully once that window has passed.
What is the difference between a "one of A or B" scope rule and a normal single scope requirement?
Some routes accept more than one scope as sufficient — for example, a route might accept either a specific area scope or a broader wildcard that covers it. Newer panels state these "one of" rules explicitly in the tool description, derived from the actual middleware check, rather than requiring you to infer which combination works.
Do destructive tools require extra confirmation from the panel itself, independent of the client?
The panel enforces scope and role on every call regardless of client behavior. The destructive annotation is a signal to the calling client to seek confirmation before it sends the request at all — it does not by itself add a second server-side confirmation step, which is why choosing a client that respects the annotation, and scoping the key narrowly in the first place, both matter.
Can I restrict an API key to only be usable from my office or CI runner's IP address?
Yes — keys can be IP-whitelisted at creation time, restricting them to a specific address or range regardless of what scopes they carry.
Where can I see what an AI-driven session actually did on my server?
In the panel's audit log, the same place every other API-driven action is recorded, filterable by the API key identity that performed each action.