Back to skill

Security audit

Cronexplain

Security checks for vulnerabilities and agentic risk

Overview

This is a small local cron-expression explainer with no persistence or data access, though malformed input can make its parser consume resources or fail.

Reasonable to install for manual cron-expression explanation. Do not expose it directly to untrusted users or automated public inputs until range and step validation is added in both duplicate script copies.

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
cronexplain.py:8
Finding

Unbounded Cron Field Expansion Allows Local Denial of Service

Content
View full analysis

Vulnerability Details

File Location: cronexplain.py:8-30 and identical copy scripts/cronexplain.py:8-30
Vulnerability Type: Unvalidated numeric ranges and steps causing resource exhaustion or process crashes
Risk Level: Medium

Vulnerable Code

python
def parse_field(field, name, min_val, max_val):
    """Parse a cron field into a set of values."""
    values = set()
    for part in field.split(","):
        if "/" in part:
            range_part, step = part.split("/", 1)
            step = int(step)
            if range_part == "*":
                start, end = min_val, max_val
            elif "-" in range_part:
                start, end = map(int, range_part.split("-", 1))
            else:
                start, end = int(range_part), max_val
            values.update(range(start, end + 1, step))
        elif "-" in part:
            start, end = map(int, part.split("-", 1))
            values.update(range(start, end + 1))
        elif part == "*":
            values.update(range(min_val, max_val + 1))
        else:
            values.add(int(part))
    return sorted(values)

Technical Analysis

parse_field() accepts numeric values, range endpoints, and step values directly from command-line input without enforcing the field-specific bounds supplied through min_val and max_val.

For example, a minute field is expected to remain between 0 and 59, but an expression such as 0-1000000000 * * * * causes the program to iterate over the entire attacker-controlled range and insert its values into a set. This can consume excessive CPU and memory until the process or host terminates it.

Step values are also not validated. A step of zero, such as */0, reaches range(..., step) and raises an uncaught ValueError. Negative steps and reversed or out-of-bounds ranges are likewise not handled through controlled validation.

Both executable copies contain th ...[truncated 1543 chars]

Remediation
View remediation

Remediation Suggestions

  • Validate every parsed value against the field-specific min_val and max_val before constructing or expanding a range.
  • Require range endpoints to be ordered and contained within the permitted field bounds.
  • Require step values to be positive integers and reject zero or negative steps.
  • Reject empty list components, malformed integers, multiple separators, and excessively long expressions with controlled error messages.
  • Avoid expanding any range until its expected size has been checked against a small fixed limit.
  • Catch ValueError and related parsing exceptions at the command-line boundary and exit with a nonzero status instead of exposing a traceback.
  • Apply the same fix to both script copies, or remove the duplicate implementation and maintain a single canonical executable.
  • Add regression tests covering huge endpoints, */0, negative steps, reversed ranges, out-of-bounds individual values, and malformed list elements.

A hardened range check should follow this pattern:

python
def validate_range(start, end, step, min_val, max_val):
    if step <= 0:
        raise ValueError("step must be a positive integer")
    if not (min_val <= start <= end <= max_val):
        raise ValueError(
            f"range must be between {min_val} and {max_val}"
        )

Validation must occur before calling range() or adding values to the set.

Vulnerability Patterns
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · SKILL.md (reported line 3)May include surrounding context.


name: cronexplain description: Explain cron expressions in plain English and calculate next run times. Use when asked to decode a crontab entry, understand a cron schedule, check when a cron job will next run, or translate between cron syntax and human-readable schedules. Supports ranges, steps, lists, and wildcards. Zero dependencies.

cronexplain 📅

Cron expression explainer with next-run calculator.

Commands

bash
# Explain a cron expression
python3 scripts/cronexplain.py "30 9 * * 1-5"
# → at minute 30; at 09:00; on Mon, Tue, Wed, Thu, Fri

# Show next N run times
python3 scripts/cronexplain.py "0 */4 * * *" -n 5

# Monthly schedule
python3 scripts/cronexplain.py "0 0 1,15 * *" -n 3

Supporte

Static analysis

No suspicious patterns detected.