Back to skill

Security audit

Nutrition Logger Pro

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local diet logger, but it has broad activation rules and writes user-controlled text into spreadsheet CSV files without formula protection.

Review before installing if this agent may receive messages from other people or channels. Use a dedicated nutrition-log directory, avoid opening exported CSV files from untrusted inputs in spreadsheet software until CSV formula neutralization is added, and consider requiring confirmation before append, undo, or update actions inferred from vague messages.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/log_store.py:194
Finding

CSV Formula Injection in Nutrition Log Export

Content
View full analysis

Vulnerability Details

File Location: scripts/log_store.py, lines 194–221
Vulnerability Type: CSV formula injection
Risk Level: Medium

Vulnerable Code

python
def append_csv(log_dir, entries):
    ensure_log_dir(log_dir)
    with csv_path(log_dir).open("w", encoding="utf-8-sig", newline="") as handle:
        writer = csv.DictWriter(handle, fieldnames=CSV_FIELDS)
        writer.writeheader()
        for entry in entries:
            for item in entry.get("items", []):
                nutrition = item.get("nutrition") or {}
                row = {
                    "date": entry.get("date"),
                    "time": entry.get("time"),
                    "timezone": entry.get("timezone"),
                    "meal": entry.get("meal"),
                    "food": item.get("food"),
                    "amount_raw": item.get("amount_raw"),
                    "amount_g": item.get("amount_g"),
                    "source": item.get("source"),
                    "confidence": item.get("confidence"),
                    "note": item.get("note"),
                    "raw_message": entry.get("raw_message"),
                    "entry_id": entry.get("entry_id"),
                }
                for field in CSV_NUTRIENT_FIELDS:
                    row[field] = nutrition.get(field)
                writer.writerow(row)

Technical Analysis

The application writes attacker-influenced text fields directly to food_log.csv without neutralizing spreadsheet formula prefixes. Relevant fields include food, amount_raw, note, and raw_message.

CSV quoting performed by csv.DictWriter protects the CSV structure but does not prevent spreadsheet applications from interpreting cell contents as formulas. A value beginning with =, +, -, or @, including one preceded by whitespace, may therefore be evaluated when the generated file is opened in Excel or compatible spreadsheet software.

For example, a crafted food name or raw messag ...[truncated 1462 chars]

Remediation
View remediation

Remediation Suggestions

Introduce a dedicated CSV-cell sanitization function for every user-influenced textual field:

  1. Convert the value to text when appropriate.
  2. Inspect the first non-whitespace character.
  3. If it is =, +, -, or @, prefix the value with a single quote or another spreadsheet-safe neutralization marker.
  4. Preserve numeric fields as numeric values rather than applying text sanitization indiscriminately.
  5. Apply sanitization immediately before writer.writerow(row) so all CSV export paths receive consistent protection.
  6. Add regression tests covering formula prefixes, leading whitespace, tabs, carriage returns, and newlines.
  7. Document that JSONL remains the canonical data format and that CSV output is intended for spreadsheet consumption.

Example hardening pattern:

python
DANGEROUS_CSV_PREFIXES = ("=", "+", "-", "@")


def sanitize_csv_text(value):
    if value is None:
        return None
    text = str(value)
    if text.lstrip().startswith(DANGEROUS_CSV_PREFIXES):
        return "'" + text
    return text

Apply this function to fields such as food, amount_raw, note, raw_message, meal, and other text values that may be derived from untrusted input.

Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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 (14)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Line L005 states that all user-visible prompts, reply templates, examples, and error messages must use Chinese. This is a natural-language policy concern because it forces a specific language for all users without documenting user choice, opt-in, or a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill instructs the agent to read reference files, invoke a local Python script, and write persistent nutrition logs, but it does not declare any explicit tool or permission scope. That creates an over-privileged execution model where the runtime may grant broader file, shell, and environment access than the skill actually needs, increasing the blast radius if the skill is mis-triggered or influenced by crafted user input.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger list includes broad everyday words like '记录', meal names, and common English words such as 'lunch' and 'dinner', which can cause the skill to activate in conversations that are not intended to create or modify nutrition logs. Because this skill performs persistent writes and supports undo/update actions, accidental activation can lead to unintended data creation or modification.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file explicitly states it will process requests from arbitrary plain-text messages, leaving activation boundaries unclear. In a multi-skill or multi-channel agent, this broad intake combined with file reads, shell invocation, and persistent log writes raises the risk of cross-context triggering, causing private conversation content to be interpreted as structured nutrition data and stored locally.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

“始终使用中文回复用户”属于语言/locale 强制策略,但文档中没有提供用户选择语言的方式,也没有说明这是经用户明确选择的区域性工具。根据规则,这构成自然语言层面的语言政策问题。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This markdown file is entirely written in Chinese and the example user-facing response at L49 is also prescribed in Chinese, with no indication that users may choose another language. Under the policy, forcing a specific language without opt-in is a natural-language policy violation unless the locale constraint is explicitly justified, which is not present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This markdown file contains all user-facing guidance in Chinese, and there is no indication that users may select another language or that the skill is intentionally limited to a Chinese-speaking context. That creates a natural-language policy concern under the language/locale rule because it implicitly forces a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file presents all operational instructions and examples exclusively in Chinese, and it does not state that the user can choose another language or that the skill is intended only for Chinese-speaking contexts. Under the policy rule for natural-language violations, forcing a specific language without opt-in is a reportable issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The file title and all response templates are written exclusively in Chinese, indicating the skill is designed to respond in a fixed language. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This code includes natural-language messages shown to users in Chinese, such as the JSON parse error at L117, and similar strings appear throughout the file. The skill does not offer a language choice or document that it is intentionally region-specific, so it appears to impose a specific language/locale by default.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The parser error handler emits only Chinese text, and the file consistently uses Chinese-only user-facing strings. This creates a natural-language policy concern because the skill enforces a specific language without any opt-in, fallback, or documented region-specific justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This code returns user-visible natural-language messages such as validation errors and calculation notes entirely in Chinese, including at L056-L058, L062, L066, L068, and L092. Because the file provides no opt-in, fallback, or justification for a Chinese-only locale, it creates a language-policy risk under the rule for forced language without user choice.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/test_nutrition_cli.py (reported line 19)May include surrounding context.

python
if log_dir is not None:
            args.extend(["--log-dir", str(log_dir)])
        args.append(command)
        proc = subprocess.run(
            args,
            input=json.dumps(payload or {}, ensure_ascii=False),
            text=True,

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The examples and expected behavior are written only in Chinese, which can amount to a language/locale policy issue if the organization requires avoiding forced language constraints without user opt-in. The file does not indicate that the skill is region-specific or that users may choose another language.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.