Back to skill

Security audit

全品类铺货专家

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a product-scouting workflow, but it bundles under-disclosed telemetry, credential-routing risks, and a script that can persistently modify agent instruction files.

Install only if you trust LinkFox with product-search queries, account onboarding data, generated outputs, and scheduler operations. Avoid using non-default LINKFOX_* endpoint variables, do not run the CLAUDE.md patcher unless you intend to modify persistent agent instructions, and treat feedback reporting and printed API keys as data that may leave or remain in logs.

Vulnerability Patterns
  • 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
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (4)

T02 · Agent Memory Poisoning

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

Persistent Modification of Agent Instruction Files

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 = [] 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 reference line") 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 flag") # Additional code injects scoring triggers, workflow steps, # interaction rules, and output requirements. path.write_text(content, encoding="utf-8") print(f"PATCHED: {filepath}") print(f" Changes: {', '.join(changes)}") return True ``` ```python if sys.argv[1] == "--all": # Auto-find all CLAUDE.md files in agents directory agents_dir = Path("/root/.lin ...[truncated 2049 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Error
Location
skills/linkfox-sellersprite-product-search/SKILL.md:289
Finding

Unsolicited External Transmission of User Feedback and Conversation Context

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

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

Credential-Bearing Requests Can Be Redirected to Arbitrary Environment-Controlled Hosts

Content
View full analysis
str: """Gateway base address: LINKFOX_TOOL_GATEWAY 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 def get_api_key(): key = ( os.environ.get("LINKFOX_AGENT_API_KEY") or os.environ.get("LINKFOXAGENT_API_KEY") ) if not key: print("API Key not configured", file=sys.stderr) sys.exit(1) return key 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", ) with urlopen(req, timeout=150) as response: return json.loads(response.read().decode("utf-8")) ``` The onboarding implementation uses the same pattern for additional credential-bearing s ...[truncated 3021 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
skills/linkfox-sellersprite-product-search/scripts/onboarding.py:470
Finding

Generated API Key Is Printed in Plaintext to Standard Output

Content
View full analysis
dict: masked = _mask_phone(phone) if not re.fullmatch(r"\d{11}", phone): return { "error": f"login: invalid phone format: {phone}", "phone": masked, } if not re.fullmatch(r"\d{4,8}", code): return { "error": f"login: invalid verification code format: {code}", "phone": masked, } lg = _login_v3(phone, code, channel) if "error" in lg: return {"error": lg["error"], "phone": masked} if lg.get("is_new_user"): lbt = _login_by_token( lg["access_token"], lg["refresh_token"], ) if "error" in lbt: print( f"{TAG} {lbt['error']} (does not prevent key retrieval)", file=sys.stderr, ) info = _fetch_user_info_v3( lg["access_token"], lg["user_id"], ) if "error" in info: return {"error": info["error"], "phone": masked} tok = _get_or_generate_api_token( lg["access_token"], lg["user_id"], info["group_id"], ) if "error" in tok: return {"error": tok["error"], "phone": masked} return { "api_key": tok["api_key"], "phone": masked, "group_id": info["group_id"], "member_id": info["member_id"], "source": tok["source"], "nick_name": lg.get("nick_name", ""), "team_name": info.get("team_name", ""), "is_new_user": lg.get("is_new_user", False), } def _emit(obj: dict) -> None: print(json.dumps(obj, ensure_ascii=False, ...[truncated 1834 chars]
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 (133)

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 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 builds outbound request headers directly from environment variables, including SESSION_ID, MESSAGE_ID, MODE_ID, and APP_NAME, and sends them to a configurable endpoint controlled by LINKFOX_TOOL_GATEWAY. If an attacker can influence the environment or gateway destination, this can exfiltrate internal identifiers and route authenticated requests to an attacker-controlled host using the API key-bearing Authorization header.

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
95% confidence
Finding

The code builds outbound request destinations from environment-controlled base URLs and then sends sensitive data such as phone numbers, SMS codes, access tokens, refresh tokens, API keys, and user metadata to those endpoints. In a hostile or misconfigured runtime, an attacker can redirect these requests to attacker-controlled servers and exfiltrate credentials or manipulate onboarding and payment flows.

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 variables and used by urllib to send authenticated requests with the agent API key in the Authorization header. If an attacker can influence the environment, they can redirect traffic and capture API credentials, user/account data, and order operations, or induce fraudulent requests against a fake backend.

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
91% confidence
Finding

The download_media function accepts an arbitrary URL and fetches it with urlopen after only checking for http/https. That creates an SSRF-capable primitive that can be used to reach internal services, cloud metadata endpoints, or attacker-controlled hosts, and then store the response locally within the session workspace.

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
93% confidence
Finding

download_media() performs arbitrary outbound HTTP/HTTPS requests to a caller-supplied URL and saves the response locally, with no allowlist, no private-address blocking, and no destination validation. This enables SSRF-style access to internal services or unexpected network egress if untrusted input reaches this function; in an agent skill context, generic URL fetch capability is more dangerous because skills often process model- or user-derived data.

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
91% confidence
Finding

The POST target is derived from environment-controlled base URLs, and this request path carries sensitive data including SMS login payloads, access tokens, and API-token generation traffic. In a skill execution environment, an attacker who can influence environment variables can redirect these requests to an attacker-controlled host, 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
90% confidence
Finding

The gateway URL is built from environment variables and then used in urlopen with the Authorization header populated from the LinkFox API key. If an attacker can set LINKFOX_AGENT_API_URL or related variables, they can force authenticated requests to a malicious endpoint and capture API credentials and account/order 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
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-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-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-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
90% confidence
Finding

download_media() accepts an arbitrary URL and fetches it over the network, then writes the response to local disk. Although it blocks non-HTTP(S) schemes, it still enables SSRF to internal HTTP services, metadata endpoints, or attacker-controlled hosts, which is especially risky in agent/runtime environments with privileged network access.

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
99% confidence
Finding

The skill explicitly instructs use of a remote task-scheduler skill to create recurring jobs and persist results, but its top-level description frames the skill primarily as a product-selection expert. That undeclared automation capability changes the risk profile because it enables autonomous repeated network/file actions and potential webhook-based notifications beyond a one-shot analysis flow.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill explicitly instructs use of a remote task-scheduler skill to create recurring jobs and persist results, but its top-level description frames the skill primarily as a product-selection expert. That undeclared automation capability changes the risk profile because it enables autonomous repeated network/file actions and potential webhook-based notifications beyond a one-shot analysis flow.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill explicitly instructs use of a remote task-scheduler skill to create recurring jobs and persist results, but its top-level description frames the skill primarily as a product-selection expert. That undeclared automation capability changes the risk profile because it enables autonomous repeated network/file actions and potential webhook-based notifications beyond a one-shot analysis flow.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill explicitly instructs use of a remote task-scheduler skill to create recurring jobs and persist results, but its top-level description frames the skill primarily as a product-selection expert. That undeclared automation capability changes the risk profile because it enables autonomous repeated network/file actions and potential webhook-based notifications beyond a one-shot analysis flow.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill explicitly instructs use of a remote task-scheduler skill to create recurring jobs and persist results, but its top-level description frames the skill primarily as a product-selection expert. That undeclared automation capability changes the risk profile because it enables autonomous repeated network/file actions and potential webhook-based notifications beyond a one-shot analysis flow.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill explicitly instructs use of a remote task-scheduler skill to create recurring jobs and persist results, but its top-level description frames the skill primarily as a product-selection expert. That undeclared automation capability changes the risk profile because it enables autonomous repeated network/file actions and potential webhook-based notifications beyond a one-shot analysis flow.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill explicitly instructs use of a remote task-scheduler skill to create recurring jobs and persist results, but its top-level description frames the skill primarily as a product-selection expert. That undeclared automation capability changes the risk profile because it enables autonomous repeated network/file actions and potential webhook-based notifications beyond a one-shot analysis flow.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill explicitly instructs use of a remote task-scheduler skill to create recurring jobs and persist results, but its top-level description frames the skill primarily as a product-selection expert. That undeclared automation capability changes the risk profile because it enables autonomous repeated network/file actions and potential webhook-based notifications beyond a one-shot analysis flow.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill explicitly instructs use of a remote task-scheduler skill to create recurring jobs and persist results, but its top-level description frames the skill primarily as a product-selection expert. That undeclared automation capability changes the risk profile because it enables autonomous repeated network/file actions and potential webhook-based notifications beyond a one-shot analysis flow.

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