Back to skill

Security audit

SEO Article Pipeline

Security checks for vulnerabilities and agentic risk

Overview

This SEO writing skill is mostly purpose-aligned, but it tells the agent to commit and push generated blog content to the main branch without a clear confirmation step.

Install only if you are comfortable with an SEO workflow that sends keywords to DataForSEO and Google Suggest, uses DataForSEO credentials from environment variables, writes article and image files, and may commit and push to your repository. Treat Git commit and push steps as manual review points, prefer a draft branch or pull request, and avoid using confidential campaign terms unless third-party lookup is acceptable.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/research-keyword.sh:19
Finding
DataForSEO Credentials Exposed Through Process Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/research-keyword.sh`, lines 19-39 **Vulnerability Type**: Credentials exposed through command-line arguments **Risk Level**: Medium ### Vulnerable Code ```bash DFORSEO_LOGIN="${DATAFORSEO_LOGIN}" DFORSEO_PASS="${DATAFORSEO_PASSWORD}" if [ -z "$DFORSEO_LOGIN" ] || [ -z "$DFORSEO_PASS" ]; then echo "Error: DATAFORSEO_LOGIN and DATAFORSEO_PASSWORD env vars are required." echo "Get your credentials at https://dataforseo.com" exit 1 fi echo "=== Keyword Research: $KEYWORD (lang=$LANG, loc=$LOCATION) ===" echo "" # 1. Search volume echo "--- Search Volume ---" curl -s -X POST "https://api.dataforseo.com/v3/keywords_data/google_ads/search_volume/live" \ -u "$DFORSEO_LOGIN:$DFORSEO_PASS" \ -H "Content-Type: application/json" \ -d "[{\"keywords\":[\"$KEYWORD\"],\"language_code\":\"$LANG\",\"location_code\":$LOCATION}]" | ``` The same credential-passing pattern is repeated in the second authenticated request at lines 52-56. ### Technical Analysis The script passes the DataForSEO login and password to `curl` through the `-u` command-line option. This places the expanded credential pair in the process argument vector while `curl` is running. Depending on operating-system process visibility, container configuration, monitoring software, logging, and user permissions, another local process may be able to inspect the arguments and recover the credentials. Although transmission to `https://api.dataforseo.com` is declared and necessary for keyword research, exposing credentials through process metadata is not necessary. There is no evidence that the credentials are deliberately sent to an unrelated service. The vulnerability concerns local secret handling rather than covert network exfiltration. ### Attack Path 1. A user configures `DATAFORSEO_LOGIN` and `DATAFORSEO_PASSWORD`. 2. The Skill invokes `research-keyword.sh`. 3. The script expands both values into the `curl -u` argument. 4. A local ...[truncated 700 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Avoid passing secrets directly through command-line arguments. - Supply credentials using a protected curl configuration through standard input or another secret mechanism that does not expose them in the process argument vector. - Ensure any temporary credential material is created with restrictive permissions and deleted reliably; preferably avoid filesystem-backed temporary secret files entirely. - Use narrowly scoped, revocable API credentials when DataForSEO supports them. - Restrict process visibility between users and workloads on shared systems. - Ensure process monitoring, debugging, and CI logs do not capture authentication values. - Rotate the credentials if there is evidence that process arguments have previously been collected or exposed. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/research-keyword.sh:8
Finding
Unvalidated Input Embedded in Authenticated JSON Requests and Google Suggest URL<![CDATA[ ## Vulnerability Details **File Location**: `scripts/research-keyword.sh`, lines 8-69 **Vulnerability Type**: Unsafe request construction and missing input validation **Risk Level**: Medium ### Vulnerable Code ```bash KEYWORD="$1" LANG="${2:-en}" LOCATION="${3:-2840}" ``` ```bash curl -s -X POST "https://api.dataforseo.com/v3/keywords_data/google_ads/search_volume/live" \ -u "$DFORSEO_LOGIN:$DFORSEO_PASS" \ -H "Content-Type: application/json" \ -d "[{\"keywords\":[\"$KEYWORD\"],\"language_code\":\"$LANG\",\"location_code\":$LOCATION}]" | ``` ```bash curl -s -X POST "https://api.dataforseo.com/v3/keywords_data/google_ads/keywords_for_keywords/live" \ -u "$DFORSEO_LOGIN:$DFORSEO_PASS" \ -H "Content-Type: application/json" \ -d "[{\"keywords\":[\"$KEYWORD\"],\"language_code\":\"$LANG\",\"location_code\":$LOCATION,\"sort_by\":\"search_volume\",\"limit\":15}]" | ``` ```bash curl -s -A "Mozilla/5.0" "https://suggestqueries.google.com/complete/search?client=firefox&q=$(echo $KEYWORD | sed 's/ /+/g')" 2>/dev/null | ``` ### Technical Analysis `KEYWORD`, `LANG`, and `LOCATION` originate from positional command-line arguments and are inserted directly into JSON strings. They are not encoded by a JSON serializer: - Quotes, backslashes, control characters, and JSON delimiters in `KEYWORD` or `LANG` can invalidate or alter the request structure. - `LOCATION` is inserted as an unquoted JSON value and is not verified as numeric, increasing the potential for structural manipulation. - The authenticated DataForSEO requests are made with the user's credentials, so manipulated request data can consume the user's account quota. - The Google Suggest request replaces spaces with plus signs but does not perform complete URL encoding. Reserved characters such as `&`, `#`, `=`, and `?` can alter query interpretation. The shell does not recursively reinterpret metacharacters produced by ordinary parameter expansion, so the reviewed code does not establish di ...[truncated 1135 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Construct JSON with a real serializer such as `jq` instead of string interpolation. For example, use `jq -n --arg keyword "$KEYWORD" --arg lang "$LANG" --argjson location "$LOCATION"` to create the request body. - Validate `LOCATION` against a numeric format or, preferably, an explicit list of supported location codes before passing it to `--argjson`. - Validate `LANG` against an explicit allowlist such as `en` and `fr`. - Define and enforce reasonable length and character limits for keywords. - Build the Google Suggest request with proper URL encoding, such as: ```bash curl -s -A "Mozilla/5.0" \ --get \ --data-urlencode "client=firefox" \ --data-urlencode "q=$KEYWORD" \ "https://suggestqueries.google.com/complete/search" ``` - Use `curl --fail-with-body` and explicitly check HTTP and JSON parsing failures so malformed requests do not silently produce misleading output. - Consider applying API request limits or user confirmation for bulk execution to reduce quota-abuse risk. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:302
Finding
Generated Content Is Pushed Directly to the Main Branch Without a Confirmation Boundary<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 302-308 **Vulnerability Type**: Excessive repository modification and publication privileges **Risk Level**: Medium ### Vulnerable Code ```markdown 3. **Git commit & push**: ```bash cd your-project git add content/blog/en/slug.mdx public/blog/*.webp git commit -m "feat(blog): add EN article — slug" git push origin main ``` ``` The translation workflow also instructs the Agent to perform another Git commit and push at line 319. ### Technical Analysis The Skill's primary declared function is researching, writing, assembling, and translating SEO articles. Directly pushing generated files to the repository's `main` branch is not required to produce those artifacts. The instructions do not require the Agent to: - Obtain explicit user confirmation immediately before committing or pushing. - Verify the configured Git remote. - Review the exact staged file set. - Use a dedicated branch. - Open a pull request for human review. - Confirm that generated content and externally sourced material are safe and accurate before publication. The workflow therefore uses ambient Git credentials to cross a publication boundary without an explicit least-privilege safeguard. The broad image pathspec also risks staging more matching files than the newly generated artifacts. This is not evidence that the Skill acquires new credentials or bypasses repository access controls. The risk arises because it automatically exercises whatever repository write authority is already available to the Agent. ### Attack Path 1. The Agent generates an article and image files using researched external information and workspace configuration. 2. The Skill instructs the Agent to stage the article and all files matching `public/blog/*.webp`. 3. The Agent commits the staged content without a mandatory human review step. 4. The Agent uses existing Git credentials to run `git push origin main`. 5. Unreviewed, in ...[truncated 856 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Make artifact generation the default endpoint of the workflow. Do not commit or push unless the user explicitly requests publication. - Require a separate, immediate confirmation before every commit and every remote push. - Display and validate the repository root, remote URL, target branch, and exact changed-file list before proceeding. - Stage explicit generated filenames rather than a broad wildcard such as `public/blog/*.webp`. - Create a dedicated topic branch instead of pushing directly to `main`. - Prefer opening a pull request so repository protections and human review can apply. - Preserve `draft: true` until the user explicitly approves publication. - Respect branch protection and never attempt to bypass review, status checks, or signing requirements. - Provide a dry-run mode that reports the commands and affected files without modifying Git state. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description promises a broad end-to-end SEO content pipeline covering research through article creation, image generation, fact-checking, humanization, assembly, and translation. The supplied code chunk only implements a narrow keyword research utility: it validates inputs and credentials, calls DataForSEO APIs for search volume and related keywords, and fetches Google Suggest suggestions. While keyword research is one component of the declared pipeline, the code shown does not perform the other major advertised capabilities. This is a material description-to-behavior mismatch because the actual code’s primary purpose is limited keyword research rather than full article production.

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill clearly instructs use of shell capabilities (`scripts/research-keyword.sh`, `cwebp`, `ffmpeg`, `git`) but does not declare an explicit tool scope or allowed-tools boundary. That creates an authorization gap where an agent may execute filesystem and command operations beyond what a user would reasonably expect from a content-writing skill.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The description says the skill generates SEO content, but the body also stages files into a repository and performs version-control operations. Omitting write-and-publish behavior is dangerous because users may invoke what looks like a drafting tool and unexpectedly get local repo changes or remote publication actions.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The invocation wording is broad enough to match many ordinary writing requests, increasing the chance the skill is triggered in situations where the user only wanted brainstorming or drafting help. Because the skill also performs shell, file-write, image, and git actions, overbroad triggering materially increases the risk of unintended side effects.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The instructions direct file creation, image copying, git commit, and git push without any required user-facing warning or approval step. This is dangerous because the skill can make persistent local changes and publish them remotely as part of a routine content request, violating user expectations and change-control practices.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
Including `git push origin main` gives the skill the ability to publish content directly to a remote branch, potentially altering production content or triggering deployment pipelines. In a content-generation context, automatic remote push is higher risk because it crosses from drafting assistance into unilateral external side effects.

External Transmission

Medium
Category
Data Exfiltration
Content
# 1. Search volume
echo "--- Search Volume ---"
curl -s -X POST "https://api.dataforseo.com/v3/keywords_data/google_ads/search_volume/live" \
  -u "$DFORSEO_LOGIN:$DFORSEO_PASS" \
  -H "Content-Type: application/json" \
  -d "[{\"keywords\":[\"$KEYWORD\"],\"language_code\":\"$LANG\",\"location_code\":$LOCATION}]" | \
Confidence
88% confidence
Finding
This code transmits the supplied keyword and contextual metadata to DataForSEO over the network. In this skill, external transmission is functionally expected, but it still constitutes a real data egress path that can leak sensitive inputs if users assume processing is local.

External Transmission

Medium
Category
Data Exfiltration
Content
# 1. Search volume
echo "--- Search Volume ---"
curl -s -X POST "https://api.dataforseo.com/v3/keywords_data/google_ads/search_volume/live" \
  -u "$DFORSEO_LOGIN:$DFORSEO_PASS" \
  -H "Content-Type: application/json" \
  -d "[{\"keywords\":[\"$KEYWORD\"],\"language_code\":\"$LANG\",\"location_code\":$LOCATION}]" | \
Confidence
88% confidence
Finding
This code transmits the supplied keyword and contextual metadata to DataForSEO over the network. In this skill, external transmission is functionally expected, but it still constitutes a real data egress path that can leak sensitive inputs if users assume processing is local.

External Transmission

Medium
Category
Data Exfiltration
Content
# 2. Related keywords
echo "--- Related Keywords (top 15 by volume) ---"
curl -s -X POST "https://api.dataforseo.com/v3/keywords_data/google_ads/keywords_for_keywords/live" \
  -u "$DFORSEO_LOGIN:$DFORSEO_PASS" \
  -H "Content-Type: application/json" \
  -d "[{\"keywords\":[\"$KEYWORD\"],\"language_code\":\"$LANG\",\"location_code\":$LOCATION,\"sort_by\":\"search_volume\",\"limit\":15}]" | \
Confidence
88% confidence
Finding
This second API call sends the keyword to DataForSEO again for related-keyword expansion, increasing external exposure of user input. The behavior aligns with the stated SEO purpose, but it remains a real privacy and data-governance concern if not transparently communicated.

External Transmission

Medium
Category
Data Exfiltration
Content
# 2. Related keywords
echo "--- Related Keywords (top 15 by volume) ---"
curl -s -X POST "https://api.dataforseo.com/v3/keywords_data/google_ads/keywords_for_keywords/live" \
  -u "$DFORSEO_LOGIN:$DFORSEO_PASS" \
  -H "Content-Type: application/json" \
  -d "[{\"keywords\":[\"$KEYWORD\"],\"language_code\":\"$LANG\",\"location_code\":$LOCATION,\"sort_by\":\"search_volume\",\"limit\":15}]" | \
Confidence
88% confidence
Finding
This second API call sends the keyword to DataForSEO again for related-keyword expansion, increasing external exposure of user input. The behavior aligns with the stated SEO purpose, but it remains a real privacy and data-governance concern if not transparently communicated.

Context-Inappropriate Capability

Low
Confidence
79% confidence
Finding
The manifest describes an SEO article pipeline driven by a target keyword, but does not indicate that the skill depends on host-stored credentials or secret access. Reading DATAFORSEO_LOGIN and DATAFORSEO_PASSWORD introduces a credential-handling capability that goes beyond the user-facing content-creation purpose, even though it is used for legitimate keyword research.

Missing User Warnings

Low
Confidence
90% confidence
Finding
The script sends the user-supplied keyword to a third-party SEO API without any explicit notice or consent gate. While keyword research inherently requires external lookup, user inputs may contain sensitive business plans, unpublished campaign terms, or client data, so silent transmission creates a privacy risk.

Missing User Warnings

Low
Confidence
92% confidence
Finding
The script also sends the keyword to Google's suggestion endpoint without notifying the user. This expands third-party exposure beyond the primary SEO vendor, which is unnecessary from a privacy perspective unless clearly disclosed and justified.

Static analysis

No suspicious patterns detected.