You can give an AI assistant useful access to a server without handing it your passwords, but only if the access is built for it. A root SSH key or a full panel API key pasted into a chat gives the assistant - and the chat history, and whoever reads that history - everything. What works instead is narrow: a link or connection that sees the server's shape but not its secrets, that can act only in the ways you chose, that ends on its own when you stop using it, that you can cut off in one click, and that leaves a record of what it did. For the one job that genuinely needs a secret - putting a password into a .env file - the right tool writes the value without ever reading the file back. That is the whole design, and the rest of this post is the detail of each piece and where its limits are.
We built the AI features in our panel around exactly those rules, so where the post describes how RE:NODE does a step, it is because the step is a concrete example of the principle. The principles apply on any host.
What an assistant actually needs from a server#
Most of what an assistant needs to be helpful is not secret. To fix a crashing Node app it needs the runtime and version, the start command, the port the server is supposed to bind, the last few hundred lines of console output, and a look at the directory tree. To connect a database it needs the host, the port, the database name and the name of the environment variable your code reads. To add a domain it needs the address the A record should point at.
None of that requires a password. The password is needed exactly once, at the moment it goes into a config file, and after that nobody - human or model - needs to read it again. This is the distinction the rest of the post rests on:
- Context is what the server is: runtime, ports, file layout, logs, variable names. Safe to show, and the thing that makes an assistant useful.
- Secrets are the values that grant access: database passwords, API tokens, OAuth client secrets, signing keys, SMTP credentials. Never needed for reading, needed once for writing.
- Power is what the assistant may change: files, the console, start and stop. Useful, and the part that should be opt-in and short-lived.
If a tool cannot tell those three apart, it has to give the assistant all of them or none of them. That is why "just give it SSH" is the wrong answer even when you trust the model completely. We covered the wider argument, that the agent writes and a human reviews, in AI coding agents for server work.
Where secrets actually leak#
It is worth being specific about the path a secret takes when it leaks through an assistant, because most of it has nothing to do with the model misbehaving.
- The transcript. Anything the assistant reads becomes part of the conversation. Conversations are stored by the provider, synced to other devices, shared with colleagues as links, pasted into tickets and screenshotted for help forums. A database password that appeared once in a tool result is now in all of those places.
- The context files. Agents like Claude Code and Cursor write notes and summaries into the repository -
CLAUDE.md,AGENTS.md, planning files. If a secret was in the context, it can end up in a committed file, and from there in every clone. - The round trip. An assistant asked to change one line in
.envoften reads the file, edits it in memory and writes the whole thing back. If the read was redacted, the write-back replaces every real value with the placeholder and breaks the app. If the read was not redacted, every value went through the transcript. - The long-lived credential. A key pasted into a chat in March still works in October unless someone remembered to rotate it. Nobody remembers.
The model choosing to exfiltrate your password is the least likely of these. The boring routes - logs, history, files - are where secrets go. Our post on environment variables and secrets covers the general hygiene; the sections below are about closing those four routes when the reader is an AI.
What the panel withholds#
On RE:NODE, everything an assistant receives through a share link or our MCP endpoint passes through a redactor first. It works in three layers, because each one alone misses things the others catch.
| Layer | What it catches |
|---|---|
| By variable name | Anything named like TOKEN, PASSWORD, KEY, SECRET, AUTH, SALT |
| By shape | GitHub, Slack, OpenAI and AWS keys, JWTs, passwords in URLs, long random strings |
| By value | The server's actual secrets and database passwords, scrubbed from the finished output |
The name layer handles the obvious case: DB_PASSWORD=... in a startup variable shows the name with the value withheld. The shape layer handles a token that turns up somewhere unexpected - a stack trace that printed a connection string with user:password@host in it, or a GitHub token echoed into the console by a careless install script. The value layer is the backstop: the panel knows what this server's real secrets are, so it searches the finished output for those exact strings and removes them wherever they appear, under any name.
Database passwords in particular are never in the output. The assistant gets the host, port, database name and user, which is enough to write the connection code and the name of the variable it should read from, and you put the password in place yourself or through the write-only tool below.
We say that plainly because the code says it about itself. Three layers make a leak much less likely; they do not make it impossible, and a vendor that tells you otherwise has not tested it against real console output.
Read access also has a deliberate gap: a default share link shows directory listings but not file contents. The assistant can see that config/database.php exists; it cannot read it unless you give it a link that can act, and even then reads come back through the same redactor.
Writing a secret without reading it: set_env#
The round-trip problem from earlier has a clean fix: do the merge on the server side and never send the file to the assistant at all. Our MCP tools include set_env for exactly this. It takes a .env path, a set of keys to set and a list of keys to remove. The panel reads the file itself, replaces or appends the named lines, keeps every other byte where it was, writes it back, and returns only the key names it touched.
A call from the assistant looks like this:
{ "server": "1a2b3c4d", "path": "/.env", "set": { "DATABASE_URL": "postgres://app:the-real-password@db-host:5432/app", "SESSION_SECRET": "a-long-random-string" }, "unset": ["OLD_API_KEY"]}And what comes back is no more than this:
/.env - updated: DATABASE_URL; added: SESSION_SECRET; removed: OLD_API_KEY.Values are not echoed. Restart the server for the app to read them.The details that make it safe rather than merely convenient:
- It is write-only by construction. There is no mode in which it returns a value, so there is nothing to misconfigure.
- It only edits files named `.env` or `.env.something`. Everything else goes through the ordinary file tools.
- Other lines are untouched. Comments, ordering, blank lines and line endings stay as they were. A key that appears twice has every occurrence replaced, because whichever one your loader honours must hold the new value.
- Values are single lines. A value with a newline is refused rather than silently splitting the file.
- It exists only on links that can act. A read link cannot write anything,
.envincluded.
There is one honest caveat. If you type the password into the chat so the assistant can pass it to set_env, the password is in the transcript, because you put it there. set_env stops the file's other secrets from leaking and stops the write-back from destroying them; it cannot un-send what you typed. The cleaner pattern for a high-value credential is to let the assistant set every non-secret key and add the one password yourself in the file manager, or to generate the value on the server and never show it to anyone.
# Set by the assistant through set_env - safe to discussNODE_ENV=productionPORT=25601DATABASE_HOST=db-hostDATABASE_NAME=app# Added by hand in the file manager - never in a chatDATABASE_PASSWORD=The port and host above are placeholders; use the values the panel shows for your server.
Scopes: what a link can and cannot do#
Access should be the smallest thing that gets the job done. On RE:NODE there are two kinds of share link, made from the Connect AI button in the bar above the console, and the kind depends on what you said the assistant is for.
| Link | It can | Default |
|---|---|---|
| Read | Server context, task prompts, console tail, directory listings | Yes |
| Can act | All of that, plus start, stop, restart, kill, console input and file edits | Only for "Manage this server" |
Picking General, Set up a new project, Fix my repository, Connect a database or Add a domain makes a read link. Only "Manage this server" makes one that can act. "Server won't start" does not make a link at all: it copies a ready-to-paste prompt with the console tail, which is often all an assistant needs to diagnose a crash.
Some things are never available through any link, whatever its kind:
- deleting, renaming or reinstalling the server
- startup command and variable changes
- databases and their passwords
- backups and schedules
- users and subusers
- SFTP details and API keys
Writes through a link are text only, at most 1 MB per file, and never inside .git/. Each link is limited to 60 requests a minute, 20 actions a minute and 6 power actions a minute, which is generous for an assistant doing real work and a hard brake on one stuck in a loop restarting your server.
If you would rather connect an assistant to your account than paste a link, the panel has a hosted MCP endpoint with OAuth 2.1 sign-in. You add the URL and approve once on a consent page:
$ claude mcp add --transport http renode https://panel.renode.space/api/client/mcpOn the consent page you pick which servers (all of yours, or a selection) and a level: Files (read and edit files, console) or Manage (that, plus start, stop and restart). Databases, backups, schedules, users, startup and settings are never on offer. Access tokens last an hour; refresh tokens last 30 days and slide with use. A replayed refresh token revokes the whole grant, so a stolen token that is used after the real client has already used it kills itself. We built and tested this against Claude Code and Claude.ai's custom connectors; other clients that speak remote MCP should work, but we have not tested them specifically.
The same least-privilege thinking applies to people, and the panel's model for it is in subusers and least privilege.
Expiry and rotation#
The usual failure with access tokens is not that they are stolen on day one. It is that they are still valid on day two hundred. So share links do not ask you for a duration and do not need deleting. They expire on their own:
| Link | Idle expiry | Hard ceiling |
|---|---|---|
| Read | 7 days after last use | 90 days from creation |
| Can act | 24 hours after last use | 30 days from creation |
Each use pushes the idle expiry forward, so a link an assistant is actively using keeps working, and one you forgot about dies within a week, or within a day if it could change things. The ceiling means even a link in constant use ends.
Rotation works the same way. Making a new link for the same server and the same purpose replaces the previous one; you do not have to find and delete the old one first. A server holds at most five active links, two of which can act, and the oldest is retired when you go past that.
The URL itself is shown once. The panel stores only a hash of it, so a copy of the database does not contain a working link. If you lose it, make a new one - the old one is revoked in the same step.
Two more rules close the gaps people usually find later:
- A link is only as good as its creator's access. If you were a subuser and your access is removed, every link you made stops working at once, on every fetch.
- Every refusal is a plain 404. Expired, revoked, creator lost access, server suspended - the response is the same. Someone probing a link learns nothing about why it does not work, or whether it ever did.
Revoking access#
Expiry handles the links you forget. Revocation is for the ones you want gone now - you pasted a link into the wrong chat, a colleague's laptop was stolen, or you have simply finished.
Everything is in one place: Account, then Connected AI. It lists every OAuth connection with a Disconnect button and every active share link your account made, on any server, with a Revoke button. Each link shows how many actions it has taken and when it was last used, which is the quickest way to spot one that is still being called when you thought you were done with it.
A revoked link answers 404 on its next request. A disconnected OAuth connection loses its access in the same way. Neither needs a password change, though if the assistant could act and you do not know what it did, read the next section before you decide that is the end of it.
Auditing what the assistant did#
The question after any incident is "what changed?", and the answer has to come from a record the assistant did not write. On RE:NODE, every action taken through a link or an OAuth connection writes the same activity event that the equivalent button in the panel writes. A file edited through the assistant is a server:file.write row; a restart is a power event; a set_env call is a file write that records the file and the key names, never the values.
Those rows are recorded under the account that made the link or approved the connection, because that is whose authority the assistant used. Behind the scenes each row also records which door it came through - a share link, an OAuth grant or an API key - so support can tell them apart. Creating and revoking links are events too: server:ai.link.create and server:ai.link.revoke. Connecting and disconnecting an OAuth client are logged against the account.
How to use that in practice:
- Before you hand over a link that can act, take a backup from the Backups tab. The activity log tells you what changed; a backup lets you undo it.
- During, keep the console open, so you see restarts and errors as they happen.
- After, check the action count on the Connected AI page against what you expected. A link that should have made three edits and shows forty actions is worth reading the log for.
- If something is wrong, revoke first, then read the activity log for the window the link was live, then restore or fix.
A log does not stop anything; it tells you what to fix. That is why it sits next to scopes, limits and expiry rather than replacing them.
A checklist before you paste a link#
The whole post in a list you can run through in under a minute:
- Does the assistant need to change anything? If not, use a read link. Most diagnosis does not need power.
- If it needs to act, take a backup first.
- Keep passwords out of the chat. Let the assistant set non-secret keys with
set_envand add the secret yourself. - Never paste an SFTP password, a panel API key or a database password into a conversation. If you did, rotate it.
- Paste the link only into the conversation that needs it. A shared conversation shares the link.
- When the task is done, revoke the link on the Connected AI page.
- Glance at the activity log and the action count. If either surprises you, investigate before you move on.
If you deploy from GitHub, there is one more place secrets hide: the repository. A committed .env is reported by name by the pre-flight check on the GitHub tab, without the panel opening it. Our guide to deploying a Node app from GitHub covers how environment values should reach the server instead.
FAQ#
Can the AI see my database password?
Not through the panel's links or MCP endpoint. Database passwords are withheld from every output, and no link can open the database settings. The assistant gets the host, port, database name and user, which is enough to write the code. If you type the password into the chat yourself, it is in the transcript like anything else you type.
Is redaction enough to make it safe to share any server?
No. It makes leaks much less likely, but a secret in an unexpected format can slip through. Combine it with a read-only link where you can, revoke links when you are done, and rotate any credential you notice in a transcript.
Which assistants work with a share link?
A share link is a URL, so any assistant that can fetch one works - Claude and ChatGPT included. The hosted MCP endpoint and OAuth sign-in were built and tested with Claude Code and Claude.ai custom connectors. Cursor picks up the server's rules through the context files the GitHub integration can add to your repository.
What happens if someone else gets hold of my link?
They get exactly what the link allows, inside its rate limits, until it expires or you revoke it. A read link shows context and logs with secrets withheld; a link that can act can also edit files and restart the server, which is why those die after 24 hours idle. Revoke it on the Connected AI page and it answers 404 from the next request.
Can a link delete my server or touch my backups?
No. Deleting, reinstalling, renaming, backups, schedules, users, startup settings and databases are outside every link and every OAuth level, so they always need you in the panel.
Do I have to delete old links?
No. Read links expire 7 days after their last use and links that can act after 24 hours, with hard ceilings of 90 and 30 days. Making a new link for the same purpose replaces the old one. Revoking is still the right habit when you finish a task.


