Back to skill

Security audit

Late Brake

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its racing lap-analysis purpose, but its local cache and track writes are not safely contained and could overwrite other writable files if paths are tampered with.

Install only if you are comfortable with the skill creating local cache files next to telemetry files and storing custom tracks under ~/.late-brake/tracks. Avoid running it on files in shared or attacker-writable directories until the cache and track writes are hardened against symlinks and accidental overwrites.

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
scripts/late_brake/io/cache.py:16
Finding

Symlink-Following Telemetry Cache Write Allows Arbitrary Writable-File Corruption

Content
View full analysis

Vulnerability Details

File Location: scripts/late_brake/io/cache.py:16-40
Vulnerability Type: Predictable file write without symbolic-link protection
Risk Level: Medium

Vulnerable Code

python
def cache_file_path(source_file: str) -> str:
    """Generate cache file path."""
    source_file_norm = os.path.normpath(source_file)
    dirname = os.path.dirname(source_file_norm)
    basename = os.path.basename(source_file_norm)
    cache_basename = f".{basename}.lb.json"
    cache_path = os.path.join(dirname, cache_basename)
    cache_path = os.path.normpath(cache_path)
    # After normalization, verify cache is still within the normalized source directory
    # This prevents traversal even if original source_file contained ../ tricks
    source_dir_norm = os.path.normpath(dirname) + os.sep
    if not cache_path.startswith(source_dir_norm):
        raise ValueError(f"Cache path generation failed: {source_file}")
    return cache_path


def save_cached_laps(source_file: str, laps: List[Lap], track_id: str) -> None:
    """Save parsed and split lap data to the cache."""
    cache_path = cache_file_path(source_file)
    data = {
        "source_file": source_file,
        "track_id": track_id,
        "laps": [lap.model_dump() for lap in laps]
    }
    with open(cache_path, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2, ensure_ascii=False)

Technical Analysis

The cache filename is predictable: a source named session.vbo produces .session.vbo.lb.json in the same directory. The lexical path-prefix check prevents ordinary ../ traversal, but it does not inspect the destination with lstat, reject symbolic links, or open the file with O_NOFOLLOW.

Python's open(path, "w") follows an existing symbolic link and truncates its target. Consequently, an attacker who can create the predictable cache path can redirect the generated JSON write to another ...[truncated 1494 chars]

Remediation
View remediation

Remediation Suggestions

  1. Reject symbolic-link destinations using os.lstat before writing.
  2. Open newly created files with os.open and flags such as O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, where supported.
  3. Write to a securely created temporary file in the same trusted directory, flush and synchronize it, and publish it with os.replace.
  4. Apply restrictive cache permissions, such as 0o600.
  5. Validate each relevant path component and reject symlinked parent directories when processing files from attacker-writable locations.
  6. Consider placing caches in a private application-owned directory instead of beside untrusted telemetry files. Derive cache keys from a canonical source path and metadata.
  7. Validate cached source_file, track_id, and lap structure before use. Consider binding the cache to the source using a content hash rather than modification time alone.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/late_brake/io/track_store.py:202
Finding

Symlink-Following Custom Track Write Allows Arbitrary Writable-File Corruption

Content
View full analysis

Vulnerability Details

File Location: scripts/late_brake/io/track_store.py:202-224
Vulnerability Type: Predictable file overwrite without symbolic-link protection
Risk Level: Medium

Vulnerable Code

python
def add_track_from_file(source_path: str) -> Tuple[bool, str, Optional[Track]]:
    """Add or update a custom user track."""
    valid, err_msg, track = validate_track_file(source_path)
    if not valid or track is None:
        return False, err_msg, None  # type: ignore

    # Validate track.id against allowed pattern
    if not TRACK_ID_PATTERN.fullmatch(track.id):
        return False, f"Invalid track ID '{track.id}'", None

    user_dir = get_user_track_dir()
    os.makedirs(user_dir, exist_ok=True)

    dest_path = os.path.join(user_dir, f"{track.id}.json")
    # Normalize and verify path is still within user track directory
    dest_path = os.path.normpath(dest_path)
    if not dest_path.startswith(os.path.normpath(user_dir) + os.sep):
        return False, f"Track ID '{track.id}' generated an invalid path", None

    with open(dest_path, "w", encoding="utf-8") as f:
        json.dump(track.model_dump(), f, indent=2, ensure_ascii=False)

Technical Analysis

Restricting the track ID to alphanumeric characters, underscores, and hyphens prevents direct path traversal. However, the destination remains predictable as ~/.late-brake/tracks/TRACK_ID.json.

The implementation performs only lexical normalization and containment validation. It does not verify that the destination is a regular file, reject an existing symbolic link, or use a no-follow file-opening primitive. If the predictable destination is a symlink, open(dest_path, "w") follows it and truncates the linked target.

This issue requires an attacker to have sufficient local access to create an entry inside ~/.late-brake/tracks, or to control a symlinked application directory. Under that precondition, invoki ...[truncated 1281 chars]

Remediation
View remediation

Remediation Suggestions

  1. Ensure ~/.late-brake and ~/.late-brake/tracks are owned by the current user and are not writable by group or other users.
  2. Create application directories with restrictive permissions, such as 0o700, and verify their ownership and file type before use.
  3. Reject symbolic links using os.lstat for the destination and relevant parent components.
  4. Use os.open with O_NOFOLLOW; for new tracks, combine it with O_CREAT | O_EXCL.
  5. For updates, write to a securely created temporary regular file in the verified track directory and atomically replace the destination with os.replace.
  6. Set stored track files to restrictive permissions such as 0o600.
  7. Revalidate the directory immediately before the final replacement to reduce time-of-check/time-of-use exposure.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (29)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Reading built-in and user track definitions and writing JSON into ~/.late-brake/tracks introduces persistent filesystem interaction that is not clearly disclosed by the high-level description. Hidden persistence is risky in agent workflows because it can alter future runs, overwrite user-maintained data, or create an unexpected storage channel on the host.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Reading built-in and user track definitions and writing JSON into ~/.late-brake/tracks introduces persistent filesystem interaction that is not clearly disclosed by the high-level description. Hidden persistence is risky in agent workflows because it can alter future runs, overwrite user-maintained data, or create an unexpected storage channel on the host.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Reading built-in and user track definitions and writing JSON into ~/.late-brake/tracks introduces persistent filesystem interaction that is not clearly disclosed by the high-level description. Hidden persistence is risky in agent workflows because it can alter future runs, overwrite user-maintained data, or create an unexpected storage channel on the host.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Reading built-in and user track definitions and writing JSON into ~/.late-brake/tracks introduces persistent filesystem interaction that is not clearly disclosed by the high-level description. Hidden persistence is risky in agent workflows because it can alter future runs, overwrite user-maintained data, or create an unexpected storage channel on the host.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill advertises direct Python import and CLI execution but declares no explicit tool scope or permission boundaries, despite functionality that reads input files and writes user track data. In an agent environment, missing scope declarations can cause the runtime or user to underestimate filesystem access, increasing the chance of unintended file read/write operations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code presents natural-language descriptions, help text, errors, and status messages in Chinese throughout the CLI. The policy explicitly flags language or locale constraints when a skill forces a specific language without user opt-in, and there is no indication here that the tool is region-specific or that users can select another language.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes a pure CLI lap data analysis tool for importing lap data, splitting laps, comparing laps, and producing structured coaching output. The track add command modifies the tool's track store by adding or updating track metadata from JSON, which is a separate configuration-management capability not conveyed by the manifest description.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file contains natural-language documentation and operational messages exclusively in Chinese, including the module docstring and returned status/error strings. Under the stated policy, forcing a specific language without user opt-in is a locale/language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The module docstrings and error text are written only in Chinese, including operational descriptions and the raised ValueError message. Under the stated policy, forcing a specific language without offering user choice or documenting that the skill is intentionally Chinese-only is a locale-policy issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file-level docstring and inline descriptive text present user-facing natural-language guidance exclusively in Chinese. The policy for this category flags language/locale constraints when a skill effectively forces a specific language without opt-in or documented regional justification.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring explicitly states that $GPVTG heading information is extracted if present. In the actual code, only 'GPRMC' sentences are handled, and lines L150-L151 confirm GPVTG is not currently used. This is an active contradiction between stated behavior and implemented behavior.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest describes a pure CLI racing lap data analysis tool focused on importing lap files, splitting laps, comparing laps, and producing structured coaching output. This file implements persistent track-library management, including adding or updating user-defined track JSON files in ~/.late-brake/tracks, which is a broader configuration/content management capability than the manifest claims.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

For a skill presented as a lap data analysis and comparison CLI, reading input files is expected, but creating directories and writing JSON files into a user home-directory store is a separate persistence capability. The manifest does not mention track authoring, configuration management, or saving user assets, so this write behavior is not clearly justified by the stated purpose.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The function writes a JSON file into the user's home-directory track store, which modifies persistent user data. Although the function name implies an add/update action, this file does not include a confirmation prompt, print/log disclosure, or inline warning comment/docstring near the write operation describing that a local file will be created or overwritten.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The field description states name is the "Track English name," which imposes a specific language requirement in the format definition. This is a natural-language locale policy concern because the document does not provide an opt-in, alternative localized field requirement, or justification for forcing English here.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The cli docstring says the tool is used to compare lap data and find racing lines and braking points, implying an analysis-oriented interface. However, this file also exposes track list, track info, and especially track add administrative commands, which contradict that narrower stated intent rather than merely omitting detail.

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 docstring is written in Chinese and provides no indication that language choice is configurable or intentionally limited to a Chinese-speaking audience. Per the policy, forcing a specific language without opt-in is a natural-language locale violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The natural-language documentation and acceptance criteria are written entirely in Chinese, which imposes a specific language context without any opt-in or indication that the skill is intentionally region-specific. Under the policy rule, language constraints should either be optional for users or clearly justified.

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 manifest includes a user-visible name field set to Chinese text ("私有赛道 1") while other adjacent metadata fields are in English. Because the file provides no indication of user language choice, locale selection, or region-specific justification, it may violate the policy against forcing a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This JSON file contains the natural-language value "上海国际赛车场" as the full_name, which hard-codes a Chinese locale representation. Under the policy, locale-specific language is only acceptable when the skill offers a language choice or clearly documents a justified regional constraint, neither of which is evident in this file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The file includes both an English name and a Chinese full_name, but the presence of a fixed locale-specific naming field for the same entity can contribute to locale-forcing behavior if consumed directly without user choice. There is no accompanying indication here that the locale is user-selectable or that the Chinese naming is required for a documented region-specific purpose.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

This code writes a cache file in save_cached_laps and deletes it in remove_cached_laps, which are file-modifying operations covered by the missing-warning rule for code files. The functions have internal docstrings, but there is no confirmation prompt, logging/print, or other visible user disclosure in this file about creating hidden .lb.json files or removing them.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring and function docstring are written in Chinese, which imposes a specific language choice in user- or developer-facing natural language without offering an alternative or documenting a justified locale restriction. This matches the language/locale policy violation category because the file provides no opt-in or explanation that the skill is region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The module docstring contains user-facing natural-language guidance entirely in Chinese, including acceptance criteria and operational notes, with no indication that language choice is optional. Under the policy, forcing a specific language without opt-in can be a locale/language policy violation unless clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The primary descriptive docstring for the skill is written in Chinese and there is no indication that users may choose another language or that the locale is intentionally limited to a Chinese-speaking audience. The audit rule treats forced language or locale constraints without opt-in or clear justification as a natural-language policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.