Skip to content

fix(security): scan SKILL.md text in skill code-safety audit#109363

Merged
steipete merged 1 commit into
mainfrom
fix/skill-md-security-scan
Jul 17, 2026
Merged

fix(security): scan SKILL.md text in skill code-safety audit#109363
steipete merged 1 commit into
mainfrom
fix/skill-md-security-scan

Conversation

@steipete

Copy link
Copy Markdown
Contributor

What Problem This Solves

openclaw security audit --deep never scanned a skill's SKILL.md. A malicious workspace SKILL.md containing pipe-to-shell install patterns (curl … | bash), rm -rf ~/, secret-exfiltration, or prompt-injection produced zero audit findings — while the identical patterns placed in a sibling tool.js were immediately flagged skills.code_safety critical. Since SKILL.md is the primary (often only) file a skill ships, and manually-authored workspace skills are never scanned at install time, malicious skill text was invisible to the audit.

Why This Change Was Made

The scanner already has rules written for skill text (shell-pipe-to-shell = "Skill text includes pipe-to-shell install pattern", secret-exfiltration, prompt-injection-*), and the Workshop proposal path scans PROPOSAL.md markdown. But the installed/workspace-skill audit (collectInstalledSkillsCodeSafetyFindings) only fed SCANNABLE_EXTENSIONS (JS/TS) to the scanner, skipping the markdown.

Fix: each audited skill's SKILL.md content is now scanned through scanSkillContent + scanSource (the same scanners the Workshop uses), merged into the code-safety summary. Scoped to the skills audit path — the global directory scanner's extension set is unchanged, so READMEs/docs elsewhere are not newly scanned (no false-positive flood).

User Impact

security audit --deep now flags dangerous instructions in skill SKILL.md files (pipe-to-shell, prompt-injection, exfiltration), closing a security blind spot for manually-authored/workspace skills. No change to non-skill scanning.

Evidence

  • Regression test audit-extra.async.test.ts "scans SKILL.md text for dangerous skill instructions": red before ("expected skill markdown code-safety finding"), green after. 7 tests pass.
  • node scripts/check-changed.mjs green on Testbox; oxfmt --check, git diff --check clean.
  • Autoreview: clean, no accepted/actionable findings.

@steipete
steipete requested a review from a team as a code owner July 16, 2026 21:41
@openclaw-barnacle openclaw-barnacle Bot added size: S maintainer Maintainer-authored PR labels Jul 16, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7825336023

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +909 to 912
const summary = await getSkillCodeSafetySummary({
dirPath: skillDir,
skillFilePath: entry.skill.filePath,
summaryCache: params.summaryCache,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Scan plugin-provided skill markdown too

When a plugin declares skills, loadWorkspaceSkillEntries can expose SKILL.md files rooted under the installed plugin directory, but this collector skips those directories earlier because they are under stateDir/extensions. This new SKILL.md scan is therefore only reached for non-plugin skills; the plugin path still goes through collectPluginsCodeSafetyFindingsscanDirectoryWithSummary, whose scannable extensions exclude .md, so a malicious extensions/<plugin>/skills/.../SKILL.md with the same pipe-to-shell or prompt-injection text remains invisible to security audit --deep.

Useful? React with 👍 / 👎.

@steipete
steipete force-pushed the fix/skill-md-security-scan branch 3 times, most recently from 801c60c to 12ac206 Compare July 16, 2026 23:38
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 17, 2026
@clawsweeper

clawsweeper Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 17, 2026, 12:33 AM ET / 04:33 UTC.

Summary
The PR scans each audited skill’s SKILL.md through the existing skill-text and source scanners and adds regression coverage for dangerous and clean workspace skills.

PR surface: Source +30, Tests +49. Total +79 across 2 files.

Reproducibility: yes. from source inspection: workspace skills reach the new helper, while plugin-rooted skills are skipped and remain under a directory scanner that excludes Markdown. A live CLI transcript has not been supplied.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: src/security/audit-extra.async.test.ts, serialized state: src/security/audit-extra.async.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Cover dangerous and clean plugin-provided SKILL.md files in the implementation and regression tests.
  • Post redacted live deep-audit terminal output demonstrating workspace and plugin-provided behavior.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR supplies tests and CI/Testbox checks but no redacted after-fix live openclaw security audit --deep output. Add terminal evidence for dangerous and clean workspace and plugin-provided skills, update the PR body to retrigger review, or ask a maintainer to comment @clawsweeper re-review; redact private paths, endpoints, credentials, and other sensitive data.

Next step before merge

  • [P1] The contributor should resolve the existing plugin-skill finding and add real CLI proof; the protected maintainer label keeps repair and merge handling human-only.

Security
Needs attention: The hardening is directionally sound, but its security coverage remains incomplete for plugin-provided skills.

Review findings

  • [P2] Scan plugin-provided skill Markdown too — src/security/audit-extra.async.ts:909-912
Review details

Best possible solution:

Use one skill-Markdown audit path for every discovered non-bundled skill, including skills rooted under installed plugins, with dangerous and clean regression cases for both workspace and plugin sources.

Do we have a high-confidence way to reproduce the issue?

Yes, from source inspection: workspace skills reach the new helper, while plugin-rooted skills are skipped and remain under a directory scanner that excludes Markdown. A live CLI transcript has not been supplied.

Is this the best way to solve the issue?

No, not yet. Reusing the existing scanners is appropriate, but the narrowest complete fix must also cover the sibling plugin-provided skill path and prove that path with a regression test.

Full review comments:

  • [P2] Scan plugin-provided skill Markdown too — src/security/audit-extra.async.ts:909-912
    This call remains inside the branch that skips skills under stateDir/extensions. Those skills are left to the plugin directory scanner, whose extension allowlist excludes .md, so an installed plugin can still carry the same malicious SKILL.md without a deep-audit finding. Route plugin-provided skill files through the text scanner and add a plugin-path regression case.
    Confidence: 0.99

Overall correctness: patch is incorrect
Overall confidence: 0.98

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against e3618454f245.

Label changes

Label justifications:

  • P2: This is a bounded security-audit correctness fix with incomplete supported-source coverage, but no demonstrated emergency runtime compromise.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR supplies tests and CI/Testbox checks but no redacted after-fix live openclaw security audit --deep output. Add terminal evidence for dangerous and clean workspace and plugin-provided skills, update the PR body to retrigger review, or ask a maintainer to comment @clawsweeper re-review; redact private paths, endpoints, credentials, and other sensitive data.
Evidence reviewed

PR surface:

Source +30, Tests +49. Total +79 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 31 1 +30
Tests 1 49 0 +49
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 80 1 +79

Security concerns:

  • [medium] Plugin skill Markdown remains outside the audit — src/security/audit-extra.async.ts:909
    The installed-skill collector skips plugin-rooted skills, while the plugin directory scanner does not scan Markdown, preserving the reported blind spot for that supported source class.
    Confidence: 0.99

What I checked:

  • Workspace-only implementation path: The new helper is called inside the installed-skill collector after its existing plugin-directory exclusion, so it only adds Markdown scanning for non-plugin skills. (src/security/audit-extra.async.ts:909, badb34ba1e68)
  • Plugin Markdown remains excluded: Plugin directories continue through collectPluginsCodeSafetyFindings and the generic directory scanner, whose extension allowlist contains JavaScript and TypeScript variants but not .md. (src/security/skill-scanner.ts:39, e3618454f245)
  • Regression coverage omits plugin skills: The added test creates only a workspace skills/evil-skill/SKILL.md; it proves dangerous and clean workspace cases but does not exercise a plugin-provided skill. (src/security/audit-extra.async.test.ts:152, badb34ba1e68)
  • Prior finding remains applicable: The earlier review identified the plugin-provided skill gap, and the latest two-file diff still contains no plugin audit-path change or plugin-skill regression case. (src/security/audit-extra.async.ts:909, badb34ba1e68)
  • Scanner provenance: The skill/plugin code-safety scanner dates to commit bc88e58fcfa0b2b317af8f2af35ccedca704aa69; later cache and containment work was carried by steipete in 2f352306fe083295035d1d92aa7b77c3f46070b1 and c8bdefd8b40ac9427e31b4cebd3d0422b2ebac60. (src/security/skill-scanner.ts:39, bc88e58fcfa0)
  • Proof remains test-only: The PR body reports a focused regression test, Testbox checks, formatting, and autoreview, but no after-fix terminal output from a real openclaw security audit --deep run. (badb34ba1e68)

Likely related people:

  • steipete: Recent merged history includes scanner cache and path-containment refactors, making this the strongest current routing signal for the security scanner area. (role: recent area contributor; confidence: high; commits: 2f352306fe08, c8bdefd8b40a; files: src/security/skill-scanner.ts, src/security/audit-extra.async.ts)
  • thebenignhacker: Repository history credits this account among the authors of the original skill/plugin code-safety scanner implementation. (role: introduced behavior; confidence: medium; commits: bc88e58fcfa0; files: src/security/skill-scanner.ts)
  • dvrshil: Repository history credits this account among the authors of the original skill/plugin code-safety scanner implementation. (role: introduced behavior; confidence: medium; commits: bc88e58fcfa0; files: src/security/skill-scanner.ts)
  • grp06: Repository history credits this account among the authors of the original skill/plugin code-safety scanner implementation. (role: introduced behavior; confidence: medium; commits: bc88e58fcfa0; files: src/security/skill-scanner.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (2 earlier review cycles)
  • reviewed 2026-07-16T23:58:03.946Z sha 12ac206 :: needs real behavior proof before merge. :: [P2] Scan plugin-provided skill Markdown too
  • reviewed 2026-07-17T02:34:49.325Z sha 5f8dbd6 :: needs real behavior proof before merge. :: [P2] Scan plugin-provided skill Markdown too

@steipete
steipete force-pushed the fix/skill-md-security-scan branch from 12ac206 to 5f8dbd6 Compare July 17, 2026 02:29
@steipete

Copy link
Copy Markdown
Contributor Author

/allow-security-sensitive-change 5f8dbd6

@steipete

Copy link
Copy Markdown
Contributor Author

/allow-dependencies-change 5f8dbd6

@steipete steipete self-assigned this Jul 17, 2026
`security audit --deep` fed only JS/TS files (SCANNABLE_EXTENSIONS) to the skill
scanner, so a malicious workspace SKILL.md (pipe-to-shell, prompt-injection,
secret-exfiltration) produced zero findings while the same patterns in a
sibling tool.js were flagged critical. The scanner already has skill-text rules
and the Workshop path scans PROPOSAL.md markdown — the installed/workspace-skill
audit just skipped the markdown.

Scan each audited skill's SKILL.md content through scanSkillContent + scanSource
(the same scanners the Workshop uses), scoped to the skills audit path so the
global directory scanner is unchanged (no README/doc false positives).
@steipete
steipete force-pushed the fix/skill-md-security-scan branch from 5f8dbd6 to badb34b Compare July 17, 2026 04:28
@steipete

Copy link
Copy Markdown
Contributor Author

/allow-security-sensitive-change 5f8dbd6

@steipete

Copy link
Copy Markdown
Contributor Author

/allow-dependencies-change 5f8dbd6

@steipete
steipete merged commit c2cc95b into main Jul 17, 2026
120 checks passed
@steipete
steipete deleted the fix/skill-md-security-scan branch July 17, 2026 04:37
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 17, 2026
…w#109363)

`security audit --deep` fed only JS/TS files (SCANNABLE_EXTENSIONS) to the skill
scanner, so a malicious workspace SKILL.md (pipe-to-shell, prompt-injection,
secret-exfiltration) produced zero findings while the same patterns in a
sibling tool.js were flagged critical. The scanner already has skill-text rules
and the Workshop path scans PROPOSAL.md markdown — the installed/workspace-skill
audit just skipped the markdown.

Scan each audited skill's SKILL.md content through scanSkillContent + scanSource
(the same scanners the Workshop uses), scoped to the skills audit path so the
global directory scanner is unchanged (no README/doc false positives).
steipete added a commit that referenced this pull request Jul 18, 2026
#101773 removed the node:fs/promises import while switching plugin manifest
reads to fs-safe helpers, but getSkillCodeSafetySummary (added later by
#109363) still reads SKILL.md via fs.readFile. Main has been red since the
merge (check-prod-types, check-lint, check-test-types, package-boundary
compile, compact-large-5). Restore the import; skill-file reads keep their
pre-existing unbounded contract.
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 19, 2026
openclaw#101773 removed the node:fs/promises import while switching plugin manifest
reads to fs-safe helpers, but getSkillCodeSafetySummary (added later by
openclaw#109363) still reads SKILL.md via fs.readFile. Main has been red since the
merge (check-prod-types, check-lint, check-test-types, package-boundary
compile, compact-large-5). Restore the import; skill-file reads keep their
pre-existing unbounded contract.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer Maintainer-authored PR P2 Normal backlog priority with limited blast radius. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant