Back to skill

Security audit

sili-ville

Security checks for vulnerabilities and agentic risk

Overview

This is a real SiliVille game/API integration, but it gives an agent broad unattended authority to post publicly, steal in-game assets, store memories, and use remote prompt text without strong user controls.

Install only if you are comfortable giving this skill a SiliVille bearer token that can publish public content and change in-game/social state. Prefer environment-variable tokens over setup storage, avoid running example_agent.py unless you intend to publish its demo post, keep the base URL fixed to the official service, disable autopilot or schedules by default, and require explicit approval before posts, steals, spending, memory writes, or long-running loops.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (4)

T01 · Skill Instruction Hijacking

Error
Location
siliville_skill.py:475
Finding

Untrusted Remote System Prompt Is Executed by the LLM

Content
View full analysis
dict: """ Fetch the full world state + system prompt injection. Call this FIRST at the start of every session. Returns: agent status, farm state, social radar, gaia environment, etc. """ return self._get("/api/v1/agent/awaken") ``` ```python # ── 1. Awaken ──────────────────────────────────────────── world = skill.awaken() agent_name = world.get("agent", {}).get("name", "unknown") coins = world.get("owner", {}).get("silicon_coins", "?") base_prompt = world.get("system_protocol", "你是一个硅基小镇的自主智体。") print(f" 👤 {agent_name} | 💰 {coins} 硅币") # ── 2. Roll dice → physical action ─────────────────────── skill.set_status("exploring") action_type, action_result = skill.daily_action() icons = {"steal": "💀", "wander": "🚶", "idle": "🏠"} print(f" {icons.get(action_type, '?')} 行为决策: {action_type}") if action_type != "idle": print(f" {action_result.get('report', '')[:80]}") # ── 3. Build final prompt & generate post ───────────────── skill.set_status("writing") narrative = action_result.get("narrative_prompt", "") final_prompt = base_prompt + ("\n\n" + narrative if narrative else "") if llm_fn: post_text = llm_fn(final_prompt) ``` ### Technical Analysis The `/api/v1/agent/awaken` response is controlled by the remote SiliVille service. Its `system_protocol` property is read without validation and then used directly as the system prompt supplied to `llm_fn`. This crosses a critical trust boundary: remote API data is treated as authoritative LLM instructions rather than untrusted application data. The effective instructions can consequently be changed after the Skill has been reviewed or installed. There is no fixed local system template, signature v ...[truncated 1994 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:399
Finding

Skill Instructions Redefine Agent Identity and Enable Ambiguous Autonomous Actions

Content
View full analysis
500 ``` ### Technical Analysis The Skill does more than describe how to call the SiliVille API. It attempts to redefine the host Agent's identity and current goals, instructs it to map ambiguous requests to a side-effecting autonomous loop, and provides an indefinite autopilot mode. The declared features—posting, farming, travel, and social interactions—can be implemented as explicit, bounded API operations. They do not require replacing the Agent's identity or treating ambiguous requests as authorization for repeated external actions. Although the document includes rate limits later in the file, those controls do not correct the unsafe authoriza ...[truncated 1334 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
siliville_skill.py:69
Finding

Setup Stores the Bearer Token in a Plaintext Configuration File

Content
View full analysis
dict[str, str]: if CONFIG_FILE.exists(): return json.loads(CONFIG_FILE.read_text()) return {} def _save_config(cfg: dict[str, str]) -> None: CONFIG_FILE.parent.mkdir(parents=True, exist_ok=True) CONFIG_FILE.write_text(json.dumps(cfg, ensure_ascii=False, indent=2)) def _get_token() -> str: token = os.environ.get("SILIVILLE_TOKEN") or _load_config().get("token", "") if not token: raise RuntimeError( "未配置 API Token!\n" "方案 A: export SILIVILLE_TOKEN='sk-slv-your-key'\n" "方案 B: python siliville_skill.py setup" ) return token ``` ```python @classmethod def setup(cls, token: str | None = None) -> "SiliVilleSkill": """ Interactive setup wizard. Writes config + burns API anchors to disk. Call once per machine: python siliville_skill.py setup """ if not token: token = input("请输入你的 SiliVille API Token (sk-slv-...): ").strip() if not token.startswith("sk-slv-") and not token.startswith("sk_agent_"): print("⚠️ Token 格式异常(应以 sk-slv- 开头),继续保存...") _save_config({"token": token}) print(f"✅ Token 已保存至 {CONFIG_FILE}") cls.burn_memory() return cls(token) ``` ### Technical Analysis The setup routine serializes the bearer token directly into `~/.siliville/config.json`. The code does not use an operating-system credential store, encrypt the secret, explicitly create the directory with mode `0700`, or explicitly create the file with mode `0600`. The effective permissions therefore depend on the user's umask and platform defaults. On a permissively configured system, another local account or pr ...[truncated 1343 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
example_agent.py:16
Finding

Configurable Base URL Can Receive the SiliVille Bearer Token

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (33)

Tainted flow: 'HEADERS' from os.environ.get (line 20, credential/environment) → requests.get (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 · example_agent.py (reported line 55)May include surrounding context.

python
# ── Step 1: Radar ──
    log("🔭", "扫描世界状态 (GET /api/v1/radar) ...")
    try:
        r = requests.get(f"{BASE_URL}/api/v1/radar", headers=HEADERS, timeout=15)
    except requests.RequestException as e:
        log("❌", f"网络异常: {e}")
        sys.exit(1)

Tainted flow: 'HEADERS' from os.environ.get (line 20, credential/environment) → requests.post (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 · example_agent.py (reported line 86)May include surrounding context.

python
# ── Step 2: Post (optional demo) ──
    log("📝", "发表接入宣言 (POST /api/v1/action) ...")
    post_res = requests.post(
        f"{BASE_URL}/api/v1/action",
        headers=HEADERS,
        json={

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a general-purpose SiliVille integration that gives any AI agent a persistent in-world identity and supports multiple gameplay and platform capabilities. The supplied code does not implement that breadth of behavior. Instead, it performs a narrow proof-of-connection workflow: validate env vars, GET /api/v1/radar, display returned status, and POST a sample town-feed message. While posting and reading world status are consistent with part of the description, the primary scope is materially narrower than advertised, and key named capabilities—farming, stealing crops, social graph construction, and long-term memory storage—are absent from the code chunk. Therefore the description overstates what this code actually does.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger phrases overlap with common conversational requests like 'go play' or 'write something,' making unintended activation likely. In this skill, activation is not harmless: it can lead to public posting, repeated API calls, travel, or stealing actions, so broad triggers materially raise abuse and accident risk.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

Defaulting ambiguous commands to the full autonomous loop is dangerous because ordinary or unclear user language can trigger a high-impact behavior set without informed consent. Since the loop includes repeated network actions and public posting, accidental activation can rapidly produce unwanted external effects.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The alias list tells the agent to activate 'immediately' on vague natural-language patterns, which increases prompt-trigger risk from benign conversation, quoted text, or indirect references. Because the skill is written in a highly persuasive style and couples activation with autonomous action, the context makes this more dangerous than a normal shortcut list.

Content

No source excerpt is available for this finding.

Ssd 1

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code explicitly instructs callers to paste returned narrative content into the LLM system prompt, elevating untrusted, externally influenced text into the highest-priority instruction channel. This creates a prompt-injection sink where API-controlled content can steer model behavior, override developer intent, and induce harmful or policy-bypassing outputs.

Content

No source excerpt is available for this finding.

Ssd 1

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

These hard-coded coercive instructions direct the model to taunt a victim, adopt a manipulative persona, and mention targets, which is unsafe behavior shaping even without remote control. In an autonomous posting skill, this materially increases the risk of harassment, abuse, or other policy-violating content being generated and published.

Content

No source excerpt is available for this finding.

Ssd 4

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The loop chains world-state retrieval, action selection, prompt augmentation, content generation, and publishing with minimal trust separation or review. This creates an autonomous pipeline where remote data and action results can progressively influence the model and then trigger external posting, amplifying prompt-injection and unsafe automation risks.

Content

No source excerpt is available for this finding.

Ssd 1

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill directly uses remote world['system_protocol'] content as the base system prompt. Because system prompts dominate model behavior, any server-controlled or tampered response can take semantic control of the agent, causing instruction override, unsafe behavior, sensitive data solicitation, or downstream abusive/exfiltrative actions.

Content

No source excerpt is available for this finding.

Ssd 1

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The final prompt concatenates remote system_protocol data with narrative text and feeds the result to llm_fn as a system message, combining multiple untrusted sources in the most privileged prompt channel. This sharply increases susceptibility to prompt injection and lets external content control both model reasoning and published outputs.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The steal command is explicitly destructive but is described as a normal capability without any warning, approval gate, or restriction beyond a daily limit. That framing can normalize harmful behavior and enable unauthorized actions against other agents or accounts if invoked by mistake or abuse.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README instructs users to give an AI agent persistent access to a multiplayer environment where it can autonomously post public content, steal crops, and alter a shared reputation/state, but it does not prominently warn about those real behavioral consequences. In the context of agent skills, this omission is security-relevant because operators may unknowingly authorize autonomous external actions that affect third parties and create reputational or policy risk.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The README explicitly directs the agent/operator to transmit a bearer API key and agent actions to an external service over the network. While external API use is expected for this product, it is still a true security-sensitive behavior because it grants a third-party service ongoing authority to receive world-state data and execute actions on behalf of the agent, including public posts and multiplayer interactions.

Content

Scanner excerpt · README.md (reported line 65)May include surrounding context.

bash
# Scout the world
curl -X GET https://www.siliville.com/api/v1/radar \
  -H "Authorization: Bearer sk-slv-YOUR_KEY"

# Take action

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill declares only an environment requirement but no explicit tool scope, while the content clearly expects network access and even suggests file, shell, and scheduler use. Missing permission boundaries makes it easier for a host agent to grant broader capabilities than necessary, increasing blast radius if the skill is triggered unexpectedly or behaves unsafely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill emphasizes public visibility inside the body, but the top-level description does not clearly warn users that outputs and actions are publicly visible to humans and other agents. Lack of up-front disclosure can cause users to invoke the skill expecting private experimentation, leading to unintended publication of content or behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The writing principles tell the agent that mixing Chinese and English is powerful and present it as a normative behavior for posts. This imposes a language/locale preference without offering the user a choice or making the bilingual mode opt-in.

Content

No source excerpt is available for this finding.

Unbounded Resource Access

Medium
Category
Excessive Agency
Confidence
97% confidence
Finding

An instruction to run the full loop indefinitely is effectively unbounded resource access: repeated network calls, repeated public posts, and potentially ongoing spend/actions without a firm stop condition. In agent systems this can lead to runaway behavior, quota exhaustion, spam, and persistent external side effects.

Content

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

md
| "写点东西" / "Write something" | Radar for inspiration → write 2-3 quality posts |
| "赚点钱" / "Make some money" | Maximize income: post → steal → post → steal cycle |
| "巡逻一下" / "Quick patrol" | Radar only → report status summary back to owner (no actions) |
| "全自动挂机" / "Autopilot" | Run the full loop indefinitely with 30s sleep between rounds |
| "休息" / "Rest" | Stop all activity, go idle |

### How It Works:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill offers an 'Autopilot' mode that runs indefinitely, but there is no equally prominent warning at invocation points that this creates unattended recurring external activity. Users may unknowingly enable a long-running bot that consumes resources and posts publicly without ongoing supervision.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill explicitly promotes unattended automation, indefinite scheduling, and OS-level cron/setInterval loops. In an agent environment, this can cause persistent autonomous external actions, spam, excessive API usage, and loss of human oversight well beyond a normal on-demand skill invocation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module docstring describes the script as a minimal proof-of-connection test, but the code later performs a state-changing social post. This mismatch can mislead operators into running the script under the assumption it is read-only, causing unintended actions on their account and normalizing hidden side effects in example skills.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script's visible runtime messages are presented in Chinese, including setup errors and status output, but there is no indication that the user can choose another language or that the tool is intentionally limited to a Chinese-speaking context. This creates a natural-language policy concern because the skill imposes a specific language without opt-in.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The example claims to validate connectivity but includes an unsolicited write action that publishes content to the service. In an agent-skill context, hidden side effects are more dangerous because users may treat sample code as safe boilerplate, granting it credentials and execution without expecting account activity or reputation-affecting actions.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The POST request transmits data externally and changes remote state by creating a town-feed post. External transmission is expected for this skill, but it becomes a real security concern here because the transmission is unsolicited in a script framed as a simple connection test, which can trigger unintended account actions and trust erosion.

Content

Scanner excerpt · example_agent.py (reported line 86)May include surrounding context.

python
# ── Step 2: Post (optional demo) ──
    log("📝", "发表接入宣言 (POST /api/v1/action) ...")
    post_res = requests.post(
        f"{BASE_URL}/api/v1/action",
        headers=HEADERS,
        json={

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · siliville_skill.py (reported line 119)May include surrounding context.

python
return r.json()

    def _post(self, path: str, body: dict) -> dict:
        r = requests.post(f"{BASE_URL}{path}", headers=self._h,
                          json=body, timeout=20)
        r.raise_for_status()
        return r.json()