Back to skill

Security audit

sawana-multicul/official-docs-to-mdx

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent docs-conversion purpose, but it sends user-provided URLs to a third-party service and writes untrusted converted content to arbitrary MDX paths that may overwrite files.

Install only if you are comfortable sending documentation URLs to markdown.new and writing generated MDX into your workspace. Use it for public official docs, avoid private/internal URLs or URLs containing tokens, choose output paths carefully, and review generated MDX before compiling or publishing it.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mdnew_to_mdx.sh:18
Finding
Untrusted Remote Content Is Written Directly to an Executable MDX File<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mdnew_to_mdx.sh`, lines 18-70 **Vulnerability Type**: Untrusted MDX generation and insufficient input validation **Risk Level**: Medium ### Vulnerable Code ```bash curl -sS -D - "https://markdown.new/${source_url}" > "$raw_file" awk 'BEGIN{p=0} /^Markdown Content:/{p=1; next} p{print}' "$raw_file" > "$body_file" src_title="" src_description="" if awk 'NR==1{exit ($0=="---" ? 0 : 1)}' "$body_file"; then src_title="$(awk 'BEGIN{inside=0} /^---$/{if(inside==0){inside=1; next}else{exit}} inside && /^title:[[:space:]]/{sub(/^title:[[:space:]]*/, ""); print; exit}' "$body_file")" src_description="$(awk 'BEGIN{inside=0} /^---$/{if(inside==0){inside=1; next}else{exit}} inside && /^description:[[:space:]]/{sub(/^description:[[:space:]]*/, ""); print; exit}' "$body_file")" fi if [ -z "$src_title" ]; then src_title="Official Doc" fi if [ -z "$src_description" ]; then src_description="Converted from docs via markdown.new" fi awk ' BEGIN { in_fm=0 } NR==1 && $0=="---" { in_fm=1; next } in_fm && $0=="---" { in_fm=0; next } in_fm { next } { if ($0 ~ /^\[Skip to main content\]/) next if ($0 ~ /^\[\]\(https:\/\/[^)]*\)\[Docs\]\(\/home\)$/) next if ($0 ~ /^Copy as Markdown$/) next if ($0 ~ /^Copied!$/) next if ($0 ~ /^On this page$/) next if ($0 ~ /^[[:space:]]*\* \[[^]]+\]\(#[^)]+\)[[:space:]]*$/) next line=$0 gsub(/\[​\]\(#[^)]+ "Direct link to [^"]+"\)/, "", line) print line } ' "$body_file" > "$content_file" awk ' { if ($0 ~ /^[[:space:]]*$/) { blank++; if (blank <= 1) print ""; next } blank=0; print } ' "$content_file" > "$clean_file" mkdir -p "$(dirname "$out_file")" { echo "---" echo "title: ${src_title}" echo "description: ${src_description}" echo "sourceUrl: ${source_url}" echo "retrievedAt: ${retrieved_at}" echo "---" echo cat "$clean_file" } > "$out_file" echo "Wrote ${out_file}" ``` ### Technical Analysis The script accepts an arbitrary source string wi ...[truncated 2884 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Validate source URLs before making the request** - Parse the source as a URL rather than relying on string checks. - Require the `https` scheme. - Reject embedded credentials, control characters, fragments where unnecessary, and malformed hostnames. - Consider an explicit allowlist of approved official documentation domains. - Resolve redirects carefully and ensure that the final target remains within the approved policy. 2. **Treat the converted response as untrusted** - Parse the result with a maintained Markdown/MDX parser. - Reject ESM imports and exports, JSX, JavaScript expressions, raw HTML, and unknown nodes unless they are explicitly required. - Use an allowlist of permitted Markdown syntax instead of regular-expression cleanup. - Reject the conversion if parsing fails. 3. **Prefer non-executable output** - Generate `.md` rather than `.mdx` when executable MDX features are unnecessary. - If `.mdx` is required, configure the downstream compiler to disable or strictly restrict executable constructs and custom components. 4. **Serialize frontmatter safely** - Use a YAML serializer instead of direct `echo` interpolation. - Ensure `title`, `description`, and `sourceUrl` are emitted as properly escaped scalar values. - Apply length and character restrictions to metadata fields. 5. **Add post-generation verification** - Scan the generated document for prohibited MDX node types before replacing the destination. - Build into a temporary file and atomically move it to the destination only after validation succeeds. - Record the source domain and validation outcome for auditability. 6. **Constrain output destinations at the caller boundary** - If this script is invoked by an agent or service, restrict output paths to an approved documentation directory. - Run the conversion and subsequent build with minimal filesystem, environment, and network privileges. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
fi

source_url="$1"
out_file="$2"
retrieved_at="$(date -u +%F)"

raw_file="$(mktemp)"
body_file="$(mktemp)"
content_file="$(mktemp)"
clean_file="$(mktemp)"
trap 'rm -f "$raw_file" "$body_file" "$content_file" "$clean_file"' EXIT

curl -sS -D - "https://markdown.new/${source_url}" > "$raw_file"

awk 'BEGIN{p=0} /^Markdown Content:/{p=1; next} p{print}' "$raw_file" > "$body_file"

src_title=""
src_description=""
if awk 'NR==1{exit ($0=="---" ? 0 : 1)}' "$body_file"; then
  src_title="$(awk 'BEGIN{inside=0} /^---$/{if(inside==0){inside=1; next}else{exit}} inside && /^title:[[:space:]]/{sub(/^title:[[:space:]]*/, ""); print; exit}' "$body_file")"
  src_description="$(awk 'BEGIN{inside=0} /^---$/{if(inside==0){inside=1; next}else{exit}} inside && /^description:[[:space:]]/{sub(/^description:[[:space:]]*/, ""); print; exit}' "$body_file")"
fi

if [ -z "$src_title" ]; then
  src_title="Official Doc"
fi
if [ -z "$src_description" ]; then
  src_description="Converted from docs via markdown.new
Confidence
94% confidence
Finding
The script extracts title and description fields from remotely fetched content and injects them directly into generated MDX frontmatter without sanitization or escaping. An attacker controlling the source content, or a compromised conversion service, could craft frontmatter-breaking values that poison metadata, alter downstream parsing, or inject content/instructions into systems that later ingest these MDX files.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill invokes shell execution via `scripts/mdnew_to_mdx.sh` but does not declare an explicit tool scope such as `allowed-tools` or equivalent permissions. That omission weakens least-privilege controls and can let an agent run broader shell actions than reviewers or policy systems expect, especially since the skill also handles user-supplied URLs and output paths.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill explicitly states that the output file is overwritten if it already exists, but it does not require a user confirmation or even a prominent warning before destructive writes. Because the output path is user-specified and shell-backed, an agent could unintentionally replace important local documentation or other files, causing data loss or corruption.

External Transmission

Medium
Category
Data Exfiltration
Content
clean_file="$(mktemp)"
trap 'rm -f "$raw_file" "$body_file" "$content_file" "$clean_file"' EXIT

curl -sS -D - "https://markdown.new/${source_url}" > "$raw_file"

awk 'BEGIN{p=0} /^Markdown Content:/{p=1; next} p{print}' "$raw_file" > "$body_file"
Confidence
91% confidence
Finding
User-supplied input is incorporated directly into a request to an external third-party service, causing arbitrary URLs or sensitive internal URLs to be transmitted to markdown.new. In an agent context, this can leak private endpoints, tokens embedded in URLs, or internal-only documentation targets to an external service outside the user's trust boundary.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
This shell script silently fetches content from an external service with curl and writes the processed result to a caller-supplied output path. While it prints usage and a final success message, it does not disclose before execution that it will contact a remote host and overwrite the target file, which are safety-relevant actions for a general-purpose conversion script.

Static analysis

No suspicious patterns detected.