Back to skill

Security audit

Geo analytics & AI visibility

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent read-only analytics skill, but it handles private site analytics and a long-lived bearer token that users must protect.

Install only if you trust the Vtag GEO Analytics service and are authorized to view the selected site's analytics. Treat the saved access token as a secret, keep the credential path private, avoid sharing raw visitor/session/realtime data unless necessary, and revoke the token in the service console if it may have been exposed.

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/vtag.sh:19
Finding

Unsafe Storage of a Long-Lived OAuth Credential

Content
View full analysis

Vulnerability Details

File Location: scripts/vtag.sh, lines 19 and 62-65
Vulnerability Type: Unsafe credential file handling, including symbolic-link following and failure to correct existing file permissions
Risk Level: Medium

Vulnerable Code

bash
CRED="${VTAG_CRED:-$HOME/.vtag/credentials}"
bash
mkdir -p "$(dirname "$CRED")"
# umask 077 不是装饰:这里面是一把长期有效的只读凭证。
( umask 077; printf '%s' "$t" > "$CRED" )
echo "已授权,站点 $(printf '%s' "$t" | _json tag_id)" >&2

Technical Analysis

The script stores the complete OAuth token response, including a documented long-lived access_token, by using ordinary shell redirection to the configured credential path.

Although umask 077 protects a newly created file, it does not change the permissions of an existing file. If the credential file already exists with group-readable or world-readable permissions, the newly written token retains those unsafe permissions.

Shell redirection also follows symbolic links. The script does not verify that the credential path is a regular file, reject symbolic links, securely create a temporary file, or atomically install the credential. Consequently, a pre-positioned symbolic link or a path replacement race can redirect the credential write to another file writable by the invoking user.

The default path under the user's home directory reduces exposure under normal conditions, but the weakness remains relevant when the credential file or directory already has unsafe permissions, when another local process can manipulate the path, or when VTAG_CRED points to a shared or attacker-influenced location. The credential access is necessary for reusable authentication and does not itself exceed the Skill's declared read-only function; the vulnerability is in how the credential is persisted.

Attack Path

  1. The attacker obtains the ability to prepare or replace the credential path, such as through an unsafe shared ...[truncated 1757 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create and verify the credential directory with owner-only permissions:

    bash
    cred_dir=$(dirname -- "$CRED")
    mkdir -p -- "$cred_dir"
    chmod 700 -- "$cred_dir"
    
  2. Reject symbolic links and unexpected file types before replacing an existing credential:

    bash
    if [ -L "$CRED" ]; then
      echo "Refusing symbolic-link credential path" >&2
      exit 1
    fi
    if [ -e "$CRED" ] && [ ! -f "$CRED" ]; then
      echo "Credential path is not a regular file" >&2
      exit 1
    fi
    
  3. Write the response to a securely created temporary file in the same directory, apply mode 0600, validate its contents, and atomically rename it into place:

    bash
    tmp=$(mktemp "$cred_dir/.credentials.XXXXXX")
    trap 'rm -f -- "$tmp"' EXIT
    chmod 600 -- "$tmp"
    printf '%s' "$t" > "$tmp"
    
    [ -n "$(_json access_token < "$tmp")" ] || {
      echo "Credential response is invalid" >&2
      exit 1
    }
    
    mv -f -- "$tmp" "$CRED"
    chmod 600 -- "$CRED"
    trap - EXIT
    
  4. Validate custom VTAG_CRED paths. Refuse paths located in directories that are group-writable or world-writable unless the application can safely use platform-specific no-follow and exclusive-creation controls.

  5. Document that suspected token disclosure requires server-side revocation. Deleting the local credential file alone does not revoke the token.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (15)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 48)May include surrounding context.

md
- 可选的命令行封装:`scripts/vtag.sh`(需要 shell;没有 shell 就按下面的 HTTP 步骤自己发请求)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 76)May include surrounding context.

md
- 可选的命令行封装:`scripts/vtag.sh`(需要 shell;没有 shell 就按下面的 HTTP 步骤自己发请求)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly encourages persisting a long-lived access token to a local file and states it does not expire, but does not warn that the token is a sensitive bearer credential. If that file is read by another local user, malware, logs, backups, or a misconfigured workspace, an attacker could reuse the token to access private analytics data for the bound site without re-authentication.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documented /probe-events and related raw-record endpoints expose highly sensitive telemetry fields such as answer_text, query, visitor_id, session_id, ua, and detailed event sequences. Even though the file says the API is read-only and token-scoped, this still enables disclosure of potentially personal, confidential, or proprietary data if the token is over-broad, mishandled, or shown to an end user without strict minimization.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The /realtime endpoint exposes live visitor/session-level telemetry including timestamps, page paths, visitor_id, inferred engine/source metadata, device, and location breakdowns. In a conversational skill context, omission of a warning increases the chance that an agent will retrieve and reveal near-real-time tracking data to an unauthorized or overly broad audience, creating privacy and surveillance risk.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The document instructs the skill to use only specific Chinese metric names and explicitly forbids alternative wording. This is a natural-language locale policy constraint, but the file does not provide user opt-in, language alternatives, or a justification that the skill is limited to a Chinese-only regional context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The table prescribes exact Chinese phrases for how values should be explained to users, such as '来源未知' and '直接访问'. Because this guidance fixes the output language for user-facing explanations, it can violate language/locale policy unless the skill offers a choice or clearly states it is restricted to Chinese-language use.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The user-facing comments and usage instructions are written entirely in Chinese, which imposes a language choice on operators without offering an alternative or opt-in. This matches the policy category for language/locale constraints in natural-language content.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/vtag.sh (reported line 33)May include surrounding context.

sh
cmd="${1:-}"; [ -n "$cmd" ] || usage

if [ "$cmd" = "login" ]; then
  r=$(curl -fsS -X POST "$BASE/api/oauth/device_authorization" -d "client_id=$CLIENT_ID")
  dc=$(printf '%s' "$r" | _json device_code)
  uc=$(printf '%s' "$r" | _json user_code)
  uri=$(printf '%s' "$r" | _json verification_uri)

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/vtag.sh (reported line 44)May include surrounding context.

sh
echo "(或直接点带码链接: $full)" >&2
  while :; do
    sleep "$iv"
    # 这里**不加 -f**:400 带的 error 体正是流程的一部分,-f 会把它变成 curl 报错。
    t=$(curl -sS -X POST "$BASE/api/oauth/token" \
        -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
        -d "device_code=$dc" -d "client_id=$CLIENT_ID") || continue

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · LICENSE (reported line 12)May include surrounding context.

text
permit persons to whom the Software is furnished to do so.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The document states that all date parameters use Beijing-day semantics, which imposes a specific locale/timezone behavior. There is no accompanying user opt-in, locale choice, or explanation that this constraint is necessary for a region-specific compliance or product requirement.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file states that date parameters use a '北京日口径' and later mentions converting UTC minutes to Beijing time for display. This imposes a specific locale/timezone convention without any opt-in or explicit justification that the skill is limited to a Beijing/China-specific context.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.