* fix(security): stop implicit tool grants from config sections (#47487)
Configured tool sections (tools.exec, tools.fs) no longer implicitly
widen restrictive profiles (messaging, minimal). Previously, having a
tools.exec section anywhere in config — even just safety settings like
security: "allowlist" — would automatically add exec and process to the
profile's allowed tools, defeating the purpose of the restrictive
profile.
The same pattern existed in tool-fs-policy.ts where tools.fs presence
would add read/write/edit to the profile allowlist for root expansion.
Changes:
- pi-tools.policy.ts: Stop merging implicit grants into profileAlsoAllow.
Renamed resolveImplicitProfileAlsoAllow → detectImplicitProfileGrants
and use it only for a startup warning that tells users to add explicit
alsoAllow entries.
- tool-fs-policy.ts: Remove the implicit read/write/edit grant from
resolveEffectiveToolFsRootExpansionAllowed when tools.fs is present.
Root expansion now requires actual read access via profile or alsoAllow.
- Updated 4 existing tests and added 3 new regression tests.
Migration: users who relied on tools.exec or tools.fs implicitly granting
access under a restrictive profile should add explicit alsoAllow entries:
tools:
profile: "messaging"
alsoAllow: ["exec", "process"] # was implicit, now required
exec: { security: "allowlist" }
Fixes#47487
* fix: address tool policy review feedback
Wire the Control UI chat slash-command menu to the composer with stable listbox and option IDs, active-descendant updates, and a live status announcement. Keep the native textarea role conforming while preserving the menu relationships and tests.
* fix(qqbot): align clear-storage command with actual downloads directory
The /bot-clear-storage command previously targeted
~/.openclaw/media/qqbot/downloads/{appId}/, but inbound attachments
and outbound fallback downloads are stored directly under
~/.openclaw/media/qqbot/downloads/ without appId subdivision.
This mismatch caused the clear command to report 'no files to clean'
while downloaded files continued to occupy disk space.
Changes:
- Replace resolveQqbotDownloadsDirForApp(appId) with
resolveQqbotDownloadsDir() that returns the downloads root
- Use getQQBotMediaPath('downloads') instead of manual path assembly
- Remove appId-based path validation (no longer needed)
- Update usage text to reflect the new scope
* refactor(qqbot): unify slash command auth and c2cOnly gating in registry
Previously, slash command authorization and group-chat rejection were
scattered across individual handlers and a hardcoded GROUP_EXCLUDED set.
This led to inconsistent behavior: commandAuthorized was hardcoded to
true in the pre-dispatch path, some handlers checked allowFrom while
others did not, and group users received no response for auth-gated
commands.
Changes:
1. Add resolveSlashCommandAuth() (new file slash-command-auth.ts)
- Requires sender to appear in an explicit non-wildcard allowFrom
list; wildcard ['*'] does not grant admin command access
- Group messages use groupAllowFrom, falling back to allowFrom
2. Fix commandAuthorized in slash-command-handler.ts
- Replace hardcoded 'true' with resolveSlashCommandAuth() call
3. Add c2cOnly field to SlashCommand interface
- Commands declare c2cOnly: true instead of checking ctx.type
inside their handler
- Registry rejects c2cOnly commands in group chat before auth
check, returning a user-friendly hint
4. Remove GROUP_EXCLUDED hardcoded set from register-basic.ts
- /bot-help now filters by cmd.c2cOnly dynamically
5. Clean up handler-level auth and scene checks
- Remove hasExplicitCommandAllowlist check from register-logs
- Remove ctx.type !== 'c2c' guards from all c2cOnly handlers
- Improve rejection message to mention the correct config field
(allowFrom for c2c, groupAllowFrom for group)
6. Mark commands: bot-upgrade, bot-streaming, bot-logs,
bot-clear-storage, bot-approve as c2cOnly: true
* fix(qqbot): pass allowQQBotDataDownloads when sending slash command file attachments
The /bot-logs command writes temporary log files to the QQBot data
downloads directory (~/.openclaw/qqbot/downloads/), but sendDocument
was called without allowQQBotDataDownloads: true. This caused
resolveOutboundMediaPath to reject the file path as outside the
allowed media roots, silently failing the file attachment while
the text reply was sent successfully.
Add { allowQQBotDataDownloads: true } to the sendDocument call in
slash-command-handler.ts so file-bearing slash command results
(currently only /bot-logs) can deliver their attachments.
* feat(qqbot): add /bot-me command to display sender user ID
Add a new /bot-me slash command that returns the sender's user ID
(openid). This helps users quickly find the value they need to add
to allowFrom or groupAllowFrom configuration for admin command
access.
Marked as c2cOnly since the user ID is sensitive information.
* feat(qqbot): update response timeout
* feat(qqbot): add engine import boundary test and bump version
- Add engine-import-boundary.test.ts to enforce that engine/ sources
only import from openclaw/plugin-sdk/* and never reach into other
openclaw internals directly. Scans all 110 source files recursively.
- Bump plugin version to 2026.4.27.
* fix(qqbot): unify slash command auth, c2cOnly gating, and file delivery (#73616) (thanks @cxyhhhhh)
---------
Co-authored-by: sliverp <870080352@qq.com>
* fix(cron): warn when --agent is not specified on cron add
Warn users when creating a cron job without specifying the --agent flag,
so they know the job will run with the default agent (main).
Fixes#42196
* fix(cron): warn when cron add omits --agent
* fix(cron): name default agent in warning
---------
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(pdf): resolve standard fonts from pdfjs package root
Resolve PDF.js standard fonts via pdfjs-dist/package.json instead of a
relative ../../node_modules path so the fallback renderer does not depend
on emitted dist chunk layout.
Add focused regression coverage that asserts the forwarded
standardFontDataUrl matches the installed pdfjs-dist package root and
exists on disk.
* fix(pdf): resolve pdfjs standard fonts from package root
* fix(pdf): use PDF.js font URL separator
---------
Co-authored-by: Dr JCai <jingxiao.cai@gmail.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>