T09 · Insecure Skill Coding Practices
- Location
scripts/merge_mentions.py:219- Finding
Plaintext Retention and Cross-Group Aggregation of Sensitive Chat Data
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:11-13, 48-66, 81-93;scripts/merge_mentions.py:67-76, 219-220
Vulnerability Type: Sensitive data stored in plaintext with excessive retention
Risk Level: MediumVulnerable Code and Instructions
The Skill explicitly defines the mapping database as sensitive and stores it at a fixed location:
markdown > **Data path**: The mapping database is fixed at `~/.mano-asr/mentions/openclaw.json` for use with **mano-asr**. > ⚠️ **Privacy**: The generated mapping database contains group members' real names and message evidence and is therefore **sensitive data**.It mandates collecting a broad historical message window and correlating identities across groups:
markdown - **New-group initialization**: `limit=200` (or retrieve all available history) - **Incremental update**: retrieve messages since the last analysis; when that cannot be determined, default to `limit=100` - **Minimum threshold**: never use fewer than 100 messages - Each item of evidence includes a `group_id` label. - `seen_in_groups` records every group in which the person appeared. - All mappings are merged across groups by `uid` into the same `openclaw.json`.The merge implementation retains complete evidence objects, including message text, and writes the resulting database as ordinary plaintext JSON:
python for e in a.get("evidence", []): if ev_key(e) not in seen: tgt.setdefault("evidence", []).append(e) seen.add(ev_key(e)) added += 1python out = merge(base, new) os.makedirs(os.path.dirname(os.path.abspath(args.out)), exist_ok=True) json.dump(out, open(args.out, "w", encoding="utf-8"), ensure_ascii=False, indent=2) print(f"merged -> {args.out} | version={out['version']} persons={len(out['persons'])}")Technical Analysis
The Skill intentionally processes sensitive group-chat history and persists complete evidence records containing message text, sender identifiers, tim ...[truncated 2618 chars]
- Remediation
View remediation
Remediation Suggestions
- Require explicit authorization before collecting message history from each group and before enabling cross-group identity correlation.
- Make cross-group aggregation opt-in. Keep records isolated by group unless correlation is necessary and approved.
- Apply data minimization:
- Do not impose a blanket minimum of 100 messages.
- Retrieve only messages needed to resolve outstanding aliases.
- Avoid storing complete message text by default.
- Store redacted excerpts, irreversible hashes, or message IDs when possible.
- Add a configurable retention policy for raw evidence, aliases, group associations, conflicts, and previous names. Provide commands to delete a person, a group, or all expired evidence.
- Create output files with owner-only permissions, such as mode
0600, and verify permissions after replacement. - Use atomic writes: create a restrictive temporary file in the destination directory, flush and synchronize it, then replace the destination with
os.replace. - Consider authenticated encryption for data at rest, with keys supplied through an operating-system key store rather than committed configuration.
- Validate the destination path and reject symlinks or unexpected file types before writing when the tool may operate in a shared or adversarial local environment.
- Document the threat model, lawful basis or consent requirements, access policy, retention duration, and incident-response procedure for this sensitive database.
- Add automated tests verifying restrictive permissions, atomic replacement, evidence expiration, redaction, deletion, and opt-in cross-group correlation.
