Last week a developer I know ran a routine refactor through a coding agent on a free remote server. The agent finished, the diff looked clean, and the commit was pushed. Three days later someone noticed the commit author was the developer's personal name and email, and the run directory contained a .env
file with a staging database password. Nothing was exploited, but nothing had to be. The damage was the assumption that a free server behaves like a laptop.
Here is my position: when you accept a free server for agent work, the model is not the risk and the token quota is not the constraint. The boundary between your machine and the remote host is the risk, and most agent workflows treat that boundary as if it did not exist.
MonkeyCode's open-source agent project makes this concrete because it bundles two things that are usually sold separately: free model access with a 10 million token allowance as of this writing, and a free server option. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The token number gets the attention, but the server is the part that demands a different security posture.
The default assumption for any free server should be that you do not control it. You do not know who else is on the host, what is logged, or how long logs persist. That does not mean the server is malicious. It means your workflow should survive a host that is shared, monitored, and eventually recycled.
The first broken assumption is that your environment variables will be present. They will not, and the natural reaction is to pass them explicitly, which is exactly how a production key ends up in a run log.
The second is that your personal git identity is fine to reuse. It is not. Agent commits under your name create a trail that is hard to clean, and they make every future commit harder to trust.
The third is that the output is just code. The output is also logs, temporary files, and sometimes copied configuration. Every run directory is a potential leak, so it should be treated as one until it is scanned.
The artifact that matters is a wrapper that builds a deliberately small environment for each remote run. The script below is a shape, not a promise, because the exact CLI flags depend on the current MonkeyCode release.
#!/usr/bin/env bash
set -euo pipefail
TASK_FILE="${1:?usage: sanitize-agent-env.sh task.md}"
ENV_FILE="${2:?usage: sanitize-agent-env.sh task.md .env.agent}"
RUN_DIR="${RUN_DIR:-./runs/$(date +%Y%m%d-%H%M%S)}"
mkdir -p "$RUN_DIR"
env -i \
PATH="$PATH" \
HOME="$HOME" \
TZ="UTC" \
LANG="C.UTF-8" \
"$(command -v monkeycode)" \
--task "$TASK_FILE" \
--env-file "$ENV_FILE" \
--output "$RUN_DIR" \
> "$RUN_DIR/stdout.log" 2>&1
STATUS=$?
echo "agent exited with $STATUS"
tail -n 20 "$RUN_DIR/stdout.log" > "$RUN_DIR/summary.log"
exit $STATUS
The env -i
flag is the point. It starts the agent with nothing except what you explicitly allow, which means a stray shell variable cannot leak into the remote process. The companion file is a scoped credential set:
GITHUB_ACTOR=agent-bot
GITHUB_TOKEN=ghp_shortlived_placeholder
NPM_CONFIG_REGISTRY=https://registry.npmjs.org/
This file is still a secret, but it is a small, disposable secret. Treat it like a temporary badge rather than a house key.
The second artifact is a scanner that runs over the agent output before you open it. The pattern list below is a starting point, not a complete policy.
#!/usr/bin/env bash
set -euo pipefail
RUN_DIR="${1:?usage: scan-agent-output.sh run-dir}"
PATTERNS=(
'AKIA[0-9A-Z]{16}'
'ghp_[A-Za-z0-9]{36}'
'sk-[A-Za-z0-9]{20,}'
'-----BEGIN [A-Z ]*PRIVATE KEY-----'
'password[[:space:]]*=[[:space:]]*[A-Za-z0-9_./:-]+'
)
FAIL=0
for pattern in "${PATTERNS[@]}"; do
if grep -rInE "$pattern" "$RUN_DIR" 2>/dev/null; then
echo "!! matched: $pattern"
FAIL=1
fi
done
if [[ $FAIL -eq 0 ]]; then
echo "==> no secret patterns found in $RUN_DIR"
else
echo "==> SECRETS FOUND. Review before sharing or committing."
exit 1
fi
Run this before you read the diff, before you commit anything, and definitely before you push a run directory to a repository. The scanner is not a guarantee, but it changes the default from "hope nothing leaked" to "check that nothing leaked."
| Data | Free server? | Reason |
|---|---|---|
| Public repo source | Yes | Already public |
| Personal git identity | No | Use an agent-bot identity |
Production .env |
||
| No | Build a scoped .env.agent |
|
| Short-lived registry token | Only if scoped | Assume the host is shared |
| Customer or personal data | No | Not your call to make |
The pattern is consistent: anything that is public or disposable can go. Anything that identifies you or grants long-lived access stays home.
If your compliance rules require code to stay on machines you control, a free server is not a place for your agent, no matter how clean the environment wrapper is. If your organization centralizes secrets in a vault, a .env.agent
file is a step backward even when it is scoped. And if you cannot issue short-lived credentials for the services your agent touches, the residual risk of a leaked long-lived token is probably not worth the free compute.
This pattern is for solo developers and small teams who want the economics of free agent runs without importing their whole identity into a shared host.
The free server is useful precisely because it is disposable. You can run an experiment, lose the whole host, and lose nothing except the run. That property is an advantage only if you actually treat it as disposable: minimal credentials, a separate identity, and a scan before you trust the output. The agent will still do the work. You just will not be the person who accidentally ships a key.
If you want to test this discipline, MonkeyCode's free server is a cheap place to start, but start with a task that touches no secrets and run the scanner before you read the output.