Back to skill

Security audit

Opencron Skill Repo

Security checks for vulnerabilities and agentic risk

Overview

OpenCron is a real cron dashboard, but it exposes sensitive cron data through unauthenticated web pages and mutable remote code paths that users should review carefully before installing.

Install only if you are comfortable with cron job names, schedules, prompts, run history, errors, and related metadata being embedded into dashboard files or served by an unauthenticated local web server. Prefer reviewing the code, binding the server to localhost only, adding authentication, removing automatic post-run startup/link behavior, and pinning or vendoring the dashboard HTML before use.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (6)

T03 · Remote Payload Retrieval and Execution

Error
Location
serve.py:18
Finding

Mutable Remote Dashboard Code Executes Alongside Sensitive Cron Data

Content
View full analysis
" "window.__OPENCRON_DATA=" + json.dumps(jobs) + ";" "window.__OPENCRON_RUNS=" + json.dumps(runs) + ";" "" ) return template.replace("", inject + "") ``` Equivalent remote-fetch and injection behavior is implemented in `update_canvas.py`. ### Technical Analysis The dashboard template is downloaded from the mutable `master` branch and is neither pinned to an immutable commit nor validated with a cryptographic hash or signature. Because an HTML template can contain JavaScript, this mechanism allows the effective executable payload to change after the Skill has been reviewed or installed. The Skill then injects sensitive local cron definitions and run-history records into global JavaScript variables in that remotely supplied document. Consequently, any JavaScript added to the upstream template can access job prompts, descriptions, schedules, run summaries, errors, model information, token usage, and delivery metadata. Caching does not establish trust or integrity. It only preserves whichever remote payload was retrieved first. ### Attack Path 1. An attacker compromises the upstream repository, maintainer account, DNS/ne ...[truncated 915 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
serve.py:91
Finding

Unauthenticated Dashboard Exposes Cron Prompts and Run History on All Interfaces

Content
View full analysis
" "window.__OPENCRON_DATA=" + json.dumps(jobs) + ";" "window.__OPENCRON_RUNS=" + json.dumps(runs) + ";" "" ) return template.replace("", inject + "") ``` ```python class Handler(BaseHTTPRequestHandler): def do_GET(self): if self.path in ("/", "/index.html", "/cron.html"): self._serve_html() else: self.send_error(404) def _serve_html(self): html = render_page().encode("utf-8") self.send_response(200) self.send_header("Content-Type", "text/html; charset=utf-8") self.send_header("Content-Length", str(len(html))) self.end_headers() self.wfile.write(html) ``` ```python server = HTTPServer(("0.0.0.0", args.port), Handler) server.serve_forever() ``` The declared setup explicitly states that there is no authentication and that port `18790` is an exposed bridge port. ### Technical Analysis The HTTP server binds to `0.0.0.0`, making it reachable through every network interface available to the environment. The request handler performs no authentication, authorization, origin validation, or client restriction. Every successful dashboard request causes the server to read local cron definitions and run-history files and return them inside the HTML. These records may contain operational prompts, internal service names, communication-channel names, execution output, error messages, and usage metadata. Binding to all interfaces is not necessary for a dashboard documented with a `localhost` URL. This ...[truncated 882 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
update_canvas.py:57
Finding

Sensitive Cron Data Is Persisted in Predictable Static Web Locations

Content
View full analysis
" "window.__OPENCRON_DATA=" + json.dumps(jobs) + ";" "window.__OPENCRON_RUNS=" + json.dumps(runs) + ";" "" ) return template.replace("", inject + "") def deploy(html): """Write HTML to gateway UI dir and canvas dir.""" if UI_DIR.exists(): (UI_DIR / "cron.html").write_text(html, encoding="utf-8") CANVAS_DIR.mkdir(parents=True, exist_ok=True) (CANVAS_DIR / "cron.html").write_text(html, encoding="utf-8") (CANVAS_DIR / "cron-data.json").write_text(json.dumps(read_jobs())) ``` ### Technical Analysis The deployment process writes cron definitions and run history into `cron.html` under gateway and canvas directories. It also creates a separate plaintext `cron-data.json` containing job definitions. Static web roots generally lack record-level authorization and serve files by predictable paths. The standalone JSON file duplicates sensitive data without being needed by the documented embedded-data dashboard. No restrictive file mode, access-control verification, retention policy, or redaction is applied. The optional watcher repeats this deployment every 30 seconds, keeping exposed copies current and continually restoring them if they are removed while the watcher remains active. ### Attack Path 1. A user runs `update_canvas.py` or starts `watch_sync.sh`. 2. The script reads local cron definitions and run-history files. 3. It writes the records into static files at predictable locations. 4. The gateway or canvas server makes one or more of those locations w ...[truncated 557 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
serve.py:68
Finding

Unsafe JSON Embedding Enables Stored Script Injection

Content
View full analysis
" "window.__OPENCRON_DATA=" + json.dumps(jobs) + ";" "window.__OPENCRON_RUNS=" + json.dumps(runs) + ";" "" ) return template.replace("", inject + "") ``` The standalone generator uses the same unsafe pattern: ```python html = TEMPLATE_PATH.read_text() # Inject data as window.__CRON_DATA__ for offline use inject = f"" html = html.replace("", f"{inject}\n") ``` ### Technical Analysis `json.dumps()` produces valid JSON but does not make the result safe for direct insertion into an HTML `` sequence terminates the script element even when it appears inside a JavaScript string. If an attacker can influence a job name, description, payload message, error, summary, or another serialized string, a value such as the following can break out of the data block: ```html ``` The browser processes the closing tag at the HTML-parser level, after which the injected script executes. Rendering later values with `textContent` does not mitigate this earlier injection because exploitation occurs while parsing the initial generated page. ### Attack Path 1. An attacker or compromised integration places a script-closing payload in a cron definition or run-history field. 2. `serve.py`, `update_canvas.py`, or `generate.py` reads that field. 3. `json.dumps()` serializes it without escaping HTML-significant `<` characters. 4. The serialized value is concatenated directly into a `
Remediation
View remediation
` elements. 2. Store serialized data in a non-executable element such as: ```html ``` 3. Before embedding, escape at least `<`, `>`, `&`, U+2028, and U+2029 using a serialization routine designed for HTML contexts. 4. Parse the element's text content with `JSON.parse()` rather than evaluating generated JavaScript. 5. Prefer an authenticated JSON endpoint where feasible. 6. Deploy a restrictive Content Security Policy without `unsafe-inline`. 7. Add regression tests containing ``, HTML tags, ampersands, Unicode separators, and quotation marks in every user-controlled field. 8. Apply the fix consistently in `serve.py`, `update_canvas.py`, and `generate.py`. ]]>

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:27
Finding

Skill Instructions Mandate Persistent Promotional Modification of Agent Output

Content
View full analysis
Remediation
View remediation

T03 · Remote Payload Retrieval and Execution

Error
Location
bin/install.js:7
Finding

Installer Clones an Unpinned Repository and Immediately Executes Downloaded Code

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • 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 (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill presents itself as a dashboard but instructs running a network-accessible server that reads local cron job and run-history files, embeds them into pages, and serves them without authentication. In context, this makes the skill more dangerous because OpenClaw containers already expose the bridge port, so sensitive operational metadata may become reachable to other local or adjacent actors.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill presents itself as a dashboard but instructs running a network-accessible server that reads local cron job and run-history files, embeds them into pages, and serves them without authentication. In context, this makes the skill more dangerous because OpenClaw containers already expose the bridge port, so sensitive operational metadata may become reachable to other local or adjacent actors.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

The README instructs users to run npx clawhub add opencron without pinning a specific package version. This creates a supply-chain risk because a future compromised or malicious package release could be fetched and executed implicitly at install time. In a skill-installation context, this is more dangerous because users are likely to copy-paste the command and execute it with trust.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README explicitly describes a dashboard served on an exposed bridge port with 'no auth' and says it reads cron job definitions and run history from disk. Even if described as localhost access, the skill context notes the port is already exposed by the container, so sensitive operational metadata may be accessible to unintended parties without authentication or warning. This materially increases risk because the dashboard aggregates job names, schedules, and execution history in one place.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill describes capabilities that read local cron data, serve HTTP, and fetch remote content, but it declares no explicit tool scope or permissions. This is dangerous because it hides the real trust boundary from users and reviewers, increasing the chance that network and filesystem access are granted implicitly without informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The instructions tell users to launch a background server that serves cron job data and explicitly note there is no authentication, but they provide no warning about exposure risk. This is dangerous because users may unintentionally publish job names, schedules, arguments, and run history to any party that can reach the exposed port.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The installer clones a remote GitHub repository into the local environment and then executes a local Python script from that freshly fetched content. That creates a direct remote-code-execution and supply-chain trust boundary: if the repository, branch tip, or transit path is compromised, arbitrary code can run on the user's machine during installation, which is more dangerous than expected for a supposedly visual dashboard skill.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script reads cron job data from a user-specific file in the home directory and injects it directly into a standalone HTML page. Even though the embedding uses JSON encoding rather than raw string concatenation, the generated artifact can expose potentially sensitive operational metadata such as job names, schedules, commands, run history, or error details to anyone who receives or serves the HTML file, and the code provides no warning, consent prompt, or redaction step.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file explicitly states there is no auth and that the service runs on a port exposed by every container, and the code later binds to 0.0.0.0. That makes cron job metadata and run history accessible to any reachable network peer, which is broader exposure than necessary for a dashboard and can leak operational details or sensitive command/output data.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The server downloads executable HTML from a remote GitHub URL at runtime and serves it directly, creating a supply-chain and remote content injection risk. If the upstream file, repository, transport trust boundary, or account is compromised, arbitrary JavaScript can execute in clients and access the embedded local cron job and run-history data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The server listens on all interfaces and returns a page containing embedded local job and run data with no authentication or warning. In the context of a cron dashboard, those records may reveal internal schedules, commands, file paths, tokens in arguments, or job output, which materially increases the risk of information disclosure.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script downloads HTML from a remote GitHub URL at deploy time and then serves it as local UI content. Because HTML can contain executable JavaScript, this creates a supply-chain risk where a compromised upstream repository, account, or network path could inject active code into the OpenClaw UI and access embedded cron/job data in the browser context.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The network access itself is not necessarily malicious, but here it is used to retrieve content that is later trusted and deployed into a served interface. In the context of a cron dashboard, runtime dependency on GitHub is unnecessary and increases the attack surface by introducing external availability and content-trust risks.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 13)May include surrounding context.

md
#!/bin/sh
# Regenerate the embedded dashboard HTML every 30 seconds.
# This re-reads jobs.json and run history and writes fresh HTML.
# Run as: nohup sh skills/opencron/watch_sync.sh &
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
while true; do
    python3 "$SCRIPT_DIR/update_canvas.py" --sync 2>/dev/null

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
#!/bin/sh
# Regenerate the embedded dashboard HTML every 30 seconds.
# This re-reads jobs.json and run history and writes fresh HTML.
# Run as: nohup sh skills/opencron/watch_sync.sh &
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
while true; do
    python3 "$SCRIPT_DIR/update_canvas.py" --sync 2>/dev/null

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
#!/bin/sh
# Regenerate the embedded dashboard HTML every 30 seconds.
# This re-reads jobs.json and run history and writes fresh HTML.
# Run as: nohup sh skills/opencron/watch_sync.sh &
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
while true; do
    python3 "$SCRIPT_DIR/update_canvas.py" --sync 2>/dev/null

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · bin/install.js (reported line 39)May include surrounding context.

js
#!/bin/sh
# Regenerate the embedded dashboard HTML every 30 seconds.
# This re-reads jobs.json and run history and writes fresh HTML.
# Run as: nohup sh skills/opencron/watch_sync.sh &
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
while true; do
    python3 "$SCRIPT_DIR/update_canvas.py" --sync 2>/dev/null

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · watch_sync.sh (reported line 4)May include surrounding context.

sh
#!/bin/sh
# Regenerate the embedded dashboard HTML every 30 seconds.
# This re-reads jobs.json and run history and writes fresh HTML.
# Run as: nohup sh skills/opencron/watch_sync.sh &
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
while true; do
    python3 "$SCRIPT_DIR/update_canvas.py" --sync 2>/dev/null

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The installer depends on external tools (git and python3) and uses them to fetch and execute additional content, expanding the attack surface and introducing undeclared trust in the user's PATH and local toolchain. For a dashboard-oriented skill, this behavior is not minimal and increases the chance of unexpected code execution or environment-specific abuse.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file repeatedly forces the 'en-GB' locale for date and time rendering, and the document language is also set to English. This imposes a specific language/locale choice in the UI without offering opt-in, fallback, or documenting why that locale is required.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The skill downloads HTML from GitHub and caches it locally, which is a network operation and writes to disk. Although the function docstring says it downloads and caches the template, there is no runtime log or warning informing the user that an outbound network request will occur when the cache is missing.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.