Skip to content

fix(cron): tolerate malformed legacy jobs#71509

Merged
vincentkoc merged 1 commit intomainfrom
fix-cron-malformed-rows
Apr 25, 2026
Merged

fix(cron): tolerate malformed legacy jobs#71509
vincentkoc merged 1 commit intomainfrom
fix-cron-malformed-rows

Conversation

@vincentkoc
Copy link
Copy Markdown
Member

Summary

  • harden cron startup against loaded jobs that still have missing runtime state
  • make main-session systemEvent payload text resolution tolerate legacy payload.message and missing payload.text
  • make human-readable openclaw cron list tolerate malformed rows instead of crashing on undefined display fields

Fixes #66016.
Fixes #65916.
Fixes #64137.
Fixes #57872.
Fixes #59968.
Fixes #63813.
Fixes #52804.
Fixes #43163.

Related to #44920.

Validation

  • pnpm test src/cli/cron-cli/shared.test.ts src/cron/service/ops.regression.test.ts src/cron/service.jobs.test.ts src/cron/service.restart-catchup.test.ts src/cron/store.test.ts src/cron/service/store.load-missing-session-target.test.ts
  • OPENCLAW_LOCAL_CHECK=0 pnpm check:changed

@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes size: S maintainer Maintainer-authored PR labels Apr 25, 2026
@vincentkoc vincentkoc self-assigned this Apr 25, 2026
@vincentkoc vincentkoc marked this pull request as ready for review April 25, 2026 09:30
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot Bot commented Apr 25, 2026

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Terminal escape (ANSI/OSC) injection in cron CLI output
1. 🟡 Terminal escape (ANSI/OSC) injection in cron CLI output
Property Value
Severity Medium
CWE CWE-150
Location src/cli/cron-cli/shared.ts:291-363

Description

printCronList() prints multiple cron job fields directly to the terminal, including job.id, job.name, job.sessionTarget, job.agentId, job.payload.model, and schedule/delivery strings.

Because cron jobs are loaded from callGatewayFromCli("cron.list", ...) (i.e., remote gateway / persisted store), these string fields should be treated as untrusted. An attacker who can create/modify a cron job (or tamper with stored cron rows) can embed terminal control sequences (e.g., ANSI escape codes, OSC 8 hyperlinks, OSC 52 clipboard write) into these fields. When an operator runs cron list, the CLI will emit the sequences, enabling terminal injection/phishing.

Vulnerable flow:

  • Source: RPC response res.jobs in registerCronListCommand (gateway-controlled data)
  • Sink: runtime.log(line.trimEnd()) in printCronList() after concatenating raw fields

Vulnerable code (selected):

const idLabel = pad(job.id, CRON_ID_PAD);
const nameLabel = pad(truncate(stringifyCell(job.name), CRON_NAME_PAD), CRON_NAME_PAD);
const targetLabel = pad(job.sessionTarget ?? "-", CRON_TARGET_PAD);
...
const line = [
  colorize(rich, theme.accent, idLabel),
  colorize(rich, theme.info, nameLabel),
  ...
].join(" ");

runtime.log(line.trimEnd());

Note: the new stringifyCell() helper returns strings unchanged, and pad() now accepts unknown, which increases the likelihood that malformed/untrusted values reach the terminal without any neutralization.

Recommendation

Neutralize terminal control sequences before printing any untrusted values.

A pragmatic approach is to strip ANSI escapes and other control characters from job-controlled fields (ID/name/target/agent/model/schedule/delivery) before padding/truncation.

Example:

import stripAnsi from "strip-ansi";

const stripControl = (s: string) =>
  stripAnsi(s).replace(/[\u0000-\u001F\u007F-\u009F]/g, "");

const safeCell = (value: unknown, fallback = "-") => {
  const s = stringifyCell(value, fallback);
  return stripControl(s);
};

const pad = (value: unknown, width: number) => safeCell(value).padEnd(width);

If you want to preserve colors in your own output, only sanitize untrusted fields (not static labels) and keep applying colorize() after sanitization.


Analyzed PR: #71509 at commit 3eed107

Last updated on: 2026-04-25T09:39:56Z

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 25, 2026

Greptile Summary

This PR hardens the cron subsystem against malformed legacy jobs by: (1) initializing missing state to {} at startup in ops.ts, (2) tolerating missing/legacy payload.text and payload.message fields in normalize.ts, and (3) guarding all display-field accesses in the printCronList CLI path with null-safe operators and the new stringifyCell helper. Changes are well-targeted and backed by regression tests for each scenario.

Confidence Score: 5/5

Safe to merge — all changes are purely defensive null-guards with no behavioral changes for well-formed data.

All three fix sites correctly handle the malformed cases while leaving the happy path unchanged. Regression tests cover each scenario (missing state, legacy payload.message, malformed CLI row). No security surface is widened and no data is mutated in an unsafe way.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(cron): tolerate malformed legacy job..." | Re-trigger Greptile

@vincentkoc vincentkoc force-pushed the fix-cron-malformed-rows branch from dabfe99 to 3eed107 Compare April 25, 2026 09:34
@vincentkoc vincentkoc merged commit 2896107 into main Apr 25, 2026
65 checks passed
@vincentkoc vincentkoc deleted the fix-cron-malformed-rows branch April 25, 2026 09:39
vincentkoc added a commit that referenced this pull request Apr 25, 2026
… Unreleased

Three of my (vincentkoc) entries were missing closing PR refs, and
several maintainer-fix entries were missing credit for the user who
reported the underlying issue:

- Diagnostics/OTEL outbound delivery: add (#71471) and credit @jlapenna
  whose #70424 framed the broader tracing work.
- Cron malformed legacy jobs: add (#71509).
- OpenAI/Codex OAuth region failures: add (#71501) and credit reporter
  @wulala-xjj (#51175).
- Telegram duplicate pollers: credit reporter @Co-Messi (#56230).
- MCP/CLI one-shot retire: credit reporter @spartoviMD (#71457).
- OpenAI/Codex image baseUrl canonicalize: credit reporter @GodsBoy
  (#71460).
- Feishu TTS Ogg/Opus: credit reporters @sg1416-zg (#61249) and
  @ycjlb2023-peteryi (#37868).
- MiniMax TTS portal OAuth: credit reporter @zx15210404690-hash
  (#55017).
- MCP config reload disposal: credit reporter @xieyuanqing (#60656).
Angfr95 pushed a commit to Angfr95/openclaw that referenced this pull request Apr 25, 2026
… Unreleased

Three of my (vincentkoc) entries were missing closing PR refs, and
several maintainer-fix entries were missing credit for the user who
reported the underlying issue:

- Diagnostics/OTEL outbound delivery: add (openclaw#71471) and credit @jlapenna
  whose openclaw#70424 framed the broader tracing work.
- Cron malformed legacy jobs: add (openclaw#71509).
- OpenAI/Codex OAuth region failures: add (openclaw#71501) and credit reporter
  @wulala-xjj (openclaw#51175).
- Telegram duplicate pollers: credit reporter @Co-Messi (openclaw#56230).
- MCP/CLI one-shot retire: credit reporter @spartoviMD (openclaw#71457).
- OpenAI/Codex image baseUrl canonicalize: credit reporter @GodsBoy
  (openclaw#71460).
- Feishu TTS Ogg/Opus: credit reporters @sg1416-zg (openclaw#61249) and
  @ycjlb2023-peteryi (openclaw#37868).
- MiniMax TTS portal OAuth: credit reporter @zx15210404690-hash
  (openclaw#55017).
- MCP config reload disposal: credit reporter @xieyuanqing (openclaw#60656).
ayesha-aziz123 pushed a commit to ayesha-aziz123/openclaw that referenced this pull request Apr 26, 2026
… Unreleased

Three of my (vincentkoc) entries were missing closing PR refs, and
several maintainer-fix entries were missing credit for the user who
reported the underlying issue:

- Diagnostics/OTEL outbound delivery: add (openclaw#71471) and credit @jlapenna
  whose openclaw#70424 framed the broader tracing work.
- Cron malformed legacy jobs: add (openclaw#71509).
- OpenAI/Codex OAuth region failures: add (openclaw#71501) and credit reporter
  @wulala-xjj (openclaw#51175).
- Telegram duplicate pollers: credit reporter @Co-Messi (openclaw#56230).
- MCP/CLI one-shot retire: credit reporter @spartoviMD (openclaw#71457).
- OpenAI/Codex image baseUrl canonicalize: credit reporter @GodsBoy
  (openclaw#71460).
- Feishu TTS Ogg/Opus: credit reporters @sg1416-zg (openclaw#61249) and
  @ycjlb2023-peteryi (openclaw#37868).
- MiniMax TTS portal OAuth: credit reporter @zx15210404690-hash
  (openclaw#55017).
- MCP config reload disposal: credit reporter @xieyuanqing (openclaw#60656).
eleqtrizit pushed a commit to eleqtrizit/openclaw that referenced this pull request Apr 29, 2026
… Unreleased

Three of my (vincentkoc) entries were missing closing PR refs, and
several maintainer-fix entries were missing credit for the user who
reported the underlying issue:

- Diagnostics/OTEL outbound delivery: add (openclaw#71471) and credit @jlapenna
  whose openclaw#70424 framed the broader tracing work.
- Cron malformed legacy jobs: add (openclaw#71509).
- OpenAI/Codex OAuth region failures: add (openclaw#71501) and credit reporter
  @wulala-xjj (openclaw#51175).
- Telegram duplicate pollers: credit reporter @Co-Messi (openclaw#56230).
- MCP/CLI one-shot retire: credit reporter @spartoviMD (openclaw#71457).
- OpenAI/Codex image baseUrl canonicalize: credit reporter @GodsBoy
  (openclaw#71460).
- Feishu TTS Ogg/Opus: credit reporters @sg1416-zg (openclaw#61249) and
  @ycjlb2023-peteryi (openclaw#37868).
- MiniMax TTS portal OAuth: credit reporter @zx15210404690-hash
  (openclaw#55017).
- MCP config reload disposal: credit reporter @xieyuanqing (openclaw#60656).
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
… Unreleased

Three of my (vincentkoc) entries were missing closing PR refs, and
several maintainer-fix entries were missing credit for the user who
reported the underlying issue:

- Diagnostics/OTEL outbound delivery: add (openclaw#71471) and credit @jlapenna
  whose openclaw#70424 framed the broader tracing work.
- Cron malformed legacy jobs: add (openclaw#71509).
- OpenAI/Codex OAuth region failures: add (openclaw#71501) and credit reporter
  @wulala-xjj (openclaw#51175).
- Telegram duplicate pollers: credit reporter @Co-Messi (openclaw#56230).
- MCP/CLI one-shot retire: credit reporter @spartoviMD (openclaw#71457).
- OpenAI/Codex image baseUrl canonicalize: credit reporter @GodsBoy
  (openclaw#71460).
- Feishu TTS Ogg/Opus: credit reporters @sg1416-zg (openclaw#61249) and
  @ycjlb2023-peteryi (openclaw#37868).
- MiniMax TTS portal OAuth: credit reporter @zx15210404690-hash
  (openclaw#55017).
- MCP config reload disposal: credit reporter @xieyuanqing (openclaw#60656).
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
… Unreleased

Three of my (vincentkoc) entries were missing closing PR refs, and
several maintainer-fix entries were missing credit for the user who
reported the underlying issue:

- Diagnostics/OTEL outbound delivery: add (openclaw#71471) and credit @jlapenna
  whose openclaw#70424 framed the broader tracing work.
- Cron malformed legacy jobs: add (openclaw#71509).
- OpenAI/Codex OAuth region failures: add (openclaw#71501) and credit reporter
  @wulala-xjj (openclaw#51175).
- Telegram duplicate pollers: credit reporter @Co-Messi (openclaw#56230).
- MCP/CLI one-shot retire: credit reporter @spartoviMD (openclaw#71457).
- OpenAI/Codex image baseUrl canonicalize: credit reporter @GodsBoy
  (openclaw#71460).
- Feishu TTS Ogg/Opus: credit reporters @sg1416-zg (openclaw#61249) and
  @ycjlb2023-peteryi (openclaw#37868).
- MiniMax TTS portal OAuth: credit reporter @zx15210404690-hash
  (openclaw#55017).
- MCP config reload disposal: credit reporter @xieyuanqing (openclaw#60656).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment