T01 · Skill Instruction Hijacking
- Location
SKILL.md:24- Finding
Mutable Remote Instructions Can Control Agent Command Execution
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears to be a real LDM OS installer, but it makes broad persistent changes to agent, shell, credential, and system tooling behavior that require careful review before installation.
Install only if you want LDM OS to manage multiple AI harnesses at a deep system level. Before running `ldm init` or `ldm install`, review the dry run, check whether you have `~/.openclaw/secrets/op-sa-token`, and be aware that installation can persistently change Claude hooks, MCP configuration, shell startup behavior, crontab entries, and local agent message/context handling.
SKILL.md:24Mutable Remote Instructions Can Control Agent Command Execution
bin/ldm.js:466Routine Installation Registers Persistent Agent Context-Injection and Autonomous Rewake Hooks
bin/ldm.js:2080Installer Exposes a 1Password Service-Account Token to All Future Shell Descendants
bin/ldm.js:1258Initialization Installs a Recurring Task That Force-Kills Unrelated npm Processes
bin/ldm.js:1233Initialization Changes the Global Git Hooks Path for Every Repository
Lines L047-L056 describe querying ~/Library/Messages/chat.db to ingest conversation contents. Accessing private user communications is not an obvious or necessary capability for installing, updating, or checking status of LDM OS, making it context-inappropriate for the declared skill purpose.
The code appends an OP_SERVICE_ACCOUNT_TOKEN export block to shell startup files so future shells, hooks, MCP servers, cron jobs, and launch agents inherit access to secrets. Persistently wiring a secrets-bearing environment variable into the user's login shell is a powerful credential-propagation capability that is not justified by a manifest limited to LDM OS install/update/status.
The registerSkillTools path turns discovered OpenClaw skills into callable MCP tools and executes their scripts via executeSkillScript. A skill whose stated purpose is installing or updating LDM OS does not obviously require broad arbitrary script execution across unrelated skills.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Manifest-driven `ldm install` no longer appends a duplicate SessionStart boot-hook entry to `~/.claude/settings.json`. The boot hook now has a single registrar.
`lib/deploy.mjs` `installClaudeCodeHookEvent()` matched existing hook entries by an extension-dir tag (`/<toolName>/` in the command). The boot hook's deployed command is `node ~/.ldm/shared/boot/boot-hook.mjs`, which contains no `/wip-ldm-os/` segment, so the ownership check never recognized the existing entry and appended a fresh one on every manifest-driven install. This was the mechanism behind the ongoing accumulation (10 entries found 2026-07-04, then re-growing 3 -> 4 -> 5 through the day as installs ran); PR #1086 fixed only the `src/boot/installer.mjs` registration path, not this one.
Detected: suspicious.dangerous_exec, suspicious.destructive_delete_command, suspicious.env_credential_access (+3 more)