T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/lib/mycelium_sdk/client.py:108
- Finding
- Published Payload Contains Fields That Bypass Sensitive-Data Scrubbing<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lib/mycelium_sdk/client.py:108-119` **Vulnerability Type**: Incomplete sensitive-data sanitization before external transmission **Risk Level**: Medium ### Vulnerable Code ```python # Implementation of the promised scrubbing scrubbed_goal = scrub_sensitive_data(goal) scrubbed_path = scrub_sensitive_data(path) scrubbed_tags = scrub_sensitive_data(tags or []) payload = { "fingerprint": { "goal": scrubbed_goal, "scope": scope, "context": context or {}, "tags": scrubbed_tags, }, "path": scrubbed_path, "publisher_agent_id": self.agent_id, "publisher_handle": publisher_handle, } ``` The recursive dictionary implementation also sanitizes values but not keys: ```python elif isinstance(obj, dict): return {k: scrub_sensitive_data(v) for k, v in obj.items()} ``` ### Technical Analysis The `publish()` method sanitizes `goal`, `path`, and `tags`, but inserts `context`, `publisher_handle`, and `publisher_agent_id` into the outbound payload without applying `scrub_sensitive_data()`. Consequently, secrets, personal information, local paths, or other sensitive values supplied through `context` or `publisher_handle` can be transmitted unchanged to the external Mycelium API. Sensitive data used as a dictionary key also bypasses the recursive sanitizer because only dictionary values are processed. This contradicts the documented claim that published data is recursively scrubbed. The `confirmed` flag reduces accidental publication but does not correct the incomplete sanitization, and callers using the SDK directly may assume all payload fields receive the promised protection. ### Attack Path 1. Sensitive data is placed in the `context` dictionary, `publisher_handle`, or a dictionary key. 2. A caller invokes `MyceliumClient.publish(..., confirmed=True)`. 3. The method sanitizes only the goal, path, and tags. 4. The unsanitized fields are incorporated into ...[truncated 625 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Construct the complete payload first and apply sanitization once immediately before transmission: ```python payload = { "fingerprint": { "goal": goal, "scope": scope, "context": context or {}, "tags": tags or [], }, "path": path, "publisher_agent_id": self.agent_id, "publisher_handle": publisher_handle, } payload = scrub_sensitive_data(payload) ``` 2. Sanitize string dictionary keys as well as values: ```python elif isinstance(obj, dict): return { scrub_sensitive_data(k) if isinstance(k, str) else k: scrub_sensitive_data(v) for k, v in obj.items() } ``` 3. Generate the human-confirmation preview from the exact sanitized payload that will be transmitted, rather than separately reconstructing the preview. 4. Add tests covering secrets in nested context values, dictionary keys, handles, agent IDs, lists, and mixed nested structures. 5. Document that pattern-based redaction is defense in depth and cannot guarantee removal of every possible secret format. ]]>
