Skip to content

fix: CLI/installer hardening — restart labels, key permissions, unit-secret escaping (#113)#120

Merged
dtzp555-max merged 1 commit into
mainfrom
fix/113-cli-installer
May 31, 2026
Merged

fix: CLI/installer hardening — restart labels, key permissions, unit-secret escaping (#113)#120
dtzp555-max merged 1 commit into
mainfrom
fix/113-cli-installer

Conversation

@dtzp555-max

Copy link
Copy Markdown
Owner

Summary

Fixes the three CLI/installer hardening findings from the 2026-05-31 audit (#113, P2). No server.mjs.

  1. ocp-plugin restart — was gui/501/ai.openclaw.proxy (hardcoded uid + legacy label) with a dangerous pkill -f 'node.*server.mjs' && … node server.mjs & fallback (could kill an unrelated node process + relaunch an env-less ghost proxy). Now process.getuid() + live labels (dev.ocp.proxy macOS / ocp-proxy Linux systemd; OpenClaw gateway label unchanged); pkill fallback removed (returns a manual ocp restart message).
  2. ocp-connect key persistence — single-quotes the persisted OPENAI_API_KEY/OPENAI_BASE_URL and chmod 600s the rc files + the Linux environment.d/ocp.conf (was world-readable; matches the existing auth-profiles.json 0o600 convention).
  3. setup.mjs unit-secret escapingxmlEscape() on all plist <string> values; assertSafeInjectValue() rejects control chars (\x00-\x1f) in the 3 injected secrets before any unit is written, blocking a newline-injected rogue Environment= directive. Spaces intentionally allowed (CLAUDE_BIN paths). XML-escaping on write transitively resolves plist-merge.mjs's [^<]* regex concern (comment added, logic unchanged).

ALIGNMENT.md

  • cli.js citation: N/A — CLI/installer scripts, no Anthropic operation forwarded.
  • No blacklisted tokens / port literals; alignment.yml passes (server.mjs untouched).
  • Independent reviewer (Iron Rule 10): fresh-context opus reviewer verified the control-char regex byte-exact via od (no space-rejection regression — the one subtle risk here), the pkill/server.mjs &/shell:true fallback fully removed, restart labels match setup.mjs ground truth, OCP keys (base64url) cannot break the single-quoting, and the validator runs before any write. npm test163 passed, 0 failed. Verdict APPROVE.

Notes

  • ⚠️ setup.mjs/ocp-connect/launchctl were not executed during implementation or review (live-host isolation).
  • Nit (non-blocking, from review): a user-supplied --key containing a literal ' would break the rc single-quoting — but that's not an OCP-minted key, and the change is strictly safer than the prior unquoted form.

Closes #113.

🤖 Generated with Claude Code

…secret escaping (#113)

Three CLI/installer findings from the 2026-05-31 audit (no server.mjs):

1. ocp-plugin `cmdRestart` hardcoded uid 501 + the legacy `ai.openclaw.proxy`
   label, and fell through to a dangerous `pkill -f 'node.*server.mjs' && cd
   ~/.openclaw/projects/*/; node server.mjs &` that could kill an unrelated node
   process and relaunch an env-less ghost proxy from a glob-ambiguous dir. Now uses
   process.getuid() + the live labels (dev.ocp.proxy on macOS, ocp-proxy on Linux
   systemd; the OpenClaw gateway label is unchanged) and drops the pkill fallback
   entirely (returns a manual `ocp restart` message on failure).

2. ocp-connect wrote the quota key unquoted into rc files and a world-readable
   environment.d/ocp.conf. Now single-quotes the value and chmod 600s the rc files
   and ocp.conf (matching the existing auth-profiles.json 0o600 convention).

3. setup.mjs interpolated the injected service-unit secrets (CLAUDE_BIN,
   OCP_ADMIN_KEY, PROXY_ANONYMOUS_KEY) raw into plist <string> and systemd
   Environment= lines. Added xmlEscape() for all plist <string> values and
   assertSafeInjectValue() which rejects control characters (\x00-\x1f — newline,
   CR, tab) before any unit is written, blocking a newline-injected rogue
   Environment= directive. Spaces are intentionally allowed (CLAUDE_BIN paths may
   contain them). XML-escaping on write also resolves plist-merge.mjs's [^<]* regex
   concern transitively (no raw < reaches it) — comment added, logic unchanged.

ALIGNMENT.md: CLI/installer scripts only, no Anthropic operation forwarded → cli.js
citation N/A. No blacklisted tokens or port literals introduced; alignment.yml passes.

Independent fresh-context reviewer (opus): APPROVE (Iron Rule 10) — verified the
control-char regex byte-exact via od (no space-rejection regression), the pkill
fallback fully removed, restart labels match setup.mjs ground truth, OCP keys
(base64url) cannot break the single-quoting, and the validator runs before any write.

Closes #113.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dtzp555-max dtzp555-max merged commit 68d58e7 into main May 31, 2026
5 checks passed
@dtzp555-max dtzp555-max deleted the fix/113-cli-installer branch May 31, 2026 12:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] CLI/installer hardening (ocp-plugin restart, ocp-connect key chmod, plist/systemd escaping)

2 participants