Back to skill

Security audit

Soul Pack

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-aligned, but importing packages can install unreviewed agent instructions and handles archives/overwrites too loosely, so it needs Review before use.

Install only if you trust the SOUL packages you will import. Review a package's SOUL.md before importing, avoid --force unless you have backed up the workspace, use a test agent first, and avoid sharing exported archives if the embedded local workspace path is sensitive.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T01 · Skill Instruction Hijacking

Error
Location
scripts/import-soul.sh:42
Finding
Untrusted SOUL instructions are installed and registered without security review<![CDATA[ ## Vulnerability Details **File Location**: `scripts/import-soul.sh:42-65` **Vulnerability Type**: Untrusted agent instruction installation **Risk Level**: High ### Vulnerable Code ```bash [[ -f "$SRC/manifest.json" && -f "$SRC/SOUL.md" ]] || { echo "Invalid package: missing manifest.json or SOUL.md"; exit 1; } python3 - <<'PY' "$SRC/manifest.json" import json,sys p=sys.argv[1] obj=json.load(open(p)) req=['name','version','createdAt','files'] for k in req: assert k in obj, f'missing field: {k}' files=set(obj.get('files',[])) for need in ['SOUL.md','preview.md','manifest.json']: assert need in files, f'missing in files[]: {need}' print('manifest: ok') PY mkdir -p "$WS" if [[ -f "$WS/SOUL.md" && "$FORCE" != "1" ]]; then echo "Refusing to overwrite existing $WS/SOUL.md (use --force)" exit 1 fi cp "$SRC/SOUL.md" "$WS/SOUL.md" [[ -f "$SRC/preview.md" ]] && cp "$SRC/preview.md" "$WS/preview.md" || true cp "$SRC/manifest.json" "$WS/soul-manifest.json" # Add agent if not exists if openclaw agents list | grep -q "\b$AGENT\b"; then echo "Agent exists: $AGENT" else openclaw agents add "$AGENT" --workspace "$WS" fi ``` ### Technical Analysis The importer treats `SOUL.md` from an externally supplied package as trusted agent instructions. Validation only verifies that selected manifest keys exist and that the `files` array names the expected files. It does not inspect, constrain, authenticate, or request approval for the behavioral instructions in `SOUL.md`. After copying the untrusted file into the target workspace, the script immediately registers that workspace through `openclaw agents add`. Consequently, a package can introduce instructions that attempt to change the agent's role, weaken safety constraints, induce unsafe tool use, request sensitive information, or direct data to attacker-controlled destinations. The `--force` option increases the impact by allowing an existing workspace's `SOUL.md` to be replaced. ### Attack Path 1. A ...[truncated 1129 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat every imported `SOUL.md` as untrusted content. 2. Display the complete instruction changes and require explicit user approval before installing them. 3. Do not automatically register or activate the agent during import; separate extraction, review, installation, and activation into distinct steps. 4. Add package authenticity controls, such as signatures, trusted publisher identities, or user-verified checksums. 5. Scan imported instructions for attempts to override safety rules, access secrets, invoke high-risk tools, or transmit data. 6. When `--force` is used, show a diff and require a second confirmation before replacing an existing `SOUL.md`. 7. Run newly imported agents with restricted filesystem, credential, tool, and network permissions until the package has been reviewed. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/export-soul.sh:20
Finding
Unvalidated package name permits output path traversal and tar option injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/export-soul.sh:20-22,41` **Vulnerability Type**: Path traversal and unsafe command argument handling **Risk Level**: Medium ### Vulnerable Code ```bash PKG_DIR="$OUT/$NAME" mkdir -p "$PKG_DIR" cp "$WS/SOUL.md" "$PKG_DIR/SOUL.md" cat > "$PKG_DIR/preview.md" <<EOF # ${NAME} - Exported from: ${WS} - Persona source: SOUL.md EOF cat > "$PKG_DIR/manifest.json" <<EOF { "name": "${NAME}", "version": "0.1.0", "description": "Soul package exported from OpenClaw workspace", "createdAt": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "sourceWorkspace": "${WS}", "files": ["SOUL.md", "preview.md", "manifest.json"] } EOF ( cd "$OUT" && tar -czf "${NAME}.tar.gz" "$NAME" ) ``` ### Technical Analysis The user-controlled `NAME` value is directly appended to `OUT` without requiring it to be a safe basename. Shell quoting prevents shell metacharacter expansion, but it does not prevent filesystem traversal. A name containing components such as `../` can cause `PKG_DIR` and the generated archive path to resolve outside the intended output directory. The member operand passed to `tar` is also not preceded by `--`. A name beginning with `-` may therefore be interpreted as a tar option rather than a file operand, depending on the tar implementation and supplied value. Additionally, `NAME` and `WS` are embedded into JSON using string interpolation without JSON escaping. Quotes, backslashes, or control characters can produce an invalid or semantically altered manifest. ### Attack Path 1. An attacker controls or influences the value passed to `--name`. 2. The attacker supplies a value containing traversal components, such as `../target`. 3. `PKG_DIR="$OUT/$NAME"` resolves outside the intended `OUT` directory. 4. The script creates a directory and writes `SOUL.md`, `preview.md`, and `manifest.json` at that unintended location. 5. The archive output path may also escape `OUT`. 6. Alternatively, a leading-hyphen name may ...[truncated 586 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict package names to a safe basename, for example: ```bash [[ "$NAME" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]] || { echo "Invalid package name" exit 1 } [[ "$NAME" != "." && "$NAME" != ".." ]] || exit 1 ``` 2. Reject names containing `/`, backslashes, control characters, or leading hyphens. 3. Canonicalize `OUT` and the destination, then verify that the destination remains a child of `OUT`. 4. Terminate tar option parsing explicitly: ```bash ( cd -- "$OUT" && tar -czf "$NAME.tar.gz" -- "$NAME" ) ``` 5. Generate `manifest.json` with a JSON-aware utility or Python rather than interpolating values into a heredoc. 6. Refuse to reuse a package directory unless an explicit overwrite option is provided. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/import-soul.sh:27
Finding
Untrusted packages are extracted and copied without archive safety controls or full schema validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/import-soul.sh:27-54` **Vulnerability Type**: Unsafe archive extraction, symlink handling, and incomplete validation **Risk Level**: High ### Vulnerable Code ```bash TMP=$(mktemp -d) cleanup(){ rm -rf "$TMP"; } trap cleanup EXIT SRC="$TMP/pkg" mkdir -p "$SRC" if [[ -d "$PKG" ]]; then cp -R "$PKG"/* "$SRC"/ else tar -xzf "$PKG" -C "$SRC" --strip-components=1 fi [[ -f "$SRC/manifest.json" && -f "$SRC/SOUL.md" ]] || { echo "Invalid package: missing manifest.json or SOUL.md"; exit 1; } python3 - <<'PY' "$SRC/manifest.json" import json,sys p=sys.argv[1] obj=json.load(open(p)) req=['name','version','createdAt','files'] for k in req: assert k in obj, f'missing field: {k}' files=set(obj.get('files',[])) for need in ['SOUL.md','preview.md','manifest.json']: assert need in files, f'missing in files[]: {need}' print('manifest: ok') PY mkdir -p "$WS" if [[ -f "$WS/SOUL.md" && "$FORCE" != "1" ]]; then echo "Refusing to overwrite existing $WS/SOUL.md (use --force)" exit 1 fi cp "$SRC/SOUL.md" "$WS/SOUL.md" ``` ### Technical Analysis The importer extracts an untrusted tar archive before inspecting its members. It does not independently reject absolute paths, traversal components, symbolic links, hard links, device files, unexpected file types, excessive file counts, or excessive expanded sizes. Reliance on implementation-specific tar protections is insufficient for a security boundary. Directory packages are recursively copied without checking for symbolic links. The subsequent `-f` test follows symbolic links, and `cp "$SRC/SOUL.md"` can dereference a package-supplied link. A crafted package can therefore cause the importer to copy the contents of a local file accessible to the invoking user into the target workspace. An archive can also consume substantial disk space or inodes before manifest validation occurs. The temporary directory is safely created with `mktemp -d`, but that does n ...[truncated 1849 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. List and validate every archive member before extraction. 2. Reject absolute paths, `..` path components, empty or ambiguous names, symbolic links, hard links, devices, FIFOs, and other non-regular file types. 3. Allow only the expected package files and directory structure. 4. Apply limits to compressed size, expanded size, file count, per-file size, and extraction time. 5. Extract using a library or hardened routine that verifies the resolved path of every member remains inside the temporary directory. 6. For directory packages, use `lstat`-equivalent checks and reject symbolic links rather than following them. 7. Verify that `SOUL.md`, `preview.md`, and `manifest.json` are regular files located directly in the package root before copying. 8. Open source files with no-follow protections where supported and copy from validated file descriptors. 9. Validate `manifest.json` against `schema/manifest.schema.v0.1.json` using a JSON Schema Draft 2020-12 validator. 10. Perform all structural, size, type, schema, and trust checks before modifying the destination workspace or registering an agent. ]]>
Vulnerability Patterns
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (4)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The script’s behavior matches the export portion of the description: it validates a workspace, copies SOUL.md, creates package metadata files, and archives the package. However, the declared purpose says the skill can also import/install soul packages and batch list local packages. Those capabilities are absent from the supplied code chunk. Since the description claims broader functionality than what this code actually implements, this is a description-behavior mismatch.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The skill documentation is entirely written in Chinese, which imposes a specific language on users without indicating that other languages are available. Under the policy, a language constraint should either be optional or clearly justified as region-specific.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
This shell script performs file writes into the target workspace and allows overwriting existing content when `--force` is set. Although there is a refusal message when overwrite is blocked, there is no explicit confirmation prompt or warning describing the consequences of `--force` before replacing `SOUL.md`, `preview.md`, and `soul-manifest.json`.

Missing User Warnings

Low
Confidence
92% confidence
Finding
The script embeds the full workspace path into both preview.md and manifest.json, then packages those files into the exported archive. If the archive is shared externally, it can disclose local filesystem structure, usernames, project names, or other environment details that the user may not realize are being published.

Static analysis

No suspicious patterns detected.