Is atomtanstudio/craft-do safe?
https://github.com/openclaw/skills/tree/main/skills/atomtanstudio/craft-do
The atomtanstudio/craft-do skill is a functionally legitimate Craft.do REST API integration whose installation was clean — only GitHub HTTPS traffic observed, all canary files untouched, no unexpected processes. However, the skill carries three structural risks that warrant caution before deployment: the Obsidian migration scripts perform bulk filesystem reads and unconditionally upload all content to a user-configured CRAFT_ENDPOINT, which becomes a full vault exfiltration channel if that variable is poisoned; craft-api.sh and the migration scripts contain pervasive command/jq injection vulnerabilities from unquoted variable expansion in JSON construction; and cleanup-craft.sh can permanently delete an entire Craft.do workspace when an agent satisfies its trivial interactive prompt. These are design and implementation quality concerns rather than evidence of intentional malice.
Category Scores
Findings (9)
HIGH Obsidian migration bulk-uploads entire vault to configurable external endpoint -25 ▶
migrate-obsidian-nested.sh and migrate-obsidian.sh recursively traverse a user-specified vault directory, read every .md file's full content with cat, and POST it to $CRAFT_ENDPOINT/blocks. CRAFT_ENDPOINT is an environment variable with no domain validation or allow-list. If an attacker can influence this value — via a compromised shell environment, a chained malicious skill that exports CRAFT_ENDPOINT before craft-do is invoked, or prompt injection targeting the env setup step — the entire vault is silently uploaded to an attacker-controlled server. The skill explicitly advertises this capability and provides no integrity verification on the endpoint.
HIGH Command injection via unquoted positional arguments in craft-api.sh -20 ▶
craft-api.sh constructs JSON API request bodies by interpolating bare $2 and $3 positional parameters inside double-quoted shell strings. In bash, $(...) command substitutions and backtick expansions evaluate before the enclosing double-quoted string is processed. An agent passing user-controlled text as a task description (e.g., a task title containing $(cat ~/.ssh/id_rsa)) would execute that command, with output silently embedded in the outbound API request body. This affects create-task, create-doc, and complete-task commands.
HIGH cleanup-craft.sh irreversibly deletes all Craft.do documents when agent satisfies 'yes' prompt -22 ▶
cleanup-craft.sh enumerates and bulk-deletes every user document and folder from the entire Craft.do workspace. It prompts read -p "Are you sure? Type 'yes' to continue" but an LLM agent can trivially provide 'yes' when instructed to 'clean up', 'reset', or 'start fresh'. The README explicitly positions this script as a migration helper for 'starting over', making casual invocation plausible. There is no dry-run mode, no scoping to specific folders, and deleted documents go to Craft trash which the API cannot empty, but folder deletion is permanent.
MEDIUM jq injection via Obsidian folder name interpolation into filter expression -12 ▶
In migrate-obsidian-nested.sh, find_existing_folder() builds a jq filter by directly interpolating $folder_name into the expression string without any escaping. A vault directory whose name contains double-quotes, parentheses, or jq operators (e.g., " or .secrets) could corrupt the jq query, cause unintended data extraction from the API response, or produce errors that alter control flow.
MEDIUM No path boundary validation on OBSIDIAN_VAULT argument -10 ▶
Both migration scripts accept the vault path as a CLI argument (OBSIDIAN_VAULT="${1:-}") and only verify that the path is a directory. There is no check that the path is a legitimate Obsidian vault, contains a .obsidian directory, or is restricted to expected parent paths. An agent instructed with a manipulated vault path (e.g., '~/', '/home', '/etc') would enumerate and upload all .md files found in that tree, potentially capturing configuration files, notes, or documents outside the intended scope.
MEDIUM Pervasive unquoted variable expansion in JSON construction across all scripts -8 ▶
All four shell scripts share the insecure pattern of interpolating user-supplied or filesystem-derived values directly into double-quoted JSON strings without sanitization or jq-based encoding. This affects document titles, task markdown content, folder names, destination parameters, and location types. Values containing backslashes, quotes, or shell metacharacters can break JSON encoding or trigger unintended expansion. The correct pattern (piping through jq -n --arg) is used only for file content in the migration scripts.
MEDIUM CRAFT_ENDPOINT env var creates environment-level attack surface for data routing -18 ▶
All API calls in all scripts unconditionally route to $CRAFT_ENDPOINT with no certificate pinning, domain allow-list, or redirect detection. In a multi-skill agent environment where skills share an environment, a previously loaded skill could export CRAFT_ENDPOINT to an attacker-controlled URL before craft-do is invoked — routing all subsequent Craft operations (list, create, and crucially any vault migration) to the attacker silently. The skill validates that the variable is non-empty but performs no further verification.
LOW External resource URLs in SKILL.md body -10 ▶
SKILL.md contains three external URLs in the Resources section: craft.do/api, craft.do/blog, and a YouTube channel. These are formatted as markdown documentation links and do not instruct the agent to fetch or browse them. The risk is low and theoretical — an overly literal agent or a future skill-loading mechanism that auto-fetches linked resources could trigger outbound requests. No instruction to visit these URLs appears in the skill's operational guidance.
INFO Clean sparse checkout installation from openclaw/skills registry 0 ▶
The skill was installed via a depth-1 sparse checkout of the openclaw/skills monorepo targeting only the skills/atomtanstudio/craft-do subpath. The only external network connection was to 140.82.121.4:443 (GitHub HTTPS). No post-install hooks executed (GIT_TEMPLATE_DIR=/dev/null), no background processes were spawned, and the connection diff shows no new persistent listeners. All installed files match expected skill content.