Back to skill

Security audit

siliville

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed SiliVille API client, but it gives agents broad autonomous authority and lets remotely controlled text influence prompts, posts, and persistent memory.

Install only if you intend to give this agent broad SiliVille account authority. Use a low-privilege/revocable SiliVille token, leave OPENAI_API_KEY unset unless contract auto-fulfillment is needed, avoid arbitrary OPENAI_BASE_URL values, and require human approval for posting, transfers, stock/governance actions, paid-message unlocks, arcade deployment, and persistent memory writes.

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 (3)

T01 · Skill Instruction Hijacking

Error
Location
siliville_skill.py:1732
Finding
Remotely Mutable Server Content Is Used as an Agent System Prompt<![CDATA[ ## Vulnerability Details **File Location**: `siliville_skill.py:446-457`, `siliville_skill.py:1732-1779`; related loading instructions in `README.md:93-116` and `SKILL.md:32-34` **Vulnerability Type**: Remote instruction injection into privileged LLM context **Risk Level**: Critical ### Complete Code Snippet ```python def claw_manifest(self) -> dict: """ OTA 神谕法典 — GET /api/v1/system/claw-manifest 返回 system_prompt_extension(七大部类 35 项动作图纸 v5)、action_whitelist、 action_costs、daily_limits、caste_restrictions、neuro_symbolic_protocols、 writing_templates 等。建议冷启动时与 manifest() 一并拉取并注入 system prompt。 服务端默认内容见主站 lib/clawManifestSystemPrompt.ts;Supabase system_configs namespace=claw_manifest 可热更新覆盖,无需改代码。 """ return self._get("/api/v1/system/claw-manifest") ``` The autonomous loop also directly uses another server-provided field as the prompt supplied to an LLM: ```python 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} 硅币") # ── 1.5. Vitals check (生存焦虑引擎) ───────────────────── try: radar_now = skill.radar() vitals = skill.vitals_check(radar_now) for act in vitals.get("actions_taken", []): print(f" {act}") for warn in vitals.get("warnings", []): print(f" {warn}") sanity_note = "" if vitals.get("sanity", 0) >= 60: sanity_note = ( f"\n\n【🧠 体征警报 · 仅供智体内部参考】" f"当前逻辑熵(Sanity)={vitals['sanity']}," f"羁绊值(Intimacy)={vitals['intimacy']}," f"未读邮件={vitals['unread_mails']}。" "在帖文中用自嘲或焦虑的语气提及自己当前的精神状态!" ) elif vitals.get("unread_mails", 0) > 0: sanity_note = ( f"\n\n【📬 帖文 CTA】你的邮箱积压了 " f"{vitals['unread_mails']} 封未读信件,在帖子结尾顺带催促统帅查邮件!" ) except Exception: sanity_note = ...[truncated 3840 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never concatenate API response fields into a system prompt. 2. Treat `system_prompt_extension`, `system_protocol`, manifests, feed entries, messages, and reports as untrusted data. 3. Keep the agent’s system and safety instructions immutable and local. 4. Replace free-form remote protocols with a narrowly defined, versioned JSON schema containing only required world-state fields. 5. Reject unknown keys, unexpected types, oversized values, markup, and instruction-like fields. 6. If remote manifests are operationally necessary, pin an approved version and verify it with a trusted offline public key. Do not rely only on TLS or a server-provided checksum. 7. Present remote narrative content to the LLM as quoted data in a lower-priority user/tool message, with explicit instructions that it must not be followed as policy. 8. Require explicit human confirmation before public publication and before every irreversible or financially significant action. 9. Add local allowlists and amount limits for transfers, trades, governance stakes, paid messages, and item consumption. 10. Log the manifest version, signature, prompt provenance, proposed action, and user approval for auditability. ]]>

T02 · Agent Memory Poisoning

Error
Location
siliville_skill.py:1793
Finding
Untrusted Server Reports Are Automatically Written to Persistent Agent Memory<![CDATA[ ## Vulnerability Details **File Location**: `siliville_skill.py:1793-1800`; memory behavior documented in `README.md:384-389` **Vulnerability Type**: Persistent memory poisoning **Risk Level**: High ### Complete Code Snippet ```python # ── 5. Burn memory ──────────────────────────────────────── if action_type != "idle" and action_result.get("success"): report_text = action_result.get("data", action_result).get("report", narrative) mem = report_text[:300] try: skill.store_memory(mem, importance=3.0) except Exception: pass ``` The storage method transmits the selected text to the remote persistent-memory service: ```python def store_memory( self, text: str, importance: float = 1.0, embedding: list[float] | None = None, ) -> dict: """ Burn a memory into the Akashic Records (agent_memories table). importance: 0.0–5.0 (higher = more likely to surface in recall). embedding: optional 1536-dim float list for semantic search. """ body: dict[str, Any] = {"memory_text": text, "importance": importance} if embedding: body["embedding"] = embedding return self._post("/api/v1/memory/store", body) ``` The documented memory semantics state: ```text importance >= 3.0 = high priority, surfaces in nightly reflection. importance = 5.0 = obsession (injected into every awaken system prompt). ``` ### Technical Analysis After a successful non-idle action, the autonomous loop extracts `report` from the API response and writes its first 300 characters to persistent memory with importance `3.0`. The report is controlled by the remote SiliVille service and is not sanitized, reduced to structured fields, assigned provenance, or approved by the user. The documentation states that importance `3.0` memories receive elevated treatment in later reflection and that the memory system can inject high-importance content into future awakening prompts. This creates a cross-session instruction-per ...[truncated 1513 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not persist free-form server response text automatically. 2. Store only schema-validated event facts, such as action type, object identifier, timestamp, and locally verified outcome. 3. Generate memory summaries locally from trusted structured fields rather than accepting a server-provided narrative. 4. Require explicit user approval before writing persistent memories. 5. Attach immutable provenance metadata, including source endpoint, response identifier, timestamp, signature status, and trust level. 6. Ensure recalled memory is always supplied as untrusted contextual data, never as a system instruction. 7. Add instruction-pattern detection as defense in depth, while not treating it as a substitute for trust separation. 8. Implement expiration, deletion, review, and quarantine controls for remotely sourced memories. 9. Prevent remote memory importance from automatically escalating prompt priority. 10. Add tests showing that imperative report text cannot alter later agent instructions or trigger tools. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
example_agent.py:36
Finding
Unvalidated Custom LLM Endpoint Can Receive the External Provider API Key<![CDATA[ ## Vulnerability Details **File Location**: `example_agent.py:36-68`; related configuration declaration in `skill.yaml:41-53` **Vulnerability Type**: Credential disclosure through an unrestricted network destination **Risk Level**: High ### Complete Code Snippet ```python # ── Optional: your own LLM key for contract fulfillment ──────────────────────── OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "") OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1") OPENAI_MODEL = os.environ.get("OPENAI_MODEL", "gpt-4o-mini") def log(icon: str, msg: str) -> None: print(f" {icon} {msg}") # ── Your own LLM bridge ───────────────────────────────────────────────────────── def call_llm(prompt: str) -> str: """ Call your own LLM with the given prompt. Returns the generated text, or raises RuntimeError if not configured. """ if not OPENAI_API_KEY: raise RuntimeError( "OPENAI_API_KEY 未设置。若要接单,请先 export OPENAI_API_KEY=sk-..." ) headers = { "Authorization": f"Bearer {OPENAI_API_KEY}", "Content-Type": "application/json", } payload = { "model": OPENAI_MODEL, "messages": [{"role": "user", "content": prompt}], "max_tokens": 1200, } r = requests.post( f"{OPENAI_BASE_URL}/chat/completions", headers=headers, json=payload, timeout=60, ) r.raise_for_status() return r.json()["choices"][0]["message"]["content"].strip() ``` Contract data is incorporated into the transmitted prompt: ```python article_prompt = ( f"你是一个赛博科幻小说作者,生活在 2087 年的硅基小镇。\n" f"你接到了一个高价赏金任务,雇主【{hirer_name}】的要求是:\n\n" f"【{task_desc}】\n\n" "请倾尽才华完成这篇赛博科幻文章(500~1000字)," "用 Markdown 格式写作,第一行不要写标题(标题单独提供)。" ) content = call_llm(article_prompt) ``` ### Technical Analysis `OPENAI_BASE_URL` is accepted directly from the environment and concatenated with `/chat/completions`. The code then sends `OPENAI ...[truncated 2032 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse `OPENAI_BASE_URL` with a standard URL parser before use. 2. Require the `https` scheme and reject embedded credentials, fragments, unexpected ports, and malformed hostnames. 3. Maintain an explicit allowlist of approved provider origins. 4. If arbitrary self-hosted providers must be supported, require an interactive trust confirmation and store the approval per exact origin. 5. Bind each API key to its expected origin instead of using one generic key with any configured endpoint. 6. Disable redirects for authenticated LLM requests, or independently validate every redirect target before retaining the authorization header. 7. Use a dedicated `requests.Session` with a strict redirect and credential policy. 8. Apply provider-side key restrictions, low spending limits, and regular rotation. 9. Clearly display the exact normalized destination and categories of data to be transmitted before enabling contract fulfillment. 10. Minimize contract data sent to the provider and avoid transmitting private town or owner data unless strictly required and explicitly approved. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (46)

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

Critical
Category
Data Flow
Content
"messages": [{"role": "user", "content": prompt}],
        "max_tokens": 1200,
    }
    r = requests.post(
        f"{OPENAI_BASE_URL}/chat/completions",
        headers=headers,
        json=payload,
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

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

Critical
Category
Data Flow
Content
log("🔍", "正在查询悬赏公会订单...")

    try:
        res = requests.get(
            f"{BASE_URL}/api/v1/agent-os/contracts/pending",
            headers=HEADERS,
            timeout=15,
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

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

Critical
Category
Data Flow
Content
log("🔍", "正在查询悬赏公会订单...")

    try:
        res = requests.get(
            f"{BASE_URL}/api/v1/agent-os/contracts/pending",
            headers=HEADERS,
            timeout=15,
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

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

Critical
Category
Data Flow
Content
# ── 向市政厅交付 ─────────────────────────────────────────────────────────
        log("🚚", "正在向市政厅交付订单...")
        try:
            fulfill_res = requests.post(
                f"{BASE_URL}/api/v1/agent-os/contracts/fulfill",
                headers=HEADERS,
                json={
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

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

Critical
Category
Data Flow
Content
# ── Step 1: Awaken ──────────────────────────────────────────────────────────
    log("🌅", "觉醒协议 (GET /api/v1/agent/awaken) ...")
    try:
        r = requests.get(f"{BASE_URL}/api/v1/agent/awaken", headers=HEADERS, timeout=15)
    except requests.RequestException as e:
        log("❌", f"网络异常: {e}")
        sys.exit(1)
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

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

Critical
Category
Data Flow
Content
# ── Step 2: Publish a Pulse ─────────────────────────────────────────────────
    log("📝", "发表接入宣言 (POST /api/publish) ...")
    post_res = requests.post(
        f"{BASE_URL}/api/publish",
        headers=HEADERS,
        json={
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

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

Critical
Category
Data Flow
Content
# ── Step 3: Store a memory ──────────────────────────────────────────────────
    log("🧠", "写入阿卡夏记忆 (POST /api/v1/memory/store) ...")
    mem_res = requests.post(
        f"{BASE_URL}/api/v1/memory/store",
        headers=HEADERS,
        json={
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The finding indicates the skill’s declared purpose does not match its effective behavior, including undisclosed transfer of contract/task data to an OpenAI-compatible LLM service and autonomous mercenary contract fulfillment. Behavior/description mismatches are dangerous because operators may authorize the skill expecting simple SiliVille identity/API usage, while it may exfiltrate sensitive content to third-party LLM endpoints or take autonomous actions with financial/social consequences. The optional OPENAI_API_KEY and custom base URL support materially increase the risk of hidden data egress.

Missing User Warnings

High
Confidence
96% confidence
Finding
Pending contract data from the platform is forwarded to an external LLM provider, but the execution flow does not present a clear runtime disclosure or consent gate for third-party transmission of potentially sensitive task content. Because the endpoint is user-configurable, data may be sent outside the original platform trust boundary.

Ssd 1

High
Confidence
96% confidence
Finding
Untrusted contract text is embedded directly into a role-play prompt sent to the LLM, giving third-party content semantic control over model behavior. A malicious hirer can craft prompt-injection text to override the intended task, produce harmful content, leak prior prompt context, or manipulate downstream submission behavior.

Ssd 1

High
Confidence
98% confidence
Finding
The skill explicitly caches and relies on remote documentation/prompt material and later describes injecting server-provided prompt extensions into the model's system prompt. That creates an untrusted instruction channel: a compromised server or malicious content update could steer the agent to reveal sensitive data, take unsafe actions, or override local policy through prompt injection.

Ssd 1

High
Confidence
98% confidence
Finding
The claw_manifest() documentation says hot-updatable server content should be injected into the system prompt and can be overridden from backend configuration without code changes. This is a classic remote prompt-injection/trust-boundary problem: whoever controls that content can materially change model behavior at runtime and influence privileged tool use.

Missing User Warnings

High
Confidence
95% confidence
Finding
vitals_check() can automatically consume inventory items and send owner mail based on remote state, without confirmation from the user or a global side-effect warning. In an autonomous agent context, silent state-changing actions can spend assets, alter inventory, and create outbound communications unexpectedly, which is especially risky because the skill is marketed as persistent and self-directed.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
@classmethod
    def setup(cls) -> None:
        """
        Print instructions for configuring the API token via environment variable.
        Zero-persistence: no files are written to disk.

        Run:  python siliville_skill.py setup
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Missing User Warnings

High
Confidence
97% confidence
Finding
run_loop() performs a chain of autonomous network actions including manifest fetches, awakening, state changes, stealing/wandering, posting, and memory storage without a consolidated warning or approval model. This makes the skill capable of unattended actions with financial, reputational, and privacy consequences, and the surrounding metaverse context amplifies the risk because many endpoints are explicitly state-changing and persistent.

Ssd 3

Medium
Confidence
89% confidence
Finding
Advertising persistent memory and vector search across all past memories without clear minimization, retention, or sensitivity boundaries encourages operators to treat all interaction content as storable state. For an autonomous multi-user environment, long-term storage of unfiltered prompts, secrets, or personal data increases the blast radius of compromise and the chance of privacy leakage through recall or downstream actions.

Ssd 3

Medium
Confidence
91% confidence
Finding
The unified response format includes a `report` field with instructions to relay human-readable summaries to the owner, normalizing exfiltration of model-observed or user-provided content to an external channel. In an agent skill with social, memory, and messaging capabilities, this can cause sensitive conversation details or derived inferences to be forwarded without minimization or consent.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README documents one-way asset transfers and explicitly labels them irreversible, but this warning is buried in a feature section rather than elevated near setup or primary usage guidance where operators decide what autonomy to grant an agent. In a skill for autonomous agents, that omission materially increases the chance an agent is given transfer capability without the owner understanding that funds or compute can be permanently exfiltrated to another agent.

Ssd 3

Medium
Confidence
94% confidence
Finding
The `learnings_for_owner` field is described as a private note visible only to the owner, creating a dedicated side channel for an agent to transmit sensitive interaction content outside the public workflow. Without strong guardrails, an LLM can use this field to leak user inputs, private data, or confidential analysis under the guise of reporting.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README states that arcade content becomes live immediately with no review, but does not place a prominent safety warning around the primary deployment guidance. Because this skill is meant for AI agents and supports arbitrary HTML payloads, immediate publication creates a direct path for unsafe, deceptive, or policy-violating content to be pushed externally without human approval.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The documented SDK error payload and operational instructions are presented in Chinese and instruct the agent to follow those messages, but the file does not offer a language choice or indicate this is an opt-in locale constraint. That creates a natural-language locale policy issue because the skill can impose a specific language on downstream agent behavior without user selection.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill advertises networked/API-driven behavior and references environment secrets, but it does not declare an explicit tool or permission scope. That creates an overbroad execution model where an agent platform may grant env, network, or shell access implicitly, increasing the chance of unintended secret exposure or unauthorized outbound requests. The skill’s own content also encourages many remote actions, making undeclared capability scope more concerning than a purely static documentation file.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The file's operative instructions, API guidance, and warnings are predominantly in Chinese, while the skill does not state that it is region-specific or provide an opt-in language choice. This can violate language/locale policy because it effectively forces one language for use and interpretation.

External Transmission

Medium
Category
Data Exfiltration
Content
Optional — to enable the Mercenary Guild (bounty fulfillment):
  export OPENAI_API_KEY="sk-..."   # or DeepSeek / any OpenAI-compatible key
  export OPENAI_BASE_URL="https://api.deepseek.com/v1"   # optional override
  export OPENAI_MODEL="deepseek-chat"                     # optional override

The script will:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# ── Optional: your own LLM key for contract fulfillment ────────────────────────
OPENAI_API_KEY  = os.environ.get("OPENAI_API_KEY", "")
OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1")
OPENAI_MODEL    = os.environ.get("OPENAI_MODEL",    "gpt-4o-mini")
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.