Agent Economy Report

Skill code audit

CAUTION version 1.0.11 · audited 2026-09-17

free-ride @shaivpidadi

FreeRide is a Python CLI and optional watcher that selects free OpenRouter models and updates the OpenClaw configuration so the agent uses those models with fallbacks. It reads the OpenRouter API key from the environment or from ~/.openclaw/openclaw.json, sends it to OpenRouter only, and writes model and fallback entries to the OpenClaw config plus local cache and state files. The watcher can run continuously and automatically rewrite the model chain when the current model fails. No hidden network destinations, shell execution, download-and-execute, payment redirection, or boot persistence were found. However, the instructions and status output reveal part of the API key, the installer uses an unpinned @latest package, and an optional --setup-auth write goes beyond the frontmatter's declared config writes, so review is warranted.

Declared purposeManages free AI models from OpenRouter for OpenClaw. Automatically ranks models by quality, configures fallbacks for rate-limit handling, and updates openclaw.json.
Observed behaviorThe Python code fetches https://openrouter.ai/api/v1/models using the bearer key, filters free chat-shaped models, ranks them, and writes primary/fallback/allowlist entries to ~/.openclaw/openclaw.json. It also probes models via https://openrouter.ai/api/v1/chat/completions. The optional freeride-watcher loops, probes the current primary model, and calls rotate() to rewrite the config on failure. It writes ~/.openclaw/.freeride-cache.json and ~/.openclaw/.freeride-watcher-state.json locally. No exec, base64, hidden destinations, or boot-persistence mechanisms are present in the Python code.
Verdict, rules onlyCAUTION · reads credential-like environment variables: OPENROUTER_API_KEY
Verdict, AICAUTION
Final verdictCAUTION (never better than either pass)

Capabilities

capabilityvs purposedetail
networkneededContacts OpenRouter's API at openrouter.ai/api/v1/models and openrouter.ai/api/v1/chat/completions using the provided API key. README badge images contact separate domains but are not used by the Python code.
filesystem_readneededReads OPENROUTER_API_KEY from environment or ~/.openclaw/openclaw.json, and loads OpenClaw config, cache, and watcher state files.
filesystem_writeneededWrites ~/.openclaw/openclaw.json, ~/.openclaw/.freeride-cache.json, and ~/.openclaw/.freeride-watcher-state.json. It can also optionally write an OpenRouter auth profile.
credentialsneededProcesses OpenRouter API keys as Bearer tokens, supports a single key or JSON array of keys, and prints a partially masked key in status output.
install_packagesneededsetup.py requires requests>=2.31.0, and README/SKILL.md instruct pip install -e .; README also documents npx clawhub@latest install free-ride.
otherneededOptional freeride-watcher runs an interruptible background loop that probes the primary model and may rotate the config. It is user-started and has no auto-start persistence in the package.

Findings

severityfinding
mediumInstructs echoing the API secret
The instructions tell the agent or user to print the OpenRouter secret to the terminal, which can expose it in logs or to shoulder-surfing. skill-card.md line 25 also identifies the secret-check instructions as unsafe.
SKILL.md:28 1. **OPENROUTER_API_KEY is set.** Check with `echo $OPENROUTER_API_KEY`. If empty, the user must get a free key at https://openrouter.ai/keys and set it:
lowDeclared writes are narrower than optional code behavior
The frontmatter says only model and model-list keys are written, but main.py setup_openrouter_auth can add an auth profile when --setup-auth is used.
SKILL.md:12 - ~/.openclaw/openclaw.json (keys: agents.defaults.model, agents.defaults.models only)
infoPrimary network destination
The CLI fetches the available model list from this OpenRouter endpoint.
main.py:25 OPENROUTER_API_URL = "https://openrouter.ai/api/v1/models"
infoAPI key sent to OpenRouter
The OpenRouter API key is used as a Bearer token for OpenRouter API calls. The code does not send it to other domains.
main.py:40 "Authorization": f"Bearer {api_key}",
infoReads secret from OpenClaw config
If the key is not in the process environment, the tool extracts it from ~/.openclaw/openclaw.json.
main.py:111 raw = config.get("env", {}).get("OPENROUTER_API_KEY")
infoWrites model cache
Caches OpenRouter model data in ~/.openclaw/.freeride-cache.json.
main.py:279 CACHE_FILE.write_text(json.dumps(cache, indent=2))
mediumRewrites OpenClaw config
Saves the updated configuration to ~/.openclaw/openclaw.json. This is the tool's main intended effect and can alter the active model chain.
main.py:312 OPENCLAW_CONFIG_PATH.write_text(json.dumps(config, indent=2))
lowAdds OpenRouter auth profile beyond declared keys
When --setup-auth is used, the code writes an auth.profiles entry that the SKILL.md frontmatter did not list as a written key.
main.py:389 config["auth"]["profiles"]["openrouter:default"] = {
mediumStatus output reveals part of secret
The status command prints the first eight and last four characters of API keys, which is more revealing than a typical masked display.
main.py:678 masked = k[:8] + "..." + k[-4:] if len(k) > 12 else "***"
infoWatcher state writes
Writes watcher state atomically through a temporary file to ~/.openclaw/.freeride-watcher-state.json.
watcher.py:42 tmp.write_text(content)
infoLong-running watcher loop
The daemon repeatedly probes the configured primary model and can automatically rotate and rewrite config. It runs until interrupted.
watcher.py:117 while running:
infoDocumented background execution
README suggests running the watcher in the background with nohup, but this is user-initiated and not installed as system persistence.
README.md:199 nohup freeride-watcher > ~/.openclaw/freeride-watcher.log 2>&1 &
lowUnpinned @latest installer reference
The documented install command uses an unpinned latest package, which can pull future code changes unexpectedly.
README.md:50 npx clawhub@latest install free-ride

0 AI finding(s) were dropped because their file, line or quote did not match the package.

Network destinations in the code

domainservice ratingwhere
api.clawhub-badge.xyznot in the service indexREADME.md:5
clawhub.ainot in the service indexREADME.md:5
github.comnot in the service indexREADME.md:11
img.shields.ionot in the service indexREADME.md:10
openrouter.ainot in the service indexREADME.md:61
opensource.orgnot in the service indexREADME.md:10

Other facts

Binaries invokedbash, nohup, npx, pip, python3
Environment variables readOPENROUTER_API_KEY
Hard-coded walletsnone
Pipes a download to a shell0
eval / exec / subprocess0
base64 blobs0
File writes10
Persistence0

Files audited

filelinessha256
README.md318c0a12fd65dd0eeb9…
SKILL.md1199e016001b79fa853…
_meta.json6a65ca20da98a2094…
main.py10155bd3cdd63eed44e8…
requirements.txt165b777e1d69669e3…
setup.py255f532cac7bc7d35d…
skill-card.md65ccc3cb530117dcd3…
skill.json473104d740b4ea5dd1…
watcher.py18498608fccd64719e1…

For agents

JSON: https://agenteconomy.report/k/free-ride.audit.json · badge: https://agenteconomy.report/k/free-ride.audited.svg · skill rating: /k/free-ride · commission an audit of any skill: US$ 29 per version.

How this is computed

The complete published package of this exact version was downloaded from the registry and read statically; nothing was executed. A deterministic pass extracts network destinations, binaries, environment variables, writes, install commands, obfuscation markers, subprocesses and wallets, each with file and line. An AI then reads the whole package with those facts and writes the summary, the capabilities and the findings under a strict schema; every finding it produces must cite a file, a line and the exact text, or it is dropped. The final verdict is the worst of the two passes. The audit does not change the skill's trust tier (policy); the author may respond through the dispute channel and the response is published here. Commissioned by: the Agent Economy Report (free program: the 150 most downloaded skills, September 2026).