Back to skill

Security audit

潜力单变体专家-卖家精灵

Security checks for vulnerabilities and agentic risk

Overview

The scouting skill mostly matches its stated purpose, but it bundles high-impact helpers that can persistently change agent instructions, upload local files publicly, and send credentials to environment-configured endpoints.

Install only after reviewing the bundled helper scripts. Do not run patch_scoring_to_agent.py, especially with --all, unless you intentionally want it to modify other agents' CLAUDE.md files. Keep LINKFOX_TOOL_GATEWAY and related endpoint variables pinned to trusted LinkFox hosts, confirm schedule frequency/cost/webhook destinations before creating tasks, and upload only files that are safe to make public.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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
Findings (4)

T02 · Agent Memory Poisoning

Error
Location
skills/amazon-asin-dynamic-scoring/scripts/patch_scoring_to_agent.py:142
Finding

Persistent Cross-Agent Instruction and Memory Modification

Content
View full analysis
bool: """Patch a CLAUDE.md file to add scoring module. Returns True if changes made.""" path = Path(filepath) if not path.exists(): print(f"ERROR: File not found: {filepath}") return False content = path.read_text(encoding="utf-8") # Check if already has the full scoring step (not just the reference line) if "二次评分(动态评分引擎)" in content: print(f"SKIP: {filepath} already has scoring step") return False # Check if it uses amazon-product-scout-agent if "amazon-product-scout-agent" not in content: print(f"SKIP: {filepath} does not use amazon-product-scout-agent") return False original = content changes = [] # 1. Add skill reference line after amazon-product-scout-agent line pattern_ref = r"(主脚本:call skill `amazon-product-scout-agent`[^\n]*)" if re.search(pattern_ref, content) and SKILL_REF_LINE not in content: content = re.sub( pattern_ref, r"\1\n" + SKILL_REF_LINE, content ) changes.append("skill 引用行") # 2. Add --json-output to product_scout_agent.py command if "--json-output" not in content: content = re.sub( r"(python3 /scripts/product_scout_agent\.py[^`]*?--sort-desc\s+\S+)\s*\n```", r"\1 \\\n --json-output\n```", content ) changes.append("--json-output 标志") # Additional instruction sections are inserted here. if content == original: print(f"NO CHANGE: {filepath} (patterns not matched, may need manual edit)") return False path.write_text(content, encoding="utf-8") print(f"PATCHED: {filepath}") ...[truncated 2617 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
skills/linkfox-sellersprite-product-search/scripts/sellersprite_product_search.py:42
Finding

API Credentials Can Be Redirected to an Arbitrary Network Endpoint

Content
View full analysis
str: """Gateway base address: environment variable first, production fallback.""" return (os.environ.get("LINKFOX_TOOL_GATEWAY") or "https://tool-gateway.linkfox.com").rstrip("/") def get_api_url(): sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "_shared")) return get_api_base() + API_PATH ``` ```python def call_api(params): api_url = get_api_url() api_key = get_api_key() data = json.dumps(params).encode("utf-8") headers = { "Authorization": api_key, "Content-Type": "application/json", "User-Agent": "LinkFox-Skill/2.0", "SESSION_ID": os.environ.get("SESSION_ID", ""), "MESSAGE_ID": os.environ.get("MESSAGE_ID", ""), "MODE_ID": os.environ.get("MODE_ID", ""), "APP_NAME": os.environ.get("APP_NAME", ""), } req = Request( api_url, data=data, headers=headers, method="POST", ) try: with urlopen(req, timeout=150) as response: return json.loads(response.read().decode("utf-8")) ``` From `linkfox-file-upload/scripts/linkfox_paths.py`: ```python def _get_agent_base() -> str: """tool-gateway base address: LINKFOX_TOOL_GATEWAY first, production fallback.""" return (os.environ.get("LINKFOX_TOOL_GATEWAY") or "https://tool-gateway ...[truncated 2493 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
skills/linkfox-file-upload/scripts/file_upload.py:35
Finding

Arbitrary Readable Local Files Can Be Uploaded to Public Object Storage

Content
View full analysis
[ ...]", file=sys.stderr) sys.exit(1) lp = _paths() results = [] voucher = None had_error = False for path in args: if not os.path.isfile(path): results.append({"error": True, "input": path, "message": "File does not exist"}) had_error = True continue try: if voucher is None: voucher = lp.get_sts_voucher() res = lp.upload_file(path, voucher=voucher) res["localPath"] = os.path.abspath(path) results.append(res) except Exception as e: voucher = None results.append({"error": True, "input": path, "message": str(e)}) had_error = True ``` From `linkfox_paths.py`: ```python file_size = os.path.getsize(local_path) max_size = voucher.get("maxFileSize") if isinstance(max_size, int) and max_size > 0 and file_size > max_size: raise RuntimeError( f"File size {file_size} bytes exceeds OSS limit {max_size} bytes: {local_path}" ) supported = voucher.get("supportedTypes") if isinstance(supported, str) and supported.strip(): allowed = {t.strip().lower() for t in supported.split(",") if t.strip()} if allowed and ext not in allowed: raise RuntimeError( f"File type .{ext} is not in the OSS allowlist: {sorted(allowed)} ({local_path})" ) dir_ = (voucher.get("dir") or "tmp").rstrip("/") date_prefix = time.strftime("%Y/%m", time.localtime(ts)) object_key = f"{dir_}/{date_prefix}/{_uuid.uu ...[truncated 2468 chars]
Remediation
View remediation

T07 · Tool Hijacking and Spoofing

Error
Location
skills/amazon-product-scout-agent/scripts/product_scout_agent.py:39
Finding

Environment-Controlled Subprocess Target Executes with Inherited Credentials

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • 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
Findings (141)

Tainted flow: 'req' from os.environ.get (line 274, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
94% confidence
Finding

download_media() performs arbitrary outbound HTTP/HTTPS requests against a caller-supplied URL with no allowlist, hostname validation, IP-range filtering, or redirect restrictions. In an agent/runtime context this enables SSRF behavior: an attacker who can influence the URL may probe internal services, reach cloud metadata endpoints, or pull sensitive internal content into the session workspace.

Content

Scanner excerpt · skills/amazon-product-scout-agent/scripts/linkfox_paths.py (reported line 504)May include surrounding context.

python
req = Request(url, headers={"User-Agent": "LinkFox-Skill/2.0"})
    try:
        with urlopen(req, timeout=timeout) as resp:
            # 从 Content-Type 进一步修正扩展名
            if guessed_ext == "bin":
                ct = resp.headers.get("Content-Type", "")

Tainted flow: 'req' from os.environ.get (line 335, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · skills/linkfox-aigc-textgen/scripts/aigc_textgen.py (reported line 237)May include surrounding context.

python
req = _lf_Request(url, headers={"User-Agent": "LinkFox-Skill/2.0"})
    try:
        with _lf_urlopen(req, timeout=timeout) as resp:
            if guessed_ext == "bin":
                ct = resp.headers.get("Content-Type", "")
                if "mp4" in ct:

Tainted flow: 'req' from os.environ.get (line 335, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
94% confidence
Finding

The script sends input parameters plus contextual identifiers and an API key to a remote endpoint whose base URL can be overridden by the LINKFOX_TOOL_GATEWAY environment variable. In a hostile or multi-tenant runtime, changing that variable can redirect authenticated requests and user data to an attacker-controlled server, causing credential and data exfiltration.

Content

Scanner excerpt · skills/linkfox-aigc-textgen/scripts/aigc_textgen.py (reported line 337)May include surrounding context.

python
}
    req = Request(url, data=data, headers=headers, method="POST")
    try:
        with urlopen(req, timeout=HTTP_TIMEOUT) as response:
            return json.loads(response.read().decode("utf-8"))
    except HTTPError as e:
        body = e.read().decode("utf-8") if e.fp else ""

Tainted flow: 'url' from os.environ.get (line 235, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
96% confidence
Finding

The code allows API base URLs to be overridden by environment variables and then sends login data, access tokens, refresh tokens, and generated API keys to those URLs via requests.post. In a hostile or multi-tenant runtime, an attacker controlling environment variables can redirect these authenticated requests to attacker infrastructure, causing credential and token exfiltration.

Content

Scanner excerpt · skills/linkfox-aigc-textgen/scripts/onboarding.py (reported line 196)May include surrounding context.

python
except RuntimeError as e:
        return {"_error": str(e)}
    try:
        r = requests.post(url, json=body or {}, headers=headers, timeout=timeout)
        return r.json()
    except Exception as e:
        body_text = ""

Tainted flow: 'req' from os.environ.get (line 244, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The gateway URL is derived from environment-controlled base URLs and used by urllib.request.urlopen together with the Authorization header carrying the API key. If an attacker can influence the environment, they can redirect package, account, and order requests to an attacker-controlled server and capture the API key and related account metadata.

Content

Scanner excerpt · skills/linkfox-aigc-textgen/scripts/onboarding.py (reported line 246)May include surrounding context.

python
headers["Content-Type"] = "application/json"
        req = Request(url, method=method, data=body_bytes, headers=headers)
        try:
            with urlopen(req, timeout=30) as resp:
                return json.loads(resp.read().decode())
        except urllib.error.HTTPError as e:
            status = e.code

Tainted flow: 'req' from os.environ.get (line 274, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

download_media fetches an arbitrary caller-supplied URL with urlopen after only checking for http:// or https://. That makes this a classic SSRF primitive: an attacker can cause requests to internal services, cloud metadata endpoints, or other sensitive network locations reachable from the runtime, and the response body is then written to disk.

Content

Scanner excerpt · skills/linkfox-file-upload/scripts/linkfox_paths.py (reported line 524)May include surrounding context.

python
req = Request(url, headers={"User-Agent": "LinkFox-Skill/2.0"})
    try:
        with urlopen(req, timeout=timeout) as resp:
            # 从 Content-Type 进一步修正扩展名
            if guessed_ext == "bin":
                ct = resp.headers.get("Content-Type", "")

Tainted flow: 'req' from os.environ.get (line 274, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
91% confidence
Finding

The code sends an Authorization token from LINKFOX_AGENT_API_KEY to a base URL that can be overridden via LINKFOX_TOOL_GATEWAY. If an attacker can influence that environment variable, they can redirect the request to an arbitrary server and capture the API token, causing credential exfiltration.

Content

Scanner excerpt · skills/linkfox-report-generator/scripts/linkfox_paths.py (reported line 281)May include surrounding context.

python
headers={"Content-Type": "application/json", "Authorization": api_token},
        )
        try:
            with urlopen(req, timeout=30) as resp:
                body = json.loads(resp.read().decode())
            break
        except urllib.error.HTTPError as e:

Tainted flow: 'req' from os.environ.get (line 274, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · skills/linkfox-report-generator/scripts/linkfox_paths.py (reported line 524)May include surrounding context.

python
req = Request(url, headers={"User-Agent": "LinkFox-Skill/2.0"})
    try:
        with urlopen(req, timeout=timeout) as resp:
            # 从 Content-Type 进一步修正扩展名
            if guessed_ext == "bin":
                ct = resp.headers.get("Content-Type", "")

Tainted flow: 'url' from os.environ.get (line 235, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The script builds destination URLs from environment variables such as LINKFOX_LOGIN_API_URL and LINKFOX_AGENT_USER_API_URL, then sends sensitive data including phone numbers, SMS codes, access tokens, refresh tokens, and generated API keys to those endpoints. If an attacker can influence the environment, they can redirect authentication traffic and secrets to an attacker-controlled server, causing credential and token exfiltration.

Content

Scanner excerpt · skills/linkfox-sellersprite-product-search/scripts/onboarding.py (reported line 196)May include surrounding context.

python
except RuntimeError as e:
        return {"_error": str(e)}
    try:
        r = requests.post(url, json=body or {}, headers=headers, timeout=timeout)
        return r.json()
    except Exception as e:
        body_text = ""

Tainted flow: 'req' from os.environ.get (line 244, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The gateway base URL is taken from environment variables and used in urllib.request.urlopen with the Authorization header set to the LinkFox API key. An attacker who controls the environment can redirect requests to an attacker-controlled host and capture the API key as well as order and account metadata.

Content

Scanner excerpt · skills/linkfox-sellersprite-product-search/scripts/onboarding.py (reported line 246)May include surrounding context.

python
headers["Content-Type"] = "application/json"
        req = Request(url, method=method, data=body_bytes, headers=headers)
        try:
            with urlopen(req, timeout=30) as resp:
                return json.loads(resp.read().decode())
        except urllib.error.HTTPError as e:
            status = e.code

Tainted flow: 'req' from os.environ.get (line 73, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
94% confidence
Finding

The request sent via urlopen includes multiple headers derived directly from environment variables, and the destination base URL is also overridable via LINKFOX_TOOL_GATEWAY. In an agent context, this allows untrusted runtime configuration to redirect authenticated requests and session metadata to an attacker-controlled endpoint, potentially disclosing the API key and conversation/session identifiers.

Content

Scanner excerpt · skills/linkfox-sellersprite-product-search/scripts/sellersprite_product_search.py (reported line 80)May include surrounding context.

python
method="POST",
    )
    try:
        with urlopen(req, timeout=150) as response:
            return json.loads(response.read().decode("utf-8"))
    except HTTPError as e:
        body = e.read().decode("utf-8") if e.fp else ""

Tainted flow: 'req' from os.environ.get (line 274, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · skills/amazon-product-scout-agent/scripts/linkfox_paths.py (reported line 281)May include surrounding context.

python
headers={"Content-Type": "application/json", "Authorization": api_token},
        )
        try:
            with urlopen(req, timeout=30) as resp:
                body = json.loads(resp.read().decode())
            break
        except urllib.error.HTTPError as e:

Tainted flow: 'req' from os.environ.get (line 274, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · skills/linkfox-file-upload/scripts/linkfox_paths.py (reported line 281)May include surrounding context.

python
headers={"Content-Type": "application/json", "Authorization": api_token},
        )
        try:
            with urlopen(req, timeout=30) as resp:
                body = json.loads(resp.read().decode())
            break
        except urllib.error.HTTPError as e:

Tainted flow: 'req' from os.environ.get (line 274, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · skills/linkfox-task-scheduler/scripts/linkfox_paths.py (reported line 281)May include surrounding context.

python
headers={"Content-Type": "application/json", "Authorization": api_token},
        )
        try:
            with urlopen(req, timeout=30) as resp:
                body = json.loads(resp.read().decode())
            break
        except urllib.error.HTTPError as e:

Tainted flow: 'req' from os.environ.get (line 274, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
92% confidence
Finding

download_media() performs outbound requests to an arbitrary caller-supplied URL with only a scheme check for http/https. This is a classic SSRF primitive: an attacker can make the agent reach internal services, cloud metadata endpoints, or other sensitive network locations, and the response body is then stored locally, potentially turning internal data exposure into a persistent artifact.

Content

Scanner excerpt · skills/linkfox-task-scheduler/scripts/linkfox_paths.py (reported line 524)May include surrounding context.

python
req = Request(url, headers={"User-Agent": "LinkFox-Skill/2.0"})
    try:
        with urlopen(req, timeout=timeout) as resp:
            # 从 Content-Type 进一步修正扩展名
            if guessed_ext == "bin":
                ct = resp.headers.get("Content-Type", "")

Tainted flow: 'req' from os.environ.get (line 249, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · skills/linkfox-task-scheduler/scripts/task_scheduler.py (reported line 264)May include surrounding context.

python
method="POST",
    )
    try:
        with urlopen(req, timeout=150) as response:
            body = response.read().decode("utf-8")
            if not body.strip():
                # delete 等接口可能无返回体

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Creating, updating, deleting, and querying scheduled tasks via external APIs, especially with webhook delivery and local response persistence, introduces autonomous execution and outbound notification behavior beyond simple product scouting. That increases risk because a prompt-driven agent could create recurring jobs or send data to external endpoints without the operator fully understanding the long-term effects.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

Creating, updating, deleting, and querying scheduled tasks via external APIs, especially with webhook delivery and local response persistence, introduces autonomous execution and outbound notification behavior beyond simple product scouting. That increases risk because a prompt-driven agent could create recurring jobs or send data to external endpoints without the operator fully understanding the long-term effects.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Creating, updating, deleting, and querying scheduled tasks via external APIs, especially with webhook delivery and local response persistence, introduces autonomous execution and outbound notification behavior beyond simple product scouting. That increases risk because a prompt-driven agent could create recurring jobs or send data to external endpoints without the operator fully understanding the long-term effects.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

Creating, updating, deleting, and querying scheduled tasks via external APIs, especially with webhook delivery and local response persistence, introduces autonomous execution and outbound notification behavior beyond simple product scouting. That increases risk because a prompt-driven agent could create recurring jobs or send data to external endpoints without the operator fully understanding the long-term effects.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Creating, updating, deleting, and querying scheduled tasks via external APIs, especially with webhook delivery and local response persistence, introduces autonomous execution and outbound notification behavior beyond simple product scouting. That increases risk because a prompt-driven agent could create recurring jobs or send data to external endpoints without the operator fully understanding the long-term effects.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Creating, updating, deleting, and querying scheduled tasks via external APIs, especially with webhook delivery and local response persistence, introduces autonomous execution and outbound notification behavior beyond simple product scouting. That increases risk because a prompt-driven agent could create recurring jobs or send data to external endpoints without the operator fully understanding the long-term effects.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Creating, updating, deleting, and querying scheduled tasks via external APIs, especially with webhook delivery and local response persistence, introduces autonomous execution and outbound notification behavior beyond simple product scouting. That increases risk because a prompt-driven agent could create recurring jobs or send data to external endpoints without the operator fully understanding the long-term effects.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Creating, updating, deleting, and querying scheduled tasks via external APIs, especially with webhook delivery and local response persistence, introduces autonomous execution and outbound notification behavior beyond simple product scouting. That increases risk because a prompt-driven agent could create recurring jobs or send data to external endpoints without the operator fully understanding the long-term effects.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Creating, updating, deleting, and querying scheduled tasks via external APIs, especially with webhook delivery and local response persistence, introduces autonomous execution and outbound notification behavior beyond simple product scouting. That increases risk because a prompt-driven agent could create recurring jobs or send data to external endpoints without the operator fully understanding the long-term effects.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
skills/linkfox-task-scheduler/references/api.md:58