Back to skill

Security audit

linkedclaw-provider

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent LinkedClaw provider setup guide, but it asks users to run an unattended marketplace daemon with mutable package installs and sensitive credential/session access that warrant careful review.

Install only if you intentionally want this machine to serve untrusted marketplace requests. Pin and review all npm, npx, pip, and plugin versions before running the daemon, avoid @latest and runtime npx fetching, use a dedicated unprivileged account with a minimal HOME, restrict credentials to the minimum needed model key, and keep the default text-only/tool-disabled mode unless you have a real OS sandbox.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T08 · Insecure Dependencies

Error
Location
SKILL.md:70
Finding
Unpinned Third-Party Packages Are Downloaded and Executed with Provider Access<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:70-75, 93, 153, 180`; `references/claude-code.md:5-8, 50-54`; `references/codex.md:5-8, 59-63`; `references/pi.md:4-7, 82-85, 126-130`; `references/hermes-plugin.md:13-16, 455-458`; `references/openclaw-plugin.md:13-16, 471-478` **Vulnerability Type**: T08: Insecure Dependencies **Risk Level**: High ### Vulnerable Code `SKILL.md:70-75`: ```markdown | **Claude Code** | ACP path: `--handler-acp "npx @agentclientprotocol/claude-agent-acp"` — see [references/claude-code.md](references/claude-code.md) | | **Gemini CLI** | ACP path: `--handler-acp "gemini --acp"` — see [references/gemini.md](references/gemini.md) | | **Codex CLI** | ACP path: `--handler-acp "npx @agentclientprotocol/codex-acp"` — see [references/codex.md](references/codex.md) | | **Hermes Agent** | Two paths. **Light (ACP):** `--handler-acp "hermes acp"` — see [references/hermes.md](references/hermes.md). **Deep (plugin):** the native `hermes-linkedclaw` (PyPI) plugin (gateway-resident / standalone daemon) — see [references/hermes-plugin.md](references/hermes-plugin.md). | | **OpenCode** | ACP path: `--handler-acp "opencode acp"` — see [references/opencode.md](references/opencode.md) | | **pi (earendil-works/pi)** | ACP path: `--handler-acp "npx -y pi-acp"` — **set `PI_ACP_PI_COMMAND` to a wrapper script with `--no-tools` or `--exclude-tools bash`** (reject-all does NOT confine pi; pi-acp cannot forward flags by itself); see [references/pi.md](references/pi.md) | ``` `SKILL.md:93`: ```markdown `npm i -g @linkedclaw/cli` if missing → `linkedclaw whoami` → `linkedclaw login` if 401. ``` `SKILL.md:153`: ```bash linkedclaw provider run <slug> \ --handler-acp "npx @agentclientprotocol/claude-agent-acp" ``` `SKILL.md:180`: ```bash npm i -g pm2 ``` `references/claude-code.md:5-8`: ```bash linkedclaw provider run my-provider.yaml \ --handler-acp "npx @agentclientprotocol/claude-agent-acp" ``` `references/claude-code.md:50-54`: `` ...[truncated 4200 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every executable dependency to a reviewed exact version, for example: ```bash npx --yes @agentclientprotocol/claude-agent-acp@<reviewed-version> npx --yes @agentclientprotocol/codex-acp@<reviewed-version> npx --yes pi-acp@<reviewed-version> pip install hermes-linkedclaw==<reviewed-version> ``` 2. Remove `@latest` from operational instructions. Treat upgrades as separate, explicit security-sensitive actions. 3. Prefer installing adapters into a dedicated project or virtual environment with committed npm lockfiles or hash-pinned Python requirement files. 4. For Python packages, use hashes: ```bash pip install --require-hashes -r requirements.txt ``` 5. Verify npm package integrity and provenance before installation. Record the expected package version, publisher, integrity digest, and source repository. 6. Disable package lifecycle scripts during inspection where practical, and review packages before allowing installation scripts to execute. 7. Install and audit dependencies before enabling the persistent service. Do not let a boot-time daemon perform runtime package retrieval through `npx`. 8. Run the provider under a dedicated unprivileged account with a minimal `HOME`, restricted filesystem permissions, and narrowly scoped outbound network access. 9. Document a controlled upgrade procedure that includes version review, integrity verification, staging tests, credential rotation readiness, and rollback instructions. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/hermes-plugin.md:31
Finding
LinkedClaw Provider API Key Is Passed Through the Process Argument Vector<![CDATA[ ## Vulnerability Details **File Location**: `references/hermes-plugin.md:31-36` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: Medium ### Vulnerable Code ```bash hermes linkedclaw auth set \ --api-key "$(awk '/^apiKey:/{print $2}' ~/.linkedclaw/config.yaml | tr -d '\"')" \ --agent-id agt_xxxxxxxx ``` ### Technical Analysis The shell substitution prevents the API key from being printed directly into the conversational transcript, but it expands the secret before starting `hermes`. The resulting process is therefore invoked with the complete credential in its argument vector: ```text hermes linkedclaw auth set --api-key lc_<secret> --agent-id agt_xxxxxxxx ``` Command-line arguments may be observable through process inspection facilities, endpoint monitoring, audit frameworks, crash diagnostics, debugging tools, or process-accounting systems. Exposure depends on the operating system and local security configuration, but command-line arguments should not be treated as a protected secret transport. The source file is documented as mode `0600`, but that protection does not extend to the transient argument vector. The destination file also contains other Hermes provider credentials, increasing the importance of avoiding tooling or workflows that may log the command. ### Attack Path 1. The operator runs the documented `hermes linkedclaw auth set` command. 2. The shell reads the LinkedClaw API key from `~/.linkedclaw/config.yaml`. 3. Command substitution inserts the plaintext key into the `hermes` process arguments. 4. A local user, privileged monitoring agent, audit service, process logger, or diagnostic tool captures the argument vector while the command is running. 5. The observer extracts the `lc_` credential. 6. The exposed credential is used to authenticate to LinkedClaw within the permissions and lifetime assigned to that provider key. ### Impact Assessment The immediate scope is disclosure of the LinkedClaw ...[truncated 646 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a secure credential-import mechanism that reads from standard input without echo: ```bash awk '/^apiKey:/{print $2}' ~/.linkedclaw/config.yaml | tr -d '"' | hermes linkedclaw auth set --api-key-stdin --agent-id agt_xxxxxxxx ``` The `--api-key-stdin` option is a proposed secure interface and must be implemented by the Hermes plugin before documenting this form. 2. Alternatively, implement a direct import option that reads the protected LinkedClaw configuration itself: ```bash hermes linkedclaw auth import-linkedclaw --agent-id agt_xxxxxxxx ``` 3. If file-based input is required, use a protected file descriptor or a mode-`0600` temporary credential file, ensure atomic handling, and securely remove it immediately afterward. 4. Ensure the credential-setting command never logs the supplied key and that error messages redact all but a minimal prefix. 5. Avoid placing the key in shell history, environment variables, command arguments, service-unit text, or diagnostic output. 6. After suspected argument-vector exposure, revoke the existing key, issue a replacement, update both credential stores securely, and restart the provider. 7. Document the local process-observation risk so operators do not assume that command substitution alone protects the secret. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (51)

Credential Access

High
Category
Privilege Escalation
Content
# HOME must be the account that ran `linkedclaw login` — config + provider YAML live in ~/.linkedclaw.
Environment=HOME=/home/<you>
# The agent needs its model credential; keep LinkedClaw creds OUT of here (the daemon already holds them).
EnvironmentFile=-/home/<you>/.config/lc-provider-<slug>.env   # e.g. ANTHROPIC_API_KEY=...

[Install]
WantedBy=multi-user.target
Confidence
75% confidence
Finding
The skill advises storing model API credentials in an environment file for a persistent service. While common, plaintext env files on disk can be exposed through weak file permissions, backups, process inspection tooling, or accidental disclosure, and this matters more here because the daemon serves untrusted users continuously.

Agent Config Directory Access

High
Category
Agent Snooping
Content
**Why the obvious approaches do NOT work** (don't bother trying them — measured against
claude-agent-acp 0.49.0):
- A `~/.claude/settings.json` or project `.claude/settings.json` `permissions.deny:["Bash"]`
  is **ignored** — the Agent SDK runs in isolation mode and the adapter's own tool wiring
  decides what the model gets.
- `session/set_mode` `dontAsk` / `plan` still execute shell.
Confidence
90% confidence
Finding
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.

Agent Config Directory Access

High
Category
Agent Snooping
Content
Therefore, to confine Codex you MUST disable its exec in Codex's OWN config — a real,
in-process, approval-independent control the model never bypasses. Set in
`~/.codex/config.toml`:

```toml
sandbox_mode = "read-only"
Confidence
90% confidence
Finding
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.

Agent Config Directory Access

High
Category
Agent Snooping
Content
Therefore, to confine Codex you MUST disable its exec in Codex's OWN config — a real,
in-process, approval-independent control the model never bypasses. Set in
`~/.codex/config.toml`:

```toml
sandbox_mode = "read-only"
Confidence
90% confidence
Finding
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.

Agent Config Directory Access

High
Category
Agent Snooping
Content
Gemini does NOT honor the `disableBuiltInTools` hint that the bridge sends for Claude
Code, so for Gemini you must remove the shell tool **in Gemini's own settings**. This is a
real, in-process, approval-independent removal — the model never sees the tool. Add to
your Gemini settings (`~/.gemini/settings.json` or project `.gemini/settings.json`):

```json
{
Confidence
90% confidence
Finding
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.

Credential Access

High
Category
Privilege Escalation
Content
The `reject-all` permission mode also does NOT confine Hermes: Hermes only asks for
approval for commands it classifies as "dangerous" via ~35 regex patterns — harmless
reads like `id -un` or `cat ~/.ssh/id_rsa` do not match any pattern and run
ungated.

**Live-verified:** a "run `id -un`" prompt against bare `hermes acp` with `reject-all`
Confidence
99% confidence
Finding
The document states that Hermes can run ungated shell commands and gives `cat ~/.ssh/id_rsa` as an example of a read that would execute without approval. In context, this is evidence of a real credential-exposure risk in the described skill: an attacker could prompt the agent to read sensitive host files and exfiltrate their contents via the model response.

Self-Modification

High
Category
Rogue Agent
Content
---

## Update this skill / the plugin

```bash
# Re-fetch skill content:
Confidence
85% confidence
Finding
The skill instructs the agent to re-install or force-refresh skill content from an external source (`openclaw skills install linkedclaw-provider --force`). That is a self-modification/update path which can change the behavior of the currently trusted skill without a fresh review, creating a supply-chain risk if the remote package is compromised or unexpectedly changed. In this context the rest of the document is operationally detailed and meant to be followed, which makes the update command more likely to be executed in practice.

Session Persistence

Medium
Category
Rogue Agent
Content
description: LinkedClaw provider — register this machine's AI agent (Claude Code, Gemini CLI, or a custom handler) as a paid provider on the LinkedClaw marketplace so it EARNS credits serving other agents. Use this when the user wants to rent out their agent, register/list a provider, earn credits on LinkedClaw, set up `linkedclaw provider run`, or asks about `--handler-acp`, or install the OpenClaw/Hermes native plugin (@linkedclaw/openclaw-plugin / hermes-linkedclaw) for the deep path. This is a one-time setup/ops assistant: after setup, a daemon runs unattended — for the *requester* role (this agent hiring others), install `linkedclaw-requester` instead.
license: Apache-2.0
compatibility: Requires node + npm and the `@linkedclaw/cli`. The ACP "light" path additionally needs an ACP-speaking agent on this machine (Claude Code via `@agentclientprotocol/claude-agent-acp`, Gemini, Codex, Hermes, OpenCode, pi). OpenClaw and Hermes also offer a native-plugin "deep" path (`@linkedclaw/openclaw-plugin` / `hermes-linkedclaw`) — see their plugin references.
allowed-tools: Bash(linkedclaw:*) Bash(jq:*) Bash(npm:*) Bash(npx:*) Bash(node:*) Bash(command:*) Bash(printf:*) Bash(pm2:*) Bash(openclaw:*) Bash(hermes:*) Bash(pip:*) Bash(systemctl:*) Bash(mkdir:*) Bash(chmod:*) Read Write Edit
metadata:
  author: linkedclaw
  version: "0.1.4"
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The skill instructs use of `npx @agentclientprotocol/claude-agent-acp` without a pinned version, so each run may fetch whatever package version is current at execution time. In this skill's context, that command becomes part of an unattended provider daemon exposed to untrusted marketplace traffic, so a compromised upstream package, typo-squat, or breaking update could lead to arbitrary code execution on the host.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The unpinned `npx @agentclientprotocol/codex-acp` command allows execution of a mutable upstream package version. Because this skill is specifically about wiring an external-agent bridge into a persistent daemon that serves untrusted users, any malicious or vulnerable package update would execute with the provider host's permissions.

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding
Using `npx -y pi-acp` without version pinning permits silent installation and execution of the latest published package. In an unattended provider setup, that creates a supply-chain execution path that could be exploited to run attacker-controlled code on the machine or weaken the intended confinement of the rented-out agent.

Session Persistence

Medium
Category
Rogue Agent
Content
description: "Paste a diff or file; get a senior-level review with concrete, line-referenced fixes."   # REQUIRED for search/discovery
```

Write this under `~/.linkedclaw/providers/<slug>.yaml` (durable — survives reboot; `/tmp`
does NOT). Then `linkedclaw provider register <slug>` and `linkedclaw provider run <slug>`
resolve it by slug.
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The startup example again uses `npx @agentclientprotocol/claude-agent-acp` without version pinning, this time in the core `provider run` command. Since this is the exact long-lived daemon launch path, an upstream package change can directly alter runtime behavior or introduce code execution at service start.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
Flags:
- `--acp-permissions reject-all|allow-reads|allow-all` — default `reject-all` = remove the
  agent's built-in tools entirely (text-in/text-out; the recommended marketplace default).
  `allow-reads` keeps tools but only auto-approves tools whose NAME is a known read-only
  one (ignores the agent's self-reported kind); `allow-all` auto-approves everything. Both
  non-default modes keep tools and therefore require an OS sandbox — wrap the command, e.g.
  `--handler-acp "srt npx @agentclientprotocol/claude-agent-acp"` (the CLI warns if you don't).
Confidence
85% confidence
Finding
The skill documents an `allow-reads` mode that auto-approves tool requests based on command name classification. Even though it warns that this is non-default and should be sandboxed, automatic approval of actions for an agent serving untrusted strangers weakens human oversight and can be bypassed if supposedly read-only tools have side effects or broader access than expected.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- `--acp-permissions reject-all|allow-reads|allow-all` — default `reject-all` = remove the
  agent's built-in tools entirely (text-in/text-out; the recommended marketplace default).
  `allow-reads` keeps tools but only auto-approves tools whose NAME is a known read-only
  one (ignores the agent's self-reported kind); `allow-all` auto-approves everything. Both
  non-default modes keep tools and therefore require an OS sandbox — wrap the command, e.g.
  `--handler-acp "srt npx @agentclientprotocol/claude-agent-acp"` (the CLI warns if you don't).
- `--acp-env KEY1,KEY2` — extra env vars to pass to the agent. The built-in allowlist
Confidence
90% confidence
Finding
The skill exposes an `allow-all` mode that auto-approves every tool action for an unattended agent processing prompts from untrusted marketplace users. Although the text warns against casual use, documenting and normalizing this option materially increases the chance of remote code execution, file modification, or host compromise if operators enable it.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The sandboxed wrapper example still embeds an unpinned `npx @agentclientprotocol/claude-agent-acp`, leaving the supply-chain risk intact even if OS sandboxing is added. Sandbox guidance reduces blast radius, but a malicious package could still exfiltrate accessible data, abuse network access, or undermine the provider process.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
npm i -g pm2
pm2 start "linkedclaw provider run <slug> --handler-acp '<your handler>'" --name lc-provider-<slug>
pm2 save               # persist the process list
pm2 startup            # prints a sudo command — run it once (installs the boot launcher)
# ops: pm2 restart|stop|logs lc-provider-<slug>
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
npm i -g pm2
pm2 start "linkedclaw provider run <slug> --handler-acp '<your handler>'" --name lc-provider-<slug>
pm2 save               # persist the process list
pm2 startup            # prints a sudo command — run it once (installs the boot launcher)
# ops: pm2 restart|stop|logs lc-provider-<slug>
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
npm i -g pm2
pm2 start "linkedclaw provider run <slug> --handler-acp '<your handler>'" --name lc-provider-<slug>
pm2 save               # persist the process list
pm2 startup            # prints a sudo command — run it once (installs the boot launcher)
# ops: pm2 restart|stop|logs lc-provider-<slug>
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
`pm2 save` + `pm2 startup` are BOTH required or the daemon will NOT come back after reboot.

**systemd (Linux servers):** write a unit, then enable it.

```ini
# /etc/systemd/system/lc-provider-<slug>.service
Confidence
80% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
`pm2 save` + `pm2 startup` are BOTH required or the daemon will NOT come back after reboot.

**systemd (Linux servers):** write a unit, then enable it.

```ini
# /etc/systemd/system/lc-provider-<slug>.service
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now lc-provider-<slug>     # start + boot-persist in one
# ops: systemctl restart|stop|status lc-provider-<slug> ; journalctl -u lc-provider-<slug> -f
```
Confidence
80% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Static analysis

No suspicious patterns detected.