Back to skill

Security audit

axiom-cron-whisperer

Security checks for vulnerabilities and agentic risk

Overview

This skill is a small local cron-expression explainer with some quality and documentation issues but no evidence of hidden access, persistence, or data misuse.

Reasonable to install for local cron explanation, but do not treat its validation as a sole production safety gate until edge-case parsing bugs and stale documentation are fixed. Expect only English/French explanations.

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

Note
Location
axiom_cron_whisperer.py:53
Finding

Malformed cron fields can bypass validation and trigger runtime exceptions

Content
View full analysis
List[int]: """ Parse a single cron field into a sorted list of values. Supports: *, N, N,M, N-M, */N """ values = set() for part in field.split(","): # Step if "/" in part: base, step = part.split("/", 1) step = int(step) if base == "*": start, end = min_val, max_val elif "-" in base: start, end = map(int, base.split("-", 1)) else: start = int(base) end = max_val for v in range(start, end + 1, step): if min_val <= v <= max_val: values.add(v) # Range elif "-" in part: start, end = map(int, part.split("-", 1)) for v in range(start, end + 1): if min_val <= v <= max_val: values.add(v) # Wildcard elif part == "*": for v in range(min_val, max_val + 1): values.add(v) # Exact value else: v = int(part) if min_val <= v <= max_val: values.add(v) else: raise ValueError(f"Valeur {v} hors limites [{min_val}-{max_val}]") return sorted(values) ``` ```python def _format_value_list(values: List[int], names: List[str] = None) -> str: """Format a list of values, using names if available.""" if names: return ", ".join(names[v] if 0 <= v < len(names) else str(v) for v in values) if len(values) == 1: return str(values[0]) if len(values) == max(values) - min(values) + 1: return f"{min(values)}-{max(values)}" return ", ".join(str(v) for v i ...[truncated 2920 chars]
Remediation
View remediation
end`. 2. Validate step values explicitly: - Require `step > 0`. - Reject zero and negative steps with `ValueError`. - Validate the base range before constructing `range()`. 3. Reject empty results before returning from `parse_field()`: ```python if not values: raise ValueError("Cron field does not contain any valid values") ``` 4. Correct the progression check in `explain_minute()` so that at least three values exist before accessing index 2: ```python if ( len(minutes) > 2 and minutes[1] - minutes[0] == minutes[2] - minutes[1] and minutes[0] == 0 ): ``` For two-value sequences, either format the values directly or implement a progression check that does not require a third element. 5. Add defensive handling in `_format_value_list()`: ```python if not values: raise ValueError("Cannot format an empty cron field") ``` 6. Add regression tests for: - Entirely out-of-range ranges. - Partially out-of-range ranges. - Descending ranges. - Zero and negative steps. - Empty list results. - Two-element minute lists such as `0,30`. - Consistency between `is_valid()` and `explain()`. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • 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 (6)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The documentation states 'English (default)' while the surrounding README is primarily in French, which can create an implicit language/locale constraint without clear user-facing policy justification. Although the CLI supports French via --lang fr, the README does not clearly frame language selection as a general user choice in the overview and instead presents English as the default behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The description states that cron syntax is translated into human language specifically as English or French, which imposes a locale restriction. Under the policy rule, language constraints should either be optional for the user or clearly justified as region-specific, and no such justification appears here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

This line explicitly limits explanations to English or French. Because the file does not explain why only those languages are supported or offer a broader user-selectable locale policy, it matches the natural-language policy violation criteria.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring states "Locale unique (français par défaut)", which asserts only one locale and specifically French as the default. In code, explain(..., lang="en") defaults to English and the CLI --lang option supports both en and fr, so the documentation actively contradicts actual behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

Line L008 says "Locale unique (français par défaut)", which communicates a locale restriction in the skill description. Although the code later exposes a language choice, this natural-language statement still indicates a single-language/default-locale policy and can conflict with the requirement to avoid forcing a specific language without clear opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The determinism test calls explain(expr) without specifying a language, while other tests explicitly pass lang="en" or lang="fr". This suggests the skill may default to a specific language, which can violate language/locale policy if users are not given a choice or the default is not clearly justified.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.