http-shell-exec
ClawHub-compliant OpenClaw code-plugin that runs only whitelisted local commands, exposed over a token-protected loopback HTTP service and a Gateway RPC method.
- Default bind:
127.0.0.1:18990 - Health:
GET /health - Run:
POST /run(requiresAuthorization: Bearer <token>) - Gateway RPC:
httpshell.run(params{ name, args? })
This plugin never invokes a shell, never accepts arbitrary commands, and refuses to start unless a bearer token is configured. The default whitelist is empty — the operator must opt in to specific commands.
Layout
http-shell-exec/
├── package.json # ClawHub-required code-plugin manifest
├── openclaw.plugin.json # Plugin runtime manifest (id, services, gateway, configSchema, ...)
├── index.ts # Source entry (referenced by openclaw.extensions)
├── dist/index.js # Compiled runtime entry (referenced by openclaw.runtimeExtensions)
├── tsconfig.json
├── README.md
├── LICENSE
├── .clawhubignore
└── .gitignore
ClawHub publish
Build first, then publish via the clawhub CLI:
npm install # one-time, dev-only deps (typescript, @types/node)
npm run build # produces dist/index.js + dist/index.d.ts
# Optional: produce a ClawPack tarball locally to verify shape.
clawhub package pack ./
# Real publish (first publish must be manual, by a logged-in package owner).
clawhub package publish ./ \
--family code-plugin \
--source-repo your-org/http-shell-exec \
--source-commit "$(git rev-parse HEAD)"
After publish, you can verify it on the registry:
clawhub package readiness http-shell-exec
clawhub package inspect http-shell-exec
For CI-driven trusted publishing, configure once:
clawhub package trusted-publisher set http-shell-exec \
--repository your-org/http-shell-exec \
--workflow-filename publish.yml
Then publish from a GitHub Actions workflow that mints a publish token via /api/v1/publish/token/mint (uses the workflow's OIDC ID token).
Local install (OpenClaw host)
openclaw plugins install ./http-shell-exec --link
openclaw plugins enable http-shell-exec
openclaw config set 'plugins.entries["http-shell-exec"].config.token' '"CHANGE_ME_STRONG_TOKEN"'
openclaw gateway restart
The plugin will refuse to start until token is set.
Configure a whitelist
Each command runs as execFile(bin, args, { shell: false, env: {} }). There is no shell expansion. bin must be an absolute path. allowUserArgs: true lets callers append extra argv; default is false.
openclaw config set 'plugins.entries["http-shell-exec"].config.commands' '{
uptime: { bin: "/usr/bin/uptime" },
whoami: { bin: "/usr/bin/whoami" },
disk: { bin: "/bin/df", args: ["-h"] },
ls_logs: {
bin: "/bin/ls",
args: ["-lah", "/tmp/openclaw"],
allowUserArgs: false
}
}'
openclaw gateway restart
Avoid putting
/usr/bin/env npx ...style entries withallowUserArgs: truein the whitelist — that effectively re-opens "any npm package as a command" and will be flagged by the ClawHub LLM risk evaluator.
Use
HTTP
# Health
curl -s http://127.0.0.1:18990/health
# Run a whitelisted command
curl -s http://127.0.0.1:18990/run \
-H 'Authorization: Bearer CHANGE_ME_STRONG_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"uptime"}'
# With user args (only when the command sets allowUserArgs: true)
curl -s http://127.0.0.1:18990/run \
-H 'Authorization: Bearer CHANGE_ME_STRONG_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"some_cmd","args":["--version"]}'
Gateway RPC
{
"method": "httpshell.run",
"params": { "name": "uptime", "args": [] }
}
Both surfaces share the exact same whitelist + token enforcement.
Configuration reference
Everything below is also encoded in openclaw.plugin.json#configSchema, which ClawHub uses to render the config UI.
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | false | Master switch. Plugin will not start when false. |
host | string | "127.0.0.1" | Keep on loopback. |
port | number | 18990 | TCP port. |
token | string | (required) | Bearer token. Plugin will not start when missing. |
maxRequestBodyBytes | number | 32768 | Max POST body. |
defaultTimeoutMs | number | 10000 | Default exec timeout. |
defaultMaxBuffer | number | 1048576 | Default stdout/stderr cap. |
commands | map | {} | Whitelist; see below. |
Each entry in commands:
| Field | Type | Default | Notes |
|---|---|---|---|
bin | string | (required) | Absolute path to binary. |
args | string[] | [] | Fixed leading argv. |
cwd | string | (cwd) | Working directory. |
timeoutMs | number | inherit | Per-command timeout override. |
maxBuffer | number | inherit | Per-command buffer override. |
allowUserArgs | boolean | false | Allow callers to append argv. |
Capabilities surfaced to ClawHub
| Source | Field | Value |
|---|---|---|
package.json | openclaw.compat.pluginApi | ^1.0.0 |
package.json | openclaw.build.openclawVersion | 2026.5.0 |
package.json | openclaw.extensions | ["./index.ts"] |
package.json | openclaw.runtimeExtensions | ["./dist/index.js"] |
package.json | openclaw.hostTargets | darwin/linux × arm64/x64 |
package.json | openclaw.environment | requiresDesktop, binaries, osPermissions |
openclaw.plugin.json | id | http-shell-exec |
openclaw.plugin.json | kind | context-engine |
openclaw.plugin.json | services[] | http-shell-exec-service |
openclaw.plugin.json | gatewayMethods[] | httpshell.run |
openclaw.plugin.json | httpRoutes[] | GET /health, POST /run |
openclaw.plugin.json | configSchema | required token, full whitelist schema |
These map directly into the packageCapabilities rows ClawHub indexes for browsing and filtering.
Security checklist
- Loopback only by default (
127.0.0.1). - Bearer token required; plugin refuses to start without one.
- No shell, no string concatenation;
execFilewithshell: false. - Whitelist required; default is empty.
-
binmust be an absolute path. - Per-request body cap, per-command timeout, per-command buffer cap.
- Empty environment (
env: {}) for spawned processes — no inherited secrets. - Constant-time-ish bearer comparison.
- No
allowUserArgsdefaults; operator must opt in per command.
Uninstall
openclaw plugins disable http-shell-exec
openclaw plugins uninstall http-shell-exec
openclaw gateway restart