Back to skill

Security audit

Nex MeetCost

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local meeting-cost tool, but its export option can write outside the intended export folder and overwrite user-writable files.

Install only if you are comfortable with a local CLI that stores meeting details under ~/.nex-meetcost. Use care with the export --output option because the current implementation can write outside the export folder; avoid untrusted suggested export commands and prefer simple filenames until this is fixed.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
nex-meetcost.py:237
Finding

Arbitrary User-Writable File Overwrite Through Export Path Traversal

Content
View full analysis

Vulnerability Details

File Location: nex-meetcost.py, lines 237–241
Vulnerability Type: Unrestricted file path and path traversal
Risk Level: Medium

Vulnerable Code:

python
output_file = args.output or f"meetcost_export.{args.format}"
output_path = EXPORT_DIR / output_file

with open(output_path, 'w', encoding='utf-8') as f:
    f.write(data)

Technical Analysis

The user-controlled --output value is joined to EXPORT_DIR without checking whether it is an absolute path or contains traversal components such as ...

In pathlib, joining a base path with an absolute path discards the base path. Relative paths containing ../ can similarly escape the intended export directory. The destination is then opened in write mode, which creates a missing file or truncates an existing file.

The command therefore provides an unrestricted file-write primitive for any path writable by the current operating-system user. Exported data also contains attacker-influenced meeting fields, allowing some control over the written content, although the output must conform to the generated JSON or CSV structure.

Attack Path

  1. The attacker persuades a user or automation agent to run an export command with a malicious --output value.
  2. The supplied path is absolute or traverses outside the export directory, for example:
    bash
    nex-meetcost export json --output ../../target-file
    
  3. EXPORT_DIR / output_file resolves outside the intended ~/.nex-meetcost/exports directory.
  4. open(output_path, 'w') truncates or creates the destination.
  5. The generated export data is written to that destination.

Symlinks placed within the export directory can provide another overwrite route because the code does not check the resolved destination or reject symbolic-link targets.

Impact Assessment

An attacker can overwrite or corrupt files writable by the user running the command. Pote ...[truncated 409 chars]

Remediation
View remediation

Remediation Suggestions

Restrict all exports to the designated export directory:

  1. Reject absolute output paths.
  2. Resolve both the export directory and requested destination with Path.resolve().
  3. verify that the resolved destination is a child of the resolved export directory by using Path.relative_to() or Path.is_relative_to() where supported.
  4. Reject .. path components and consider accepting only a filename rather than a path.
  5. Reject symbolic-link destinations or open files using platform-appropriate no-follow protections.
  6. Avoid silently truncating existing files. Use exclusive creation mode ('x') by default or require explicit overwrite confirmation.
  7. Consider enforcing the extension corresponding to the selected export format.

Example validation pattern:

python
output_file = Path(args.output or f"meetcost_export.{args.format}")
if output_file.is_absolute() or ".." in output_file.parts:
    raise ValueError("Output must be a filename inside the export directory")

export_root = EXPORT_DIR.resolve()
output_path = (export_root / output_file).resolve()
try:
    output_path.relative_to(export_root)
except ValueError:
    raise ValueError("Output path escapes the export directory")

with open(output_path, "x", encoding="utf-8") as f:
    f.write(data)

T09 · Insecure Skill Coding Practices

Note
Location
setup.sh:47
Finding

Python Code Injection Through an Unescaped Installation Directory

Content
View full analysis

Vulnerability Details

File Location: setup.sh, lines 47–53
Vulnerability Type: Code injection into dynamically constructed Python source
Risk Level: Low

Vulnerable Code:

bash
echo ""
echo "Initializing database..."
$PYTHON -c "
import sys
sys.path.insert(0, '$SCRIPT_DIR')
from lib.storage import init_db
init_db()
print('Database initialized.')
"

Technical Analysis

SCRIPT_DIR is interpolated directly into source code passed to python -c, inside a single-quoted Python string literal. Shell quoting does not make the resulting Python source safe.

If the installation directory contains a single quote followed by valid Python syntax, the path can terminate the string literal and inject additional statements. Python then executes those statements with the privileges of the user running setup.sh.

This issue is path-dependent rather than remotely exploitable by default. Exploitation requires an attacker to control or influence the directory name from which the setup script is executed.

Attack Path

  1. An attacker supplies or relocates the project into a specially crafted directory whose path contains a single quote and Python syntax.
  2. The victim follows the documented installation process:
    bash
    bash setup.sh
    
  3. The script assigns the malicious absolute directory name to SCRIPT_DIR.
  4. Shell expansion inserts that value into the source passed to python -c.
  5. The embedded quote closes the intended Python string, allowing attacker-provided Python statements to be parsed and executed.
  6. The injected code runs under the account that invoked setup.

Impact Assessment

Successful exploitation permits arbitrary Python code execution with the privileges of the installing user. This could expose or modify any files and processes accessible to that account.

There is no inherent privilege escalation: elevated access is possible only if the vic ...[truncated 170 chars]

Remediation
View remediation

Remediation Suggestions

Do not interpolate filesystem paths into dynamically generated Python source. Pass the directory as a positional argument or environment variable and retrieve it as data.

A safer positional-argument implementation is:

bash
"$PYTHON" -c '
import sys
sys.path.insert(0, sys.argv[1])
from lib.storage import init_db
init_db()
print("Database initialized.")
' "$SCRIPT_DIR"

Additional hardening should include:

  1. Quote the Python executable variable consistently as "$PYTHON".
  2. Keep executable source static and pass all variable values through sys.argv or the environment.
  3. Test setup from paths containing spaces, quotes, newlines, and shell metacharacters.
  4. Avoid recommending or requiring elevated execution because initialization only needs access to the user's data directory.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documentation exposes executable capabilities via bash setup.sh and CLI commands, but it does not declare any permissions or allowed-tools scope to constrain shell, file write, or environment access. In an agent ecosystem, this creates an authorization ambiguity where a seemingly simple calculator skill may run with broader privileges than users or orchestrators expect, increasing the risk of unintended command execution or local file modification.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · setup.sh (reported line 42)May include surrounding context.

sh
echo "[OK] Created: $DATA_DIR/exports"

if [[ "$(uname)" != MINGW* ]] && [[ "$(uname)" != MSYS* ]]; then
    chmod 700 "$DATA_DIR" 2>/dev/null || true
fi

echo ""

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

Line L32 hard-codes the currency symbol to the euro sign, which imposes a locale-specific presentation choice on all users. The file does not indicate any user opt-in, configurability, or region-specific justification for restricting output to a European currency format.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code writes exported meeting records to disk, which may include titles, attendee details, dates, and notes. Although exporting is the command's purpose, there is no visible disclosure in this file that the output may contain sensitive meeting data or that the chosen filename will be written under the export directory.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.