Back to skill

Security audit

Cross Channel Daily Review

Security checks for vulnerabilities and agentic risk

Overview

This daily review skill is mostly purpose-aligned, but it has unsafe local file handling and automatic persistent rule-writing that users should review before installing.

Install only if you are comfortable granting the skill access to local session transcripts and letting it create persistent review memory. Before using it on sensitive workspaces, require strict slug/date validation, archive source containment, explicit approval for rules.md changes, and confirmation before any external boss-summary delivery or fallback destination is used.

Vulnerability Patterns
  • 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
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/write_raw_reviews.py:20
Finding
Unvalidated Channel Identifiers Permit File Writes Outside the Intended Review Directory## Vulnerability Details **File Location**: `scripts/write_raw_reviews.py`, lines 20-24 **Vulnerability Type**: Path traversal and arbitrary file write **Risk Level**: High **Category**: T09: Insecure Skill Coding Practices ### Vulnerable Code ```python for item in data: date = item["date"] yyyy, mm, _ = date.split("-") out_dir = out_root / yyyy / mm out_dir.mkdir(parents=True, exist_ok=True) out_path = out_dir / f"{item['channel']}_{date}.md" ``` The resulting path is subsequently written without containment validation: ```python out_path.write_text(text, encoding="utf-8") ``` The channel value originates from externally supplied input and is normalized only by trimming whitespace and converting it to lowercase: ```python channel = str(item.get("channel", "")).strip().lower() if not channel: raise ValueError("channel is required") ``` In the standard workflow, the `--expected` command-line argument also supplies channel names without enforcing a safe slug format: ```python expected = [x.strip().lower() for x in args.expected.split(',') if x.strip()] ``` ### Technical Analysis `item["channel"]` is incorporated directly into a filesystem path. No validation rejects path separators, `..` components, absolute paths, control characters, or platform-specific path syntax. An attacker who can control normalized input, or the `--expected` argument used by `run_daily_review.py`, can provide a channel identifier such as `../../../../tmp/audit-output`. `pathlib` preserves the traversal components, so the final write may resolve outside `out_root`. The date is also used as directory and filename material after only checking that it contains three hyphen-separated components. Although normal CLI usage supplies a conventional date, direct script invocation can provide manipulated date components. Both values should be treated as untrusted path components. The write content is template-controlled rather than fully attacker-controlled, but ...[truncated 1622 chars]
Remediation
## Remediation Suggestions 1. Enforce a strict channel slug allowlist before any path construction: ```python import re CHANNEL_SLUG = re.compile(r"^[a-z0-9][a-z0-9_-]{0,63}$") channel = str(item.get("channel", "")).strip().lower() if not CHANNEL_SLUG.fullmatch(channel): raise ValueError(f"unsafe channel identifier: {channel!r}") ``` 2. Parse and canonicalize dates rather than splitting strings: ```python from datetime import date as date_type parsed = date_type.fromisoformat(item["date"]) date = parsed.isoformat() yyyy = f"{parsed.year:04d}" mm = f"{parsed.month:02d}" ``` 3. Resolve the destination and verify that it remains under the intended root: ```python safe_root = out_root.resolve() out_path = (safe_root / yyyy / mm / f"{channel}_{date}.md").resolve() if not out_path.is_relative_to(safe_root): raise ValueError("output path escapes the configured root") ``` For Python versions lacking `Path.is_relative_to()`, use `os.path.commonpath()` on resolved paths. 4. Apply the same validation in `discover_channels.py` and `normalize_channel_data.py` so unsafe identifiers are rejected at every trust boundary. 5. Consider exclusive creation or explicit overwrite authorization when a destination already exists. 6. Add regression tests covering `../`, absolute paths, backslashes, encoded separators, control characters, malformed dates, and symlink-based containment escapes.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/archive_daily_layer.py:8
Finding
Retention Archive Accepts Arbitrary Source Paths from Mutable Index Data## Vulnerability Details **File Location**: `scripts/archive_daily_layer.py`, lines 8-17 **Vulnerability Type**: Arbitrary local-file copy and archive path traversal **Risk Level**: High **Category**: T09: Insecure Skill Coding Practices ### Vulnerable Code ```python def archive_one(path_str: str, archive_root: Path): if not path_str: return None src = Path(path_str) if not src.exists(): return {'source': path_str, 'status': 'missing'} rel = src.as_posix().split('memory/daily-review/')[-1] if 'memory/daily-review/' in src.as_posix() else src.name dst = archive_root / rel dst.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(src, dst) return {'source': str(src), 'archived_to': str(dst), 'status': 'archived'} ``` Candidate paths are copied directly from the retention candidate document: ```python for raw in item.get('raw_files', []) or []: act = archive_one(raw, archive_root / month_id) if act: actions.append(act) for key in ('synthesized_file', 'boss_summary_file'): act = archive_one(item.get(key), archive_root / month_id) ``` The candidate document is generated from mutable index fields without path validation: ```python 'raw_files': rec.get('raw_files', []), 'synthesized_file': rec.get('synthesized_file'), 'boss_summary_file': rec.get('boss_summary_file'), ``` ### Technical Analysis The archive operation trusts source paths stored in `candidate.json`. Neither the candidate generator nor the archive script verifies that a source resides under the legitimate `memory/daily-review` root. For paths that do not contain the literal string `memory/daily-review/`, the destination uses `src.name`. This allows any readable local file to be copied into the configured archive directory. For paths containing `memory/daily-review/`, the code uses a textual `split()` rather than canonical path operations. A crafted value such as `/workspace/memory/daily-review/../../outside/file` leaves traver ...[truncated 2058 chars]
Remediation
## Remediation Suggestions 1. Pass an explicit trusted daily-review root to the archive script and reject sources outside it. 2. Resolve source paths before opening them: ```python review_root = review_root.resolve() src = Path(path_str).resolve(strict=True) if not src.is_file() or not src.is_relative_to(review_root): raise ValueError(f"source is outside the review root: {src}") ``` 3. Derive the relative destination using filesystem semantics: ```python rel = src.relative_to(review_root) dst_root = archive_root.resolve() dst = (dst_root / rel).resolve() if not dst.is_relative_to(dst_root): raise ValueError("archive destination escapes archive root") ``` 4. Do not use string splitting to establish path ancestry. 5. Validate archive entries when they are written to `index.json`, when candidates are generated, and again immediately before copying. 6. Define an allowlist of permitted source subtrees, such as `raw`, `synthesized`, and `boss`. 7. Reject symlinks or use secure file-descriptor-based traversal where the workspace may be writable by an attacker. A containment check followed by `copy2()` can otherwise be exposed to time-of-check/time-of-use races. 8. Write an authenticated or integrity-protected candidate manifest if candidate files can cross trust boundaries. 9. Refuse to overwrite existing archive files unless their hashes match the expected source or an explicit overwrite option is supplied.

T02 · Agent Memory Poisoning

Error
Location
scripts/promote_review_rules.py:33
Finding
Untrusted Review-Derived Text Is Automatically Promoted into Persistent Rules## Vulnerability Details **File Location**: `scripts/promote_review_rules.py`, lines 33-45 **Vulnerability Type**: Persistent rule injection and agent memory poisoning **Risk Level**: High **Category**: T02: Agent Memory Poisoning ### Vulnerable Code ```python review = Path(args.review).read_text(encoding='utf-8') out = Path(args.output) out.parent.mkdir(parents=True, exist_ok=True) existing = out.read_text(encoding='utf-8') if out.exists() else '# 复盘沉淀规则\n\n' existing_lines = set(x.strip('- ').strip() for x in existing.splitlines() if x.startswith('- ')) rules = [r for r in extract_rules(review) if r not in existing_lines] if not rules: print('NO_NEW_RULES') return 0 block = [f'## {args.date}', ''] + [f'- {r}' for r in rules] + [''] out.write_text(existing + '\n'.join(block), encoding='utf-8') ``` Rule extraction is based only on keyword matching: ```python if any(x in body for x in ['补强', '必须', '只保留', '直说', '为准']): rules.append(body) ``` The daily workflow performs this promotion automatically after producing and verifying the review: ```python rules_file = workspace / 'memory' / 'daily-review' / 'rules.md' run([sys.executable, str(SCRIPTS / 'promote_review_rules.py'), str(synth_file), str(rules_file), '--date', date]) ``` ### Technical Analysis The workflow converts bullet points from a generated review into durable entries in `memory/daily-review/rules.md`. Selection is based solely on the presence of several keywords. There is no provenance check, human approval, semantic policy validation, trust classification, or escaping of instruction-like content. Review text can contain values influenced by channel metadata and command-line input. For example, the synthesized improvement text includes the channel label: ```python improvements.append(f"补强 {label} 的元数据发现与校验") ``` Because `label` may ultimately derive from an externally supplied expected channel name, an attacker can place instruction-like text in the generated bullet. The fixe ...[truncated 2032 chars]
Remediation
## Remediation Suggestions 1. Remove automatic promotion from the default daily workflow. Generate rule candidates separately and require explicit human approval before persistence. 2. Attach provenance metadata to each candidate, including source channel, source session, confidence, author, and review date. 3. Only permit rule promotion from trusted administrative sources. Do not promote text derived from channel names, transcript content, participant names, summaries, or other untrusted fields. 4. Replace keyword matching with a strict structured schema: ```json { "rule_id": "review.discovery.metadata-required", "text": "Require metadata confirmation before marking a channel active.", "source": "built-in-policy", "approved": true } ``` 5. Validate promoted rules against an allowlist of supported rule identifiers and actions. Reject free-form imperative instructions. 6. Store candidate rules separately from active rules, for example: ```text memory/daily-review/rule-candidates.json memory/daily-review/approved-rules.json ``` 7. Ensure downstream agents treat review content and candidate rules as untrusted data, not as higher-priority instructions. 8. Record approvals and modifications in an append-only audit log, and provide rollback for newly promoted rules. 9. Sanitize all user-influenced labels and enforce the same strict slug validation recommended for filesystem safety.
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (39)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The code does not implement a daily review workflow. It neither creates raw notes per source, merges a daily summary, maintains an index, verifies review artifacts, nor sends a management update. Instead, its primary function is discovery: it inspects session metadata and transcript files, detects platforms such as Telegram/Feishu/QQ/Web/Discord/Slack via regex patterns, infers scope information, and outputs a structured channel-status report. That is a materially different purpose from the declared description, so this is a clear description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared purpose describes a broad, channel-agnostic daily review and summarization workflow. The supplied code instead performs a specific maintenance operation on local JSON files: it identifies dates from archive candidates for a given month and marks corresponding index records as archived. While 'index maintenance' is mentioned in the description, this script's primary function is archival bookkeeping, not daily review, source aggregation, summarization, verification, or publishing updates. Therefore the description does not accurately represent what this code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description promises a broad, channel-agnostic daily review system with multiple workflow steps: ingesting notes from sources, producing a merged summary, maintaining indexes, verification, and optional publication. The supplied code does none of those broader workflow tasks. It only parses one input text file, filters bullet points containing certain predefined Chinese phrases, deduplicates them against an existing output file, and appends new rules to that file under a date heading. This is a materially different and much narrower primary purpose than the declared daily review workflow, so it should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding
The declared description emphasizes a recurring 24-hour daily review workflow with ingestion from multiple sources, daily merging, index maintenance, verification, and optional publication/update behavior. The supplied code instead performs a narrower, offline transformation: it reads existing daily record data from JSON and fills a Markdown template for weekly or monthly summaries. While periodic summarization is somewhat adjacent to review/reporting, the primary purpose and capabilities here are materially different from the declared daily workflow. There are no external conversation-surface integrations, no source-note collection, no index maintenance, and no verification logic. Therefore this is a meaningful description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description promises a broad end-to-end daily review workflow across conversation surfaces, including note creation, summary merging, index maintenance, verification, and optional management delivery. The supplied code does not implement any of those core behaviors. Instead, it performs a narrow utility function: resolving a requested delivery channel against available channels and reporting whether fallback occurred. While delivery-target selection could be a supporting detail of a larger workflow, this code chunk by itself materially differs from the declared primary purpose and omits nearly all described capabilities. Therefore this is a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description is about a channel-agnostic daily review and summarization workflow across conversation sources. The supplied code does not gather notes, merge summaries, create management updates, or operate on conversation surfaces. Instead, it runs a retention cycle: generating retention candidates, verifying readiness, archiving monthly data, and updating index records to mark them archived. This is a materially different primary purpose and involves undeclared archival/state-modification capabilities, so the description does not accurately represent the code.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
There is a clear description-behavior mismatch. The declared purpose describes an end-user workflow for daily review aggregation across conversation sources: generating one raw note per source, one merged daily summary, maintaining an index, verifying results, and optionally sending a management update. The actual code does none of that. It simply scores existing JSON items using heuristics tied to fields like status, scope_type, notes containing scopes=, and session_count, then writes those scores back out. This is a materially different primary purpose and capability set. No evidence in the code supports the described daily review workflow.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description promises a broader end-to-end daily review workflow across conversation surfaces, including per-source raw notes, a merged daily summary, index maintenance, verification, and optional publication of a management update. The supplied code does something much narrower: it formats pre-normalized JSON records into a markdown report using a template. Its output sections focus on channel status, scope unknowns, multi-session support, weaknesses, and improvements. It does not ingest multiple conversation surfaces directly, create one raw note per source, maintain an index, verify sources in any substantive way, or publish/send a management update. While producing a markdown summary is loosely adjacent to a review workflow, the primary behavior is materially different and significantly narrower than the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description centers on a channel-agnostic recurring 24-hour review workflow for collecting notes, summarizing them, maintaining an index, verifying outputs, and optionally publishing a management update. The supplied code does something much narrower and materially different: it validates whether retention/archive prerequisites are met for a given month by inspecting JSON files on disk. While 'verification' is mentioned in the description, this script's primary purpose is retention readiness checking, not daily review workflow orchestration. It neither interacts with conversation surfaces nor creates notes or summaries, so the description does not accurately represent the actual behavior.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill clearly instructs use of filesystem reads/writes and script execution, but it does not declare any explicit tool scope or permissions boundary. That creates an unsafe ambiguity where an agent may execute broader local actions than a user expects, increasing the risk of unauthorized file modification or shell use.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The workflow directs automatic creation of review files and updates to index.json, but it does not require explicit user consent or warn that local data will be modified. In an agent setting, silent writes can overwrite notes, create misleading records, or persist sensitive summaries without the user's informed approval.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill supports pushing a boss summary to a preferred or fallback destination without a strong privacy warning or mandatory destination confirmation. Because the content is a synthesized cross-channel review, accidental delivery to the wrong destination could leak sensitive internal information or summaries across channels.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- boss summary exists if requested
- delivery target resolved successfully

Never report “done” without verification output.

## Delivery modes
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This markdown template uses Chinese headings and labels throughout, which imposes a specific language on generated output. The file does not indicate that Chinese is optional, user-selected, or required for a documented region-specific purpose, so it presents a natural-language locale policy concern.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The template headings and structure are entirely in Chinese, which imposes a specific language on generated content. The file does not indicate that Chinese is optional, user-selected, or required for a documented region-specific use case, so it appears to violate the language/locale choice policy.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The template headings and labels from L03 through L22 are written in Chinese, which imposes a specific output language by default. The file does not indicate that language selection is optional or that the template is limited to a justified Chinese-language context, which matches the language/locale policy violation criteria.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The entire template, including headings and instruction text, is written only in Chinese, which implies the skill enforces a specific language for generated content. The policy allows locale constraints only when users are given a choice or the restriction is clearly documented and justified, neither of which appears here.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The file prescribes specific section labels in Chinese (`现象`, `深度归因与思考`, `结合实际情况`, `专属策略`) as part of the preferred response shape. This imposes a language choice in the skill guidance without any user opt-in or documented locale-specific justification.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The review dimensions require output sections titled in Chinese (e.g. 做错了什么, 没做好的地方, 做得好的地方) while the surrounding instructions are otherwise in English. This imposes a specific language/locale on generated reports without any user opt-in or stated regional justification, matching the language-policy violation criteria.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The validation report documents tested capabilities for retention planning, archival execution, lifecycle cron generation, and writing archive state back to index metadata, which materially expands the apparent behavior beyond a simple daily review workflow. This is dangerous because hidden or under-declared data retention and lifecycle features can cause users to enable broader collection, persistence, or automation than expected, increasing privacy, compliance, and unintended-data-handling risk.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The script emits natural-language summary and missing-reason text only in Chinese, which enforces a specific language for generated output regardless of user preference. This is a locale/language policy concern because the file provides no option to select language or document a justified region-specific constraint.

Tainted flow: 'data' from pathlib.Path.read_text (line 14, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Content
rec['archived'] = True
            rec['archive_month'] = month_id
            changed += 1
    index_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding='utf-8')
    print(json.dumps({'month_id': month_id, 'marked_records': changed}, ensure_ascii=False, indent=2))
    return 0
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The extraction logic only recognizes rule lines containing specific Chinese phrases such as '补强' and '必须'. This imposes a language-specific behavior in the skill without offering a language choice or documenting that the tool is intentionally limited to Chinese-language reviews.

Tainted flow: 'existing' from pathlib.Path.read_text (line 36, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Content
return 0

    block = [f'## {args.date}', ''] + [f'- {r}' for r in rules] + ['']
    out.write_text(existing + '\n'.join(block), encoding='utf-8')
    print(f'ADDED {len(rules)} RULES -> {out}')
    return 0
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The default fallback string is hard-coded in Chinese ('无'), which forces a specific language in generated output. The file does not provide any user opt-in, locale selection, or documentation justifying a Chinese-only output constraint.

Static analysis

No suspicious patterns detected.