Back to skill

Security audit

Flash Thoughts

Security checks for vulnerabilities and agentic risk

Overview

The skill is a straightforward local note recorder, but a crafted date argument can read Markdown files outside its note folder.

Install only if you are comfortable with local plaintext notes being created and searched by the agent. Avoid saving secrets, use an explicit private notes directory, and treat the current version as needing fixes for date validation and safer search before using it in workflows that process untrusted instructions.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/flash.py:76
Finding

Path Traversal in Daily Note Display

Content
View full analysis
Optional[str]: """显示某天的闪念""" file_path = FLASH_DIR / f"{date_str}.md" if file_path.exists(): return file_path.read_text(encoding="utf-8") return None ``` ### Technical Analysis The `date_str` command-line argument is used directly as part of a filesystem path without being validated as a date or checked for path traversal components. Although the command describes this value as a date in `YYYY-MM-DD` format, no code enforces that format. `pathlib.Path` preserves absolute paths, separators, and `..` components supplied through `date_str`. Consequently, a value containing traversal components can cause the application to resolve a Markdown file outside `FLASH_DIR`. The automatically appended `.md` extension restricts the attack to paths ending in `.md`, but it does not ensure that the target remains inside the intended notes directory. ### Attack Path 1. An attacker, untrusted automation, or manipulated agent instruction gains the ability to choose the argument passed to the `show` command. 2. The attacker supplies traversal components instead of a valid date, for example: ```bash python3 scripts/flash.py show "../../other/private-note" ``` 3. The application constructs: ```text FLASH_DIR/../../other/private-note.md ``` 4. If that path exists and is readable by the process, `read_text()` reads it. 5. The command prints the file contents to standard output through the `show` command handler. ### Impact Assessment Successful exploitation discloses the contents of arbitrary `.md` files readable by the operating-system account running the Skill. The attacker does not gain additional operating-system privileges, and the appended extension limits the set of target files. How ...[truncated 151 chars]
Remediation
View remediation
Optional[str]: try: parsed_date = datetime.strptime(date_str, "%Y-%m-%d") except ValueError: return None normalized_date = parsed_date.strftime("%Y-%m-%d") base_dir = FLASH_DIR.resolve() file_path = (base_dir / f"{normalized_date}.md").resolve() if file_path.parent != base_dir: return None if file_path.is_file(): return file_path.read_text(encoding="utf-8") return None ``` Additional hardening should include: - Rejecting path separators, `..`, null bytes, and absolute paths explicitly. - Resolving both the configured base directory and candidate path before checking containment. - Requiring the target to be a regular file. - Returning a clear validation error when the input is not a valid `YYYY-MM-DD` date. - Adding tests for `../`, absolute paths, nested paths, malformed dates, and symlink-based escapes. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/flash.py:58
Finding

Regular Expression Denial of Service Through Search Input

Content
View full analysis
list: """搜索闪念""" results = [] pattern = re.compile(keyword, re.IGNORECASE) # 获取最近的文件 files = sorted(FLASH_DIR.glob("*.md"), reverse=True)[:days] for file_path in files: content = file_path.read_text(encoding="utf-8") if pattern.search(content): results.append({ "file": file_path.name, "matches": len(pattern.findall(content)) }) return results ``` ### Technical Analysis The search term is compiled directly as a Python regular expression. This creates two security and reliability problems: 1. A malformed expression, such as an unmatched parenthesis or bracket, raises `re.error`. Because the exception is not handled, the command terminates unexpectedly. 2. Expressions with catastrophic backtracking can require excessive CPU time on suitable input. The pattern is evaluated with both `search()` and `findall()` against the complete contents of every selected note file. The `--days` argument is also not bounded. Although slicing limits processing to the number of existing Markdown files, a large positive value can cause all available files to be scanned. Large note files increase the potential cost of pathological regular-expression evaluation. ### Attack Path 1. An attacker or untrusted caller controls the keyword supplied to the search command. 2. For a direct crash, the caller supplies an invalid expression: ```bash python3 scripts/flash.py search "(" ``` 3. `re.compile()` raises an uncaught `re.error`, terminating the command. 4. For resource exhaustion, the caller supplies a backtracking-heavy expression such as: ```bash python3 scripts/flash.py search "(a+)+$" ``` 5. If ...[truncated 731 chars]
Remediation
View remediation
list: results = [] pattern = re.compile(re.escape(keyword), re.IGNORECASE) safe_days = max(1, min(days, 365)) files = sorted(FLASH_DIR.glob("*.md"), reverse=True)[:safe_days] for file_path in files: content = file_path.read_text(encoding="utf-8") matches = pattern.findall(content) if matches: results.append({ "file": file_path.name, "matches": len(matches) }) return results ``` Further hardening should include: - Setting maximum lengths for search terms. - Bounding `days` to a documented, reasonable range. - Limiting the maximum file size processed by a single search. - Avoiding duplicate evaluation by calling `findall()` only once. - Catching `re.error` and returning a controlled validation error if regular-expression syntax is intentionally supported. - Using a regex engine with deterministic execution or enforcing an execution timeout when arbitrary regular expressions are a required feature. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/flash.py:38
Finding

Predictable Daily Note Path Follows Symbolic Links

Content
View full analysis
dict: """添加一条闪念""" ensure_dir() file_path = get_today_file() # 如果文件不存在,创建带标题的文件 if not file_path.exists(): today = datetime.now().strftime("%Y-%m-%d") header = f"# {today} 闪念\n" file_path.write_text(header, encoding="utf-8") # 追加新闪念 entry = format_entry(content) with open(file_path, "a", encoding="utf-8") as f: f.write(entry) ``` ### Technical Analysis The application writes to a predictable filename derived from the current date. It uses `Path.exists()`, `Path.write_text()`, and the standard `open()` function without rejecting symbolic links or atomically ensuring that the selected path is a regular file inside the configured directory. By default, these APIs follow symbolic links. If another local actor can write to `FLASH_DIR`, that actor can create the expected daily filename as a symbolic link to another file. The later append operation follows the link and writes the formatted thought to the link target. The existence check and subsequent write are separate operations, creating an additional time-of-check/time-of-use window in which the path can be replaced. ### Attack Path 1. A local attacker obtains write access to the configured `FLASH_DIR`. This may occur through overly broad directory permissions or because `FLASH_THOUGHTS_DIR` points to a shared directory. 2. The attacker determines the predictable filename for the current date, such as `2026-09-12.md`. 3. The attacker creates that path as a symbolic link to a target file writable by the victim account: ```bash ln -s /path/to/victim-writable-file ~/biji/闪念/2026-09-12.md ``` 4. The victim or agent runs: ```bash python3 scripts/flash.py add "attacker-controlled conte ...[truncated 796 chars]
Remediation
View remediation
None: flags = os.O_WRONLY | os.O_APPEND | os.O_CREAT if hasattr(os, "O_NOFOLLOW"): flags |= os.O_NOFOLLOW fd = os.open(file_path, flags, 0o600) try: metadata = os.fstat(fd) if not stat.S_ISREG(metadata.st_mode): raise ValueError("The note path is not a regular file") with os.fdopen(fd, "a", encoding="utf-8") as handle: fd = -1 handle.write(data) finally: if fd >= 0: os.close(fd) ``` Additional hardening should include: - Creating `FLASH_DIR` with restrictive permissions appropriate for private notes. - Rejecting a configured storage directory that is writable by untrusted users. - Resolving and verifying the directory location before use. - Checking with `lstat()` that existing daily paths are regular files rather than symbolic links. - Performing creation and append operations atomically rather than relying on a separate `exists()` check. - Creating new files with mode `0600` where supported. - Adding regression tests involving pre-created symlinks, dangling symlinks, nonregular files, and path replacement races. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (8)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README shows very broad natural-language trigger examples such as '帮我记下来' and '帮我找找之前关于博客的想法', which can easily overlap with ordinary conversation. In an agent setting, ambiguous triggers can cause unintended recording or retrieval of notes when the user did not mean to invoke the skill, leading to accidental persistence or exposure of sensitive content.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill documents file read/write behavior and likely uses environment/filesystem capabilities, but it does not declare any explicit tool scope or permissions. This weakens least-privilege controls and makes it easier for an agent platform to grant broader access than necessary, especially since the skill writes to user directories and may read/search note files.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are broad, conversational, and overlap with common speech such as 'help me remember this' or 'I just thought of something.' In an agent system with automatic skill routing, this can cause unintended invocation and unexpected file writes or searches from ordinary conversation, creating privacy and integrity risks even without malicious intent.

Content

No source excerpt is available for this finding.

Tainted flow: 'file_path' from os.environ.get (line 82, credential/environment) → open (file write)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/flash.py (reported line 50)May include surrounding context.

python
# 追加新闪念
    entry = format_entry(content)
    with open(file_path, "a", encoding="utf-8") as f:
        f.write(entry)

    return {

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README prominently advertises speaking to the agent to record thoughts and storing them in daily local files, but does not clearly warn users that their content will be persisted on disk. Users may disclose sensitive or private information assuming the interaction is ephemeral, creating privacy risk through unexpected long-term local storage and later discovery by other local users, backups, or indexing tools.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The trigger and usage examples for invocation are specified only in Chinese phrases, which implies activation may depend on Chinese-language input. This can conflict with a language/locale policy unless the skill explicitly offers language choice or documents that it is intentionally Chinese-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill description is written entirely in Chinese, which suggests a fixed language/locale expectation without indicating that users can choose another language. This can conflict with language/locale policy when no opt-in or justification for the restriction is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module description and user-facing text are presented exclusively in Chinese, which can effectively force a specific language for users without opt-in. The file does not indicate that the skill is intentionally region-specific or provide any alternative language option.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.