Back to skill

Security audit

Nex Timetrack

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local time tracker, but it needs review because confirmed export and setup bugs can affect files outside the skill's own data area.

Install only after reviewing the local-file risks. Do not run setup from an untrusted or unusually named directory, do not run it with elevated privileges, and avoid using --output paths outside a simple filename until path containment is fixed. Treat exports as sensitive business data, especially CSV files opened in spreadsheet software.

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

T09 · Insecure Skill Coding Practices

Error
Location
nex-timetrack.py:441
Finding

Arbitrary File Overwrite Through Export Path Traversal

Content
View full analysis

Vulnerability Details

File Location: nex-timetrack.py:441-445
Vulnerability Type: Path traversal and arbitrary file overwrite
Risk Level: High

python
output_file = args.output or f"timetrack_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 value supplied through the --output argument is used directly as a path component without validation or containment checks. Python's pathlib permits both traversal components and absolute paths:

  • A value such as ../../target escapes EXPORT_DIR.
  • An absolute value causes the preceding EXPORT_DIR component to be discarded.
  • The use of open(..., 'w') creates a missing file or truncates an existing file.
  • Symbolic links are followed, allowing a link inside the export directory to redirect the write elsewhere.

The exported contents are constrained to generated JSON or CSV, but fields within those formats include user-controlled time-entry data. The flaw therefore provides an attacker with an arbitrary file-write location, though not completely arbitrary file contents.

Attack Path

  1. The attacker obtains the ability to invoke the CLI or influences an agent to execute an export command.
  2. The attacker supplies an output path containing traversal components or an absolute path, for example:
    bash
    nex-timetrack export json --output ../../target-file
    
  3. EXPORT_DIR / output_file resolves outside the intended export directory.
  4. The program opens the selected target with write-and-truncate behavior.
  5. Any existing user-writable target is overwritten with the generated export data.

A similar attack is possible by placing a symbolic link in the export directory and selecting that link as the output filename.

Impact Assessment

The attacker can create or overwrite files accessible to the account running ...[truncated 339 chars]

Remediation
View remediation

Remediation Suggestions

  • Restrict --output to a filename rather than an arbitrary path.
  • Reject absolute paths, .. components, directory separators, empty filenames, and platform-specific alternate separators.
  • Resolve the candidate path and verify that it remains under the resolved export directory:
    python
    export_root = EXPORT_DIR.resolve()
    output_name = Path(args.output or f"timetrack_export.{args.format}")
    
    if output_name.is_absolute() or output_name.name != str(output_name):
        raise ValueError("Output must be a filename without directory components")
    
    output_path = (export_root / output_name).resolve()
    if output_path.parent != export_root:
        raise ValueError("Output path escapes the export directory")
    
  • Enforce the extension associated with the selected export format.
  • Where overwriting is unnecessary, use exclusive creation mode ('x') to prevent accidental truncation.
  • Defend against symbolic-link attacks by using operating-system facilities such as O_NOFOLLOW where supported, or by securely creating files and verifying the resulting file descriptor.
  • Apply restrictive permissions to generated exports because they may contain client names, email addresses, billing rates, notes, and work descriptions.

T09 · Insecure Skill Coding Practices

Error
Location
setup.sh:49
Finding

Python Code Injection Through Installation Directory Name

Content
View full analysis

Vulnerability Details

File Location: setup.sh:49-55
Vulnerability Type: Code injection caused by unsafe source-code interpolation
Risk Level: High

bash
$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 Python source code enclosed by single quotes. A Unix directory name may legally contain single quotes, semicolons, hash characters, and other Python syntax. Consequently, a crafted installation-directory name can terminate the string literal and append attacker-controlled Python statements.

Shell quoting does not neutralize this issue. Although the -c program is passed as one shell argument, the expanded directory value subsequently becomes part of the Python program and is parsed as executable Python syntax.

For example, a directory component conceptually shaped like the following can close the intended string, execute another Python expression, and comment out the remainder of the line:

text
crafted'); __import__('os').system('attacker-command'); #

This is a local installation-time code-injection vulnerability.

Attack Path

  1. An attacker distributes or places the project inside a directory whose name contains crafted Python syntax.
  2. The victim runs the documented installation command:
    bash
    bash setup.sh
    
  3. setup.sh calculates SCRIPT_DIR from the location of the setup script.
  4. The crafted path is inserted into the Python program passed to python -c.
  5. Python parses and executes the injected statement during database initialization.
  6. The payload runs with the privileges and environment of the user executing setup.

Exploitation requires control over, or influence on, the project installation path. It does not require elevated privileges if the victim runs setup as a normal user.

...[truncated 448 chars]

Remediation
View remediation

Remediation Suggestions

Do not embed filesystem paths into generated Python source. Pass the directory as a separate argument:

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:

  • Quote the Python executable invocation consistently.
  • Prefer invoking a dedicated initialization script over constructing multiline source for python -c.
  • Avoid relying on manual escaping because correct escaping must account for quotes, backslashes, control characters, and newlines.
  • Add an installation test using directory names containing spaces, quotes, Unicode characters, and shell metacharacters.
  • Document that the setup script should not be run with unnecessary elevated privileges.

T09 · Insecure Skill Coding Practices

Warning
Location
lib/storage.py:604
Finding

Spreadsheet Formula Injection in CSV Exports

Content
View full analysis

Vulnerability Details

File Location: lib/storage.py:604-612
Vulnerability Type: CSV formula injection
Risk Level: Medium

python
elif format_type == 'csv':
    import csv
    import io
    if not entries:
        return ""
    output = io.StringIO()
    writer = csv.DictWriter(output, fieldnames=entries[0].keys())
    writer.writeheader()
    writer.writerows(entries)

Technical Analysis

Entry data is written directly to CSV without neutralizing values that spreadsheet applications may interpret as formulas. Relevant exported fields can contain user-controlled descriptions, notes, tags, client names, and project names.

The Python CSV module correctly quotes delimiters and line breaks, but CSV quoting does not prevent spreadsheet formula evaluation. Cells beginning with characters such as =, +, -, or @ may be treated as formulas when opened in spreadsheet software. Leading whitespace, tabs, or carriage returns may also be used to evade simplistic prefix checks in some spreadsheet applications.

The severity depends on the spreadsheet program and its security settings. Modern software may restrict or warn about dangerous operations, but formula execution can still enable deceptive content, external-resource requests, or disclosure through spreadsheet-supported functions.

Attack Path

  1. An attacker supplies or causes the user to save a malicious field, such as a time-entry description beginning with a spreadsheet formula.
  2. The victim exports the affected records:
    bash
    nex-timetrack export csv
    
  3. csv.DictWriter serializes the malicious value without formula neutralization.
  4. The exported file is opened in a spreadsheet application.
  5. The application interprets the cell as a formula.
  6. Depending on spreadsheet capabilities and security settings, the formula may display deceptive content, initiate external requests, or expose spreadsheet data.

...[truncated 456 chars]

Remediation
View remediation

Remediation Suggestions

  • Sanitize every string cell before writing CSV.
  • Detect formula prefixes after accounting for leading spaces, tabs, and carriage returns.
  • Prefix dangerous values with an apostrophe or another spreadsheet-safe neutralization character:
    python
    def safe_csv_cell(value):
        if not isinstance(value, str):
            return value
        probe = value.lstrip(" \t\r")
        if probe.startswith(("=", "+", "-", "@")):
            return "'" + value
        return value
    
  • Apply the sanitizer to every exported row before calling writer.writerow.
  • Document whether CSV output is intended for spreadsheet import or strict machine interchange, as apostrophe-based escaping changes the represented value.
  • Consider offering separate csv-safe and raw machine-readable export modes.
  • Add tests covering formula prefixes, leading whitespace, tabs, carriage returns, delimiters, embedded quotes, and multiline values.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill advertises shell-based setup and local file/database operations but does not declare any explicit tool scope such as allowed tools or permissions. That mismatch can cause an agent framework to grant broader execution capabilities than users expect, increasing the risk of unintended shell execution, file writes, or environment access during normal use.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger list includes broad, everyday phrases such as 'timesheet', 'track time', and 'log hours', which can cause the skill to activate in situations where a user is speaking generally rather than intending tool execution. In an agent ecosystem, overbroad invocation raises the chance of unintended actions like starting timers, modifying records, or exposing billing data in the wrong context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code file defines destructive operations that delete persisted data: cancel_timer() deletes the active timer row and delete_entry() removes stored entry records. There is no confirmation prompt, user-facing log/print, or explanatory warning comment/docstring near these operations, so callers receive no disclosure that stored tracking data will be permanently removed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
79% confidence
Finding

export_entries() exports full entry records, which may include client names, notes, tags, timestamps, and billing information, into JSON or CSV. The code provides no warning, confirmation, or explanatory comment that potentially sensitive business data is being bulk exported.

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 46)May include surrounding context.

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

# --- Database init ---

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The command list includes destructive operations like 'delete' and state-altering operations like 'edit' and 'cancel', but the surrounding description does not prominently warn users that records can be removed or modified. This increases the risk of accidental data loss, especially if the skill is invoked through natural language and users do not realize a request may map to a destructive command.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The export command constructs an output path from user input and writes exported entries to disk. Although it prints the destination after writing, there is no prior warning in comments, help text, or confirmation that this operation will persist potentially sensitive client, billing, and work-log data to a file.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.