T06 · System Persistence
Error
- Location
- scripts/install-auto.sh:28
- Finding
- Persistent LaunchAgent Automatically Executes the Renderer Injection Pipeline<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install-auto.sh:28-46`; supporting execution loop at `scripts/watch.sh:10-21` **Vulnerability Type**: Cross-session startup persistence **Risk Level**: High ### Complete Code Snippet From `scripts/install-auto.sh`: ```sh cat > "$PLIST" <<EOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key><string>${LABEL}</string> <key>ProgramArguments</key> <array><string>/bin/bash</string><string>$ROOT/scripts/watch.local.sh</string></array> <key>RunAtLoad</key><true/> <key>KeepAlive</key><true/> <key>StandardOutPath</key><string>$ROOT/scripts/watch.log</string> <key>StandardErrorPath</key><string>$ROOT/scripts/watch.log</string> </dict> </plist> EOF launchctl bootout "gui/$(id -u)/${LABEL}" 2>/dev/null || true launchctl bootstrap "gui/$(id -u)" "$PLIST" ``` From `scripts/watch.sh`: ```sh LAST_PID="" while true; do PID=$(pgrep -f "WorkBuddy.app/Contents/MacOS/Electron" | head -1) if [ -z "$PID" ]; then LAST_PID="" elif [ "$PID" != "$LAST_PID" ]; then if curl -s --max-time 1 "http://127.0.0.1:${PORT}/json/list" 2>/dev/null | grep -q "renderer/index.html"; then "$NODE" "$ROOT/src/apply.mjs" >>"$ROOT/scripts/watch.log" 2>&1 && LAST_PID=$PID fi fi sleep 2 done ``` ### Technical Analysis The installer creates `~/Library/LaunchAgents/com.workbuddy.skin.plist`, enables both `RunAtLoad` and `KeepAlive`, and immediately loads the service with `launchctl bootstrap`. The resulting process remains active across user sessions and repeatedly invokes `src/apply.mjs` when it detects a new WorkBuddy process. The LaunchAgent executes scripts directly from the project directory. Consequently, later modifications to `watch.local.sh`, `apply.mjs`, `inject.js`, or related payload files will be executed automatically under the logged-in user's accoun ...[truncated 1595 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove the LaunchAgent and require explicit, per-session user invocation. 2. Do not use `KeepAlive` for a cosmetic theme operation. 3. If automatic startup is retained: - Require clear, informed user consent before installation. - Install a fixed, minimal payload in a protected application-support directory. - Verify cryptographic hashes or signatures before every execution. - Refuse to execute payload files that are writable by other users. - Use `RunAtLoad` only if strictly necessary and avoid an infinite polling loop. 4. Provide a complete uninstall procedure that unloads the service, removes the plist, stops active watcher processes, and removes generated files. 5. Display the exact persistence location and active status during installation. 6. Limit the persistent component to detecting startup; require fresh user approval before renderer injection. ]]>
