Back to skill

Security audit

Calorie Visualizer

Security checks for vulnerabilities and agentic risk

Overview

The calorie logger is broadly purpose-aligned, but it needs review because it reads health profile data from a workspace file by default and has weak controls around network lookup and HTML rendering.

Install only if you are comfortable with the skill reading a workspace USER.md profile for body metrics, storing diet data locally, using Chromium to render reports, and sending food search terms to the USDA API when an API key is configured. Prefer setting an explicit daily_goal, using --offline for food lookup, and avoiding untrusted meal names until HTML escaping is fixed.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/visual_renderer.py:233
Finding

Unsanitized Meal Names Are Injected into Chromium-Rendered HTML

Content
View full analysis
{"".join([f'
{n}
{k} kcal
' for n,k in items[:5]])} ``` The resulting HTML is subsequently passed to Chromium through `html2image`: ```python hti = Html2Image(output_path=BASE_DIR) hti.screenshot(html_str=html, save_as="daily_report_raw.png", size=(1200, 900)) ``` ### Technical Analysis Meal names originate from user-controlled CLI input and are stored in SQLite without HTML validation: ```python c.execute("INSERT INTO entries (date, food_name, calories, protein, photo_path) VALUES (?, ?, ?, ?, ?)", (date, food_name, calories, protein, photo_path)) ``` The renderer retrieves these values and interpolates each meal name, represented by `n`, directly into an HTML document. No context-appropriate HTML escaping is applied before the document is loaded by Chromium. A meal name containing elements such as ``, ``, SVG, or other browser-supported markup can therefore modify the generated document. Depending on Chromium and `html2image` runtime restrictions, injected markup may cause requests to arbitrary remote or local-network URLs. It can also conceal or falsify nutrition information in the generated report. The bundled food database does not contain malicious markup. The exploitable input path instead comes from arbitrary meal names accepted by the `add` command and potentially from names returned by the optional USDA API. ### Attack Path 1. An attacker supplies or induces the user to log a crafted meal name, for example: ```bash python3 scripts/calorie_visualizer.py add '<img src="https://attacker.example/track">' 100 5 ``` 2. `add_entry()` stores the crafted name in `calorie_data.db`. 3. A successful l ...[truncated 1158 chars]
Remediation
View remediation
' f'
{html.escape(str(name), quote=True)}
' f'
{html.escape(str(calories), quote=True)} kcal
' f'' for name, calories in items[:5] ) ``` 2. Insert the pre-escaped `food_items_html` into the template instead of constructing markup from raw database values. 3. Apply strict length and character validation to meal names at ingestion, while retaining HTML escaping as the primary defense. 4. Treat names returned by online APIs as untrusted and escape them identically. 5. Configure the Chromium renderer to disable network access during report generation if supported. 6. Consider rendering the report without a browser, using a graphics library that treats meal names only as text. 7. Add regression tests using names containing `<`, `>`, `"`, `'`, SVG, `iframe`, and remote-resource elements, and verify that they appear as literal text without causing network requests. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Python Dependencies Use Unbounded Version Ranges

Content
View full analysis
=2.0.4 Pillow>=10.0.0 ``` ### Technical Analysis Both dependencies specify only minimum versions. A future installation can therefore retrieve any later release selected by the package resolver, including versions that were not reviewed with this Skill. This is especially relevant to `html2image`, which controls invocation of a local Chromium runtime, and Pillow, which parses and processes image files. A compromised, malicious, or newly vulnerable future release would become part of the Skill without any change to the audited project. The audit did not identify evidence that the currently named packages or specified minimum releases are malicious. The confirmed weakness is the absence of reproducible, integrity-verified dependency resolution. ### Attack Path 1. A user follows the documented installation command: ```bash python3 -m pip install -r requirements.txt ``` 2. The resolver queries the configured Python package index. 3. Because only lower bounds are specified, it selects compatible versions available at installation time rather than versions reviewed by the project. 4. If a selected future release is compromised or contains an exploitable regression, its package code is installed into the environment. 5. The dependency executes with the privileges of the user running installation or when imported by `visual_renderer.py`. ### Impact Assessment A malicious dependency release could execute code with the privileges of the installing user. Depending on those privileges, this could permit access to local files, environment variables, the calorie database, network resources, or other user-owned data. A non-malicious but incompatible future release could also break report rendering or change Chromium invocation behavio ...[truncated 81 chars]
Remediation
View remediation
``` The exact versions should be selected through compatibility and vulnerability testing rather than copied without validation. 2. Generate and commit a lock file containing transitive dependency versions. 3. Use hash verification, such as a requirements file generated with `pip-compile --generate-hashes`, and install with: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` 4. Install dependencies in an isolated virtual environment under a non-privileged account. 5. Run automated dependency vulnerability and license scanning in continuous integration. 6. Review and deliberately update pinned versions on a controlled schedule rather than allowing installation-time upgrades. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (19)

Tainted flow: 'url' from os.getenv (line 201, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/calorie_visualizer.py (reported line 202)May include surrounding context.

python
try:
        q = parse.quote(food_name)
        url = f"https://api.nal.usda.gov/fdc/v1/foods/search?query={q}&pageSize=1&api_key={USDA_API_KEY}"
        with request.urlopen(url, timeout=12) as resp:
            data = json.loads(resp.read().decode('utf-8', errors='ignore'))

        foods = data.get('foods') or []

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

This finding indicates the skill can read profile data from USER.md or an environment-configured path, which extends access beyond the narrow local calorie-logging use case described in the metadata. Allowing an environment variable to select an external markdown file can broaden file access unexpectedly and, combined with poor disclosure, may expose sensitive local data under the guise of a benign nutrition tool.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

This finding indicates the skill can read profile data from USER.md or an environment-configured path, which extends access beyond the narrow local calorie-logging use case described in the metadata. Allowing an environment variable to select an external markdown file can broaden file access unexpectedly and, combined with poor disclosure, may expose sensitive local data under the guise of a benign nutrition tool.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill is described as local calorie logging, but this code silently performs online USDA lookups and persists remote results into the local cache. That creates an undisclosed data egress path for user-entered food queries and changes the trust model of the skill, which is especially risky in a privacy-sensitive health context.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill advertises a broad set of capabilities including shell, file read/write, environment access, and optional network use, but does not declare any explicit tool scope or permissions boundaries. That creates unnecessary ambiguity for reviewers and increases the chance the skill can access local files or external services beyond what a user would reasonably expect from a calorie logger.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code automatically reads USER.md from the workspace and extracts height, weight, age, and gender to infer a calorie target. This is sensitive health/profile processing performed implicitly, without clear consent in the code path, and broadens access from meal logging to personal data harvesting.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This function parses USER.md for health-related attributes without any upfront disclosure or runtime permission check. In the context of a calorie tracker, height, weight, age, and gender are sensitive profile data, and implicit collection from a workspace file can violate user expectations and privacy boundaries.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code sends user-provided food names to an external API without a clear privacy warning or explicit opt-in. Even if the data seems low sensitivity, dietary queries can reveal health conditions, religion, culture, or lifestyle, and the skill presents itself as local-first.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
93% confidence
Finding

This is a real external transmission to a third-party USDA endpoint. In isolation it is not malware behavior, but in this skill context it is security-relevant because the tool is framed as local and the transmission happens as part of normal food lookup behavior, potentially exposing dietary data without informed consent.

Content

Scanner excerpt · scripts/calorie_visualizer.py (reported line 201)May include surrounding context.

python
try:
        q = parse.quote(food_name)
        url = f"https://api.nal.usda.gov/fdc/v1/foods/search?query={q}&pageSize=1&api_key={USDA_API_KEY}"
        with request.urlopen(url, timeout=12) as resp:
            data = json.loads(resp.read().decode('utf-8', errors='ignore'))

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The manifest promises calorie logging and visual reporting, but does not justify executing another script via subprocess as part of normal operation. Launching subprocesses is a materially broader capability than straightforward local data processing and increases execution surface without being disclosed.

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/calorie_visualizer.py (reported line 327)May include surrounding context.

python
return None

    try:
        result = subprocess.run(
            [sys.executable, VISUAL_RENDERER_PATH],
            capture_output=True,
            text=True,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The renderer reads personal attributes from a workspace-level USER.md file and uses them to derive a calorie goal, even though the skill is described as local calorie logging and visualization. This creates unnecessary access to sensitive profile data and expands the data scope beyond what is needed for rendering, which is a privacy and data-minimization violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code silently reads height, weight, age, and gender from USER.md without any user-facing notice or consent flow. These are sensitive health-adjacent personal attributes, and covertly ingesting them in a visualization component is risky because users would not reasonably expect this file access from the stated skill behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README advertises an optional USDA online fallback but does not clearly warn that food search terms may be sent to an external service when local lookup fails. This is a real privacy/transparency issue because users may reasonably assume the skill is fully local based on the surrounding description, and sensitive diet-related queries could be transmitted unexpectedly.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This JSON file is dominated by Chinese-language values for food names and aliases, which indicates a locale-specific dataset. Because the file itself provides no natural-language note that the skill is China-specific or that users can opt into this locale, it may violate the language/locale policy for skills that should not silently force a specific language.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency html2image is specified with only a lower bound, which makes builds non-reproducible and allows future installations to pull in unreviewed versions. That increases supply-chain risk because a newly released vulnerable or malicious package version could be installed without any manifest change.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
html2image>=2.0.4
Pillow>=10.0.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

Pillow is also unpinned, so installs may resolve to different versions over time, including versions with known security defects or regressions. Because Pillow processes image data, version drift is more dangerous here: malformed or attacker-controlled images can trigger memory corruption, resource exhaustion, or other parser-related issues in affected releases.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
html2image>=2.0.4
Pillow>=10.0.0

Unverifiable Dependency: Pillow has 16 known advisory(ies) (CVE-2016-2533 (Pillow buffer overflow in ImagingPcdDecode); CVE-2023-50447 (Arbitrary Code Execution in Pillow); CVE-2021-27922 (Pillow Uncontrolled Resource Consumption) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The manifest includes Pillow without pinning a version even though the package has multiple historical advisories, so it is impossible to verify from this file whether deployment will use a safe release. In this skill's context, local calorie logging and visual report generation likely involves opening or rendering image content, which makes an image-library dependency with unknown version status materially more risky than a generic utility package.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script creates daily_report_raw.png and daily_report.png and then deletes the intermediate file, but the code does not warn the user before performing these filesystem changes. Although the final image path is printed afterward, there is no prior disclosure in comments, docstrings, or prompts describing these write/delete operations.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.