T03 · Remote Payload Retrieval and Execution
- Location
scripts/openclaw-growth-start.mjs:1348- Finding
Unpinned Remote Installer Is Downloaded and Executed Through a Shell
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a real growth automation skill, but it needs Review because it can install and update code, run on a schedule, and handle valuable credentials with several concrete security weaknesses.
Install only if you want a broad local growth-automation system, not a read-only advice prompt. Use a dedicated workspace and least-privileged OS/user account, disable or review self-update and recurring cron behavior if you need reproducible reviewed code, avoid the curl-to-bash ASC installer path, and prefer a keychain or secret manager over plaintext token files. Grant provider tokens the minimum read/write scopes needed and enable GitHub issue/PR creation only when you explicitly want the skill to mutate repository state.
scripts/openclaw-growth-start.mjs:1348Unpinned Remote Installer Is Downloaded and Executed Through a Shell
scripts/export-sentry-summary.mjs:380Sentry Pagination Can Forward Bearer Tokens to an Attacker-Controlled Origin
scripts/openclaw-growth-start.mjs:1207RevenueCat and Sentry Tokens Are Persisted in Plaintext Without Permission Hardening
The generated secret-runner install script creates system users, writes executables into /usr/local/bin, migrates secrets, and installs sudoers rules granting passwordless execution as another user. This is a major privilege-boundary modification that can create durable escalation pathways if wrapper commands or downstream scripts are ever subverted.
The public description presents a growth-analysis skill, but the content authorizes software installation, shell-profile mutation, PATH changes, and local bootstrap behavior. This mismatch can mislead users and policy systems into granting trust or execution to a skill whose operational impact is much broader than advertised.
The public description presents a growth-analysis skill, but the content authorizes software installation, shell-profile mutation, PATH changes, and local bootstrap behavior. This mismatch can mislead users and policy systems into granting trust or execution to a skill whose operational impact is much broader than advertised.
Referenced artifact was not completely inspected
- Copied-runtime scripts under `scripts/openclaw-growth-*.mjs` remain the compatibility path for agents that install this as a plain `SKILL.md` folder
Referenced artifact was not completely inspected
- The cron/system-event prompt must invoke `node scripts/openclaw-growth-runner.mjs --config <active-config> --state <active-config-dir>/state.json`. Do not let
Referenced artifact was not completely inspected
- The cron/system-event prompt must invoke `node scripts/openclaw-growth-runner.mjs --config <active-config> --state <active-config-dir>/state.json`. Do not let
The skill explicitly contemplates modifying itself directly for upstream fixes, which normalizes self-modification of trusted instructions. In agent systems, self-edit capability undermines auditability and can let a compromised or misrouted workflow alter future behavior persistently.
Treat this installed skill as vendor-managed and replaceable.
Agents should almost never edit this skill in-place for user- or project-specific customization, because future skill updates may overwrite local changes.
When the user wants custom behavior, create a separate companion skill or project-local customization skill instead, for example `openclaw-growth-custom`, and have that skill reference or layer on top of this one.
Only modify this skill directly when the change is intended as an upstream reusable fix for the canonical skill repository.
## Setup DX Rules
The skill standardizes collecting and loading multiple high-value credentials from a local secrets.env file. While local secret storage can be appropriate, centralizing broad third-party tokens and instructing the runtime to auto-load them materially increases blast radius if the host, process, logs, or downstream tools are compromised.
- After each setup phase, summarize only the result and the next concrete action.
- Keep secrets out of prompts, repo files, logs, and command arguments; prefer host-agent secret storage or environment injection.
- Never ask the user to paste API keys, GitHub tokens, or App Store Connect `.p8` private-key contents into Discord, OpenClaw chat, Hermes chat, GitHub issues, PRs, or any shared transcript. Chat is not an appropriate secret transport.
- For secrets, give a secure host-terminal path: set env vars in the runtime shell, an agent secret store, a password manager injection flow, or the wizard-managed `~/.config/openclaw-growth/secrets.env` with `chmod 600`. Growth commands must load that env file automatically. For ASC `.p8`, prefer asking for the local file path to Apple's original downloaded file name `AuthKey_<KEY_ID>.p8`; do not rename the file because the wizard derives the key id from that name. Pasted `.p8` content is only a fallback. Store only `ASC_PRIVATE_KEY_PATH` and never echo the private key back.
- When SDK instrumentation is missing or weak, guide the developer through the `analyticscli-ts-sdk` setup path so analytics events become useful for later growth analysis.
- If AnalyticsCLI has no default project and multiple projects are visible, do not report that as a hard error. List the available projects, ask the user which one to use, persist the choice with `openclaw start --config openclaw.config.json --project <project_id>` or `analyticscli projects select <project_id>`, and then retry the setup/run.
Referenced artifact was not completely inspected
node scripts/openclaw-growth-status.mjs --config data/openclaw-growth-engineer/config.json --json
Referenced artifact was not completely inspected
node scripts/openclaw-growth-status.mjs --config data/openclaw-growth-engineer/config.json --json
Instructing status commands to automatically load secrets into the process environment expands credential exposure to routines that may not strictly need all tokens. This increases the chance of accidental disclosure through subprocesses, debugging output, or compromise of auxiliary tooling.
node scripts/openclaw-growth-status.mjs --config data/openclaw-growth-engineer/config.json --json
~/.config/openclaw-growth/secrets.env, runs live connector checks, and treats GitHub code access separately from GitHub issue/PR delivery.connected; otherwise list only the non-connected connector names and the status command's next action.The documented pattern has users manually edit a plaintext secrets file containing valuable API keys and paths to private keys. Even with restrictive permissions, plaintext secret files are a sensitive target and increase persistence of credential exposure on disk.
install -d -m 700 ~/.config/openclaw-growth
umask 077
$EDITOR ~/.config/openclaw-growth/secrets.env
# add lines like:
# REVENUECAT_API_KEY=...
# ASC_KEY_ID=...
This continues the same secret-on-disk pattern and explicitly normalizes storage of several sensitive credentials in a file. The danger is compounded by the skill's broad automation and repeated command execution, which may load those secrets frequently.
chmod 600 ~/.config/openclaw-growth/secrets.env
- Good `.p8` pattern: keep Apple's original downloaded file name `AuthKey_<KEY_ID>.p8`, then paste only that local file path into the terminal wizard. Do not rename the file; the wizard derives `ASC_KEY_ID` / `ASC_BOOTSTRAP_KEY_ID` from the file name. Pasting the full `.p8` content is only a fallback when the file is not available on the host.
- OpenClaw Growth commands load the wizard-managed env file automatically; never put secrets in command-line args.
The ASC setup flow involves multiple privileged API keys and local handling of .p8 private keys, with some values persisted via environment-based secret storage. This is inherently high risk because compromise of those credentials can expose app analytics, reports, and potentially broader App Store Connect data depending on granted roles.
- Say ASC setup uses two API keys: a Reports key with `Sales and Reports` for ongoing Growth Engineer downloads, plus a temporary Setup key with `Admin` used once to create the initial App Analytics report request. `Finance` or `Admin` also works for ongoing report downloads, but prefer `Sales and Reports` after bootstrap. Add `Customer Support` for App Store ratings/review text, `Developer` for builds/TestFlight/delivery status, and `App Manager` only when app metadata, pricing, or release settings are needed.
- Tell the user to copy `ASC_ISSUER_ID` from the API keys page, download both `.p8` files, keep Apple's original `AuthKey_<KEY_ID>.p8` file names, and paste the local file paths into the terminal wizard. Do not tell them to rename the `.p8`; the wizard derives `ASC_KEY_ID` and `ASC_BOOTSTRAP_KEY_ID` from the file names.
- Store only env vars/secrets: `ASC_KEY_ID`, `ASC_ISSUER_ID`, and `ASC_PRIVATE_KEY_PATH`; the wizard can still create the `.p8` file from validated pasted terminal content as a fallback. Never commit the `.p8` private key.
- The Setup Admin key is not saved to `secrets.env`. The wizard keeps the temporary secure `.p8` copy on the host and tells the user to revoke the Admin key in App Store Connect after setup.
- Do not ask for `ASC_APP_ID` upfront. After auth succeeds, ASC should use all accessible apps by default. Store an app filter only if the user explicitly asks to scope ASC to one app.
- After the key is present, run one read-only API-key `asc` smoke test before marking ASC connected. Do not check `asc web auth` and do not force a target app selection; default ASC analysis covers all accessible apps.
- Prefer `asc auth login` when the local `asc` CLI supports keychain storage; otherwise use runtime env injection.
Referenced artifact was not completely inspected
- Use the direct Sentry API exporter as the canonical growth source: `node scripts/export-sentry-summary.mjs`.
The startup protocol mandates updating the skill before operation, creating a self-refresh path that can change future behavior on each run. Combined with unpinned package fetching, this materially increases persistence and supply-chain risk.
When the user says "start", "run", or "kick off" the skill:
1. Run the Dependency Refresh Protocol first. It must update this skill, the `analyticscli-cli` skill when available, and the `@analyticscli/cli` npm package, then verify `command -v analyticscli`.
2. If setup is incomplete, connectors are not selected, AnalyticsCLI auth is missing/invalid, or the host is Hermes, route the user to the bundled wizard before any preflight/start run.
- In Hermes chat/Discord/non-interactive terminals, do not run the wizard yourself. Show the full command below and tell the user to paste it into the VPS/host shell.
- Only run this command yourself when you are already operating inside an interactive user terminal that can safely receive secret input outside chat.
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
Use the legacy bootstrap-and-copy runtime only when the standalone CLI is unavailable in the target workspace.
## Output Rules
- max 3-5 proposals per pass
- each proposal must include measurable impact and file/module hypotheses
The skill explicitly documents persisted secrets in a local secrets.env file and marks them as agent-readable via runtime secret resolution. In the context of an automation skill that also runs external commands and can create issues or PRs, this increases the blast radius of prompt injection, command abuse, or local file exfiltration because valuable API tokens are centrally stored and accessible to the runtime.
"mode": "openclaw-secret-refs",
"persisted": true,
"agentReadable": "runtime_resolves_secret_refs",
"secretsFile": "~/.config/openclaw-growth/secrets.env"
}
},
"secrets": {
The script contains a self-update path that forcibly updates the installed skill during bootstrap, which is a strong form of self-modification. In security terms this is dangerous because a local setup action can mutate the executing toolchain by pulling new code from an external source, bypassing normal review expectations and compounding supply-chain compromise impact.
WORKSPACE="$(cd "${SKILL_ROOT}/../.." && pwd)"
fi
if [[ ( "${skill_slug}" == "growth-engineer" || "${skill_slug}" == "openclaw-growth-engineer" ) && -f "${SKILL_ROOT}/.clawhub/origin.json" && "${OPENCLAW_GROWTH_DISABLE_SELF_UPDATE:-}" != "1" && "${OPENCLAW_GROWTH_BOOTSTRAP_SKIP_UPDATE:-}" != "1" ]]; then
if command -v clawhub >/dev/null 2>&1; then
(cd "${WORKSPACE}" && clawhub --no-input --dir skills update "${skill_slug}" --force) || true
elif command -v npx >/dev/null 2>&1; then
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const token = process.env.DISCORD_BOT_TOKEN?.trim();
if (!token) {
throw new DiscordBridgeError(
"DISCORD_BOT_TOKEN is required. Put it in .env or export it in your shell.",
);
}
return token;
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const token = process.env.DISCORD_BOT_TOKEN?.trim();
if (!token) {
throw new DiscordBridgeError(
"DISCORD_BOT_TOKEN is required. Put it in .env or export it in your shell.",
);
}
return token;
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const token = process.env.DISCORD_BOT_TOKEN?.trim();
if (!token) {
throw new DiscordBridgeError(
"DISCORD_BOT_TOKEN is required. Put it in .env or export it in your shell.",
);
}
return token;
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const token = process.env.DISCORD_BOT_TOKEN?.trim();
if (!token) {
throw new DiscordBridgeError(
"DISCORD_BOT_TOKEN is required. Put it in .env or export it in your shell.",
);
}
return token;
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const token = process.env.DISCORD_BOT_TOKEN?.trim();
if (!token) {
throw new DiscordBridgeError(
"DISCORD_BOT_TOKEN is required. Put it in .env or export it in your shell.",
);
}
return token;
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const token = process.env.DISCORD_BOT_TOKEN?.trim();
if (!token) {
throw new DiscordBridgeError(
"DISCORD_BOT_TOKEN is required. Put it in .env or export it in your shell.",
);
}
return token;
Detected: suspicious.dangerous_exec, suspicious.env_credential_access, suspicious.potential_exfiltration