Commit Graph

453 Commits

Author SHA1 Message Date
Peter Steinberger
0dfea099d6 test: speed up focused test setup 2026-04-27 13:00:43 +01:00
Peter Steinberger
10257114ac test: speed up focused unit tests 2026-04-27 12:52:54 +01:00
Peter Steinberger
7f3f108521 refactor(config): migrate plugin config access 2026-04-27 12:35:58 +01:00
Peter Steinberger
3db407da40 test(security): cover bundled plugin allowlist audit 2026-04-27 11:50:24 +01:00
Vincent Koc
406ae72fd2 fix(logging): redact persisted transcript text 2026-04-26 12:12:44 -07:00
Shakker
0a82c819bb fix: keep status channel metadata cold 2026-04-26 09:01:39 +01:00
Shakker
2e101e8413 fix: keep channel security checks cold 2026-04-26 08:26:27 +01:00
Peter Steinberger
54f8e4145e test: speed up provider and security tests 2026-04-26 07:59:32 +01:00
Shakker
7a7728db13 fix: keep native command auto defaults cold 2026-04-26 07:55:00 +01:00
Shakker
3ea20d1413 fix: harden cold plugin metadata paths 2026-04-26 05:48:10 +01:00
Peter Steinberger
1bc9bada65 test: speed up security audit tests 2026-04-26 02:51:19 +01:00
Shakker
4e3b860e60 refactor: scope plugin capabilities to manifests 2026-04-26 02:31:02 +01:00
Shakker
babbad81a9 fix: preserve plugin install records without manifests 2026-04-26 01:03:13 +01:00
Shakker
56f4264f1b fix: keep plugin audit check ids stable 2026-04-26 01:03:12 +01:00
Shakker
c19f8a5223 refactor: consolidate plugin install index store 2026-04-26 01:03:12 +01:00
Vincent Koc
793b58b3f1 fix(plugins): add doctor registry repair 2026-04-25 12:45:43 -07:00
Vincent Koc
888448facc feat(plugins): move install records to managed ledger 2026-04-25 11:37:10 -07:00
Peter Steinberger
75fcb8c56d perf: lazy-load heavy test imports 2026-04-25 19:23:51 +01:00
Peter Steinberger
649a645492 test(core): trim sync test overhead 2026-04-25 18:41:21 +01:00
zhang-guiping
c1f423f845 fix(secrets): harden Windows ACL fallback and strip BOM (#70662)
Fail closed when Windows ACL checks cannot be verified for file and exec secret providers unless the provider explicitly opts into allowInsecurePath. Strip UTF-8 BOMs from file-backed secrets and document the trusted-path override.\n\nThanks @zhanggpcsu.
2026-04-23 19:32:15 +01:00
Peter Steinberger
7a9df89d26 test: trim skill scanner branch coverage 2026-04-23 18:51:20 +01:00
Peter Steinberger
73e247321b test: share channel audit plugin fixtures 2026-04-23 18:29:32 +01:00
Peter Steinberger
9ee800e81d test: share security audit temp fixtures 2026-04-23 18:29:32 +01:00
Peter Steinberger
4acae5b281 test: dedupe skill scanner stat mocks 2026-04-23 18:29:32 +01:00
Peter Steinberger
7a8d304a65 refactor: share core helper logic 2026-04-23 18:09:20 +01:00
Peter Steinberger
33d9e1aa83 perf(test): narrow security audit plugin scope test 2026-04-23 07:21:46 +01:00
Peter Steinberger
596b88986d chore: apply core lint cleanups 2026-04-23 05:30:49 +01:00
Peter Steinberger
d94a981a33 refactor: keep plugin login policy out of core 2026-04-22 06:39:48 +01:00
Gustavo Madeira Santana
f4478a142a Fix channel presence gating for disabled plugins (#69862)
Merged via squash.

Prepared head SHA: f76f6212b2
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 20:51:09 -04:00
Peter Steinberger
2514746b32 fix: sanitize LLM special tokens in external content 2026-04-21 20:29:02 +01:00
Gustavo Madeira Santana
24db09a19b fix(cli): keep channel status checks off plugin runtimes (#69479)
Merged via squash.

Prepared head SHA: 63f6e416a9
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 13:53:08 -04:00
Peter Steinberger
8a09b40cb2 perf(test): trim test teardown waits 2026-04-20 20:30:16 +01:00
Agustin Rivera
fe30b31a97 fix(gateway): tighten gateway config mutation guard (#69377)
* fix(gateway): tighten gateway config mutation guard

Co-authored-by: zsx <git@zsxsoft.com>

* fix(gateway): cover unkeyed guard entries

Co-authored-by: zsx <git@zsxsoft.com>

* fix(gateway): preserve array entry order in guard

Co-authored-by: zsx <git@zsxsoft.com>

* fix(gateway): close remaining review gaps

* fix(gateway): stabilize dangerous flag ids

* fix(gateway): log comment resolution

* fix(gateway): block id removal stripping protected overrides

* fix(gateway): drop review worklog

* docs(changelog): note gateway tool config mutation guard expansion (#69377)

---------

Co-authored-by: zsx <git@zsxsoft.com>
Co-authored-by: Devin Robison <drobison@nvidia.com>
2026-04-20 13:21:20 -06:00
Peter Steinberger
cf7b906216 perf: defer unconfigured gateway hooks 2026-04-20 19:47:35 +01:00
Peter Steinberger
dd409eec80 perf(test): mock audit plugin policy deps 2026-04-20 19:33:43 +01:00
Peter Steinberger
16985aba4e test: type skill scanner matrix cases 2026-04-20 19:21:24 +01:00
Peter Steinberger
ed526a2121 perf(test): merge skill scanner matrix cases 2026-04-20 19:11:45 +01:00
Peter Steinberger
305d04b758 perf(test): move temp path guard to check 2026-04-20 19:07:29 +01:00
Peter Steinberger
26c213031d perf(test): isolate gateway audit tests 2026-04-20 18:58:10 +01:00
Peter Steinberger
f43e006529 perf(test): mock plugin trust audit deps 2026-04-20 18:51:05 +01:00
Peter Steinberger
dbfc3d7104 perf(test): split plugin trust audit seam 2026-04-20 18:25:25 +01:00
Peter Steinberger
71b08988fb perf(test): narrow security audit imports 2026-04-20 18:09:13 +01:00
Peter Steinberger
642a3567b1 perf(test): mock security code safety scans 2026-04-20 18:06:32 +01:00
Peter Steinberger
f304af6b74 test(core): guard security audit boundaries 2026-04-20 17:38:20 +01:00
Peter Steinberger
a73bbe4bdd test(extensions): move channel security coverage 2026-04-20 17:38:20 +01:00
Peter Steinberger
c4358fb567 perf(test): shorten security audit hotspot tests 2026-04-20 16:22:36 +01:00
Peter Steinberger
e069169765 perf: decouple plugin facades from extension types 2026-04-18 22:06:45 +01:00
Peter Steinberger
d3eeadba94 refactor: drop private channel sdk facades 2026-04-18 19:37:15 +01:00
Peter Steinberger
678b019467 test: stabilize config and plugin scanner tests 2026-04-16 22:10:36 +01:00
Viz
f624b1d246 fix(security): 7 P1 hardening fixes — scan-paths, windows-acl, audit-extra (#67003)
* test(security): add coverage tests before security fixes

- scan-paths.ts: 100% line coverage (new test file, previously zero)
- windows-acl.ts: 100% line coverage (SID bypass, whoami throw, no-user null return)
- external-content.ts: 99% (line 248 defensive overlap guard, unreachable)
- skill-scanner.ts: 93% (lines 293-294/330/571 are defensive guards for
  future extensibility, unreachable with current rules/patterns)

200+ tests covering TOCTOU paths, cache invalidation, forced-file escapes,
dir-entry-cache hit, SID world-bypass, diacritic-strip fallback,
fullwidth homoglyph markers, and more.

* fix(security): 5 security hardening fixes in src/security/

scan-paths: default requireRealpath to false (safe). All production callers
already pass requireRealpath: true; default callers are now secure.

windows-acl: block world-equivalent SIDs (S-1-1-0 Everyone etc.) from being
added to trusted set via USERSID env var.

windows-acl: log resolveCurrentUserSid failures instead of bare catch{}.

audit-extra: wrap JSON.parse in readPluginManifestExtensions with try-catch.
Malformed package.json returns [] instead of crashing the audit.

audit-extra: depth guard in listWorkspaceSkillMarkdownFiles to prevent
resource exhaustion from deep symlink cycles.

audit-extra: 2s timeout on fs.realpath in collectWorkspaceSkillSymlinkEscapeFindings
to protect against hanging on slow/network filesystems.

audit-extra: warn about phantom entries in plugins.allow that don't match
any installed plugin (pre-approval exploitation vector).

media-understanding/types: add allowPrivateNetwork to transport overrides
(duplicate of PR #66967, required for tsgo to pass here).

* fix(security): address security review findings in audit-extra.async.ts

Issue 1 — Symlink escape audit bypass on realpath timeout:
When realpathWithTimeout returns null (timeout or failure), the previous code
called 'continue', silently skipping the escape check. An attacker with a
symlink to a slow/network filesystem could hang realpath to prevent escape
detection. Now treats unverifiable symlinks as potential escapes and includes
them in the finding.

Issue 2 — Malformed package.json hides extension entrypoints from deep scan:
readPluginManifestExtensions previously swallowed JSON.parse errors and
returned [], which a malicious plugin could exploit by crafting a malformed
package.json to hide its openclaw.extensions entrypoints from the deep code
scanner. Now re-throws the parse error (with cause) so the caller in
collectPluginsCodeSafetyFindings can surface a warn finding and alert the
user, while still scanning the plugin directory via getCodeSafetySummary.

* fix(security): address PR review findings (P1 + P2)

P1 — BFS realpath in listWorkspaceSkillMarkdownFiles lacks timeout:
Extract realpathWithTimeout to module scope so the BFS dequeue loop
uses the same 2 s guard as the outer escape-detection callers. Previously
only the per-workspace and per-skill-file realpaths had the timeout;
a hanging NFS/SMB directory entry inside the BFS could still block
indefinitely.

P1 (acknowledged limitation) — Promise.race leaves the underlying
fs.realpath call running after timeout. fs.realpath cannot be cancelled
once submitted to libuv. Callers are sequential (one await at a time),
so at most one worker thread is occupied; the OS will eventually time
out the stuck call. This is documented in the module-level JSDoc.

P2 — Phantom allowlist check incorrectly flags bundled plugin IDs:
listChannelPlugins() returns bundled channel plugin IDs (telegram,
discord, browser, etc.) that are never in stateDir/extensions.
Add bundledPluginIds exclusion so the phantom-entry finding is scoped
to user-installed extension IDs only.

P2 — Rename MAX_SYMLINK_DEPTH / depthGuard to MAX_TOTAL_DIR_VISITS /
totalDirVisits to accurately reflect that the guard caps total BFS
iterations (2_000 * 20 = 40_000), not per-path symlink depth.

* fix(security): clean up realpathWithTimeout timer and add regression tests

- Clear the timer handle when fs.realpath resolves before the deadline,
  preventing timer accumulation during large audit runs with many files.
- Add .unref() on the timer so it cannot hold the process alive while
  waiting on a potentially hanging NFS/SMB path.

Regression tests added for three audit-extra.async security fixes:
- manifest parse error: malformed plugin package.json surfaces
  plugins.code_safety.manifest_parse_error (audit-extra.async.test.ts)
- phantom allowlist with bundled exclusion: bundled channel plugin IDs
  are excluded from plugins.allow_phantom_entries warnings; non-installed
  non-bundled IDs are correctly reported (audit-plugins-phantom.test.ts)
- unverifiable realpath escape: fs.realpath failure / timeout produces a
  skills.workspace.symlink_escape finding with 'realpath timed out' in
  the detail (audit-workspace-skill-escape.test.ts)

* chore(security): add TODO for structured logger in windows-acl resolveCurrentUserSid

console.warn is acceptable short-term but may be noisy on constrained
Windows hosts; note the follow-up in-code so it is not lost.

* chore: drop unrelated formatting churn from security PR

Restores extensions/memory-lancedb/config.ts and
src/agents/pi-embedded-helpers/errors.ts to their origin/main state.
These were line-wrap-only formatting changes with no relation to the
security fixes in this branch.

* fix(security): address Codex P2 review findings

1. Normalize plugins.allow entries through normalizePluginId before
   phantom-entry filtering so that bundled plugin aliases and legacy IDs
   are correctly excluded. Without this, valid allow entries that resolve
   via alias normalization could generate false-positive phantom warnings.

2. Surface a skills.workspace.scan_truncated warn finding when the BFS
   visit cap (MAX_TOTAL_DIR_VISITS) is hit mid-traversal. Previously the
   scanner silently returned partial results, allowing escaped SKILL.md
   symlinks in the unvisited tree to go undetected.

   listWorkspaceSkillMarkdownFiles now returns {skillFilePaths, truncated}
   and collectWorkspaceSkillSymlinkEscapeFindings emits the new finding
   when truncated is true.

Regression test added for the truncation path using a mocked readdir
that fills the queue past the cap (40 001 fake entries) and a mocked
realpath for zero-I/O iteration speed.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-04-16 13:40:05 -04:00