mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-21 12:04:59 +00:00
fix(security): harden hook session-key normalization (#25750) (thanks @bmendonca3)
This commit is contained in:
@@ -15,6 +15,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Security/Hooks: normalize hook session-key classification with trim/lowercase plus Unicode NFKC folding (for example full-width `HOOK:...`) so external-content wrapping cannot be bypassed by mixed-case or lookalike prefixes. (#25750) Thanks @bmendonca3.
|
||||
- Discord/Block streaming: restore block-streamed reply delivery by suppressing only reasoning payloads (instead of all `block` payloads), fixing missing Discord replies in `channels.discord.streaming=block` mode. (#25839, #25836, #25792) Thanks @pewallin.
|
||||
- Matrix/Read receipts: send read receipts as soon as Matrix messages arrive (before handler pipeline work), so clients no longer show long-lived unread/sent states while replies are processing. (#25841, #25840) Thanks @joshjhall.
|
||||
- Sandbox/FS bridge: build canonical-path shell scripts with newline separators (not `; ` joins) to avoid POSIX `sh` `do;` syntax errors that broke sandbox file/image read-write operations. (#25737, #25824, #25868) Thanks @DennisGoldfinger and @peteragility.
|
||||
|
||||
@@ -252,6 +252,11 @@ describe("external-content security", () => {
|
||||
expect(isExternalHookSession(" HOOK:webhook:123 ")).toBe(true);
|
||||
});
|
||||
|
||||
it("identifies Unicode full-width hook prefixes", () => {
|
||||
expect(isExternalHookSession("HOOK:gmail:msg-123")).toBe(true);
|
||||
expect(isExternalHookSession("HOOK:custom:456")).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects non-hook sessions", () => {
|
||||
expect(isExternalHookSession("cron:daily-task")).toBe(false);
|
||||
expect(isExternalHookSession("agent:main")).toBe(false);
|
||||
@@ -278,6 +283,11 @@ describe("external-content security", () => {
|
||||
expect(getHookType("Hook:custom:456")).toBe("webhook");
|
||||
});
|
||||
|
||||
it("returns hook type for Unicode full-width hook prefixes", () => {
|
||||
expect(getHookType("HOOK:gmail:msg-123")).toBe("email");
|
||||
expect(getHookType(" HOOK:custom:456 ")).toBe("webhook");
|
||||
});
|
||||
|
||||
it("returns unknown for non-hook sessions", () => {
|
||||
expect(getHookType("cron:daily")).toBe("unknown");
|
||||
});
|
||||
|
||||
@@ -285,8 +285,14 @@ export function buildSafeExternalPrompt(params: {
|
||||
/**
|
||||
* Checks if a session key indicates an external hook source.
|
||||
*/
|
||||
function normalizeHookSessionKey(sessionKey: string): string {
|
||||
// NFKC folds common full-width forms so hook-prefix checks cannot be bypassed by
|
||||
// visually similar Unicode spellings like "HOOK:...".
|
||||
return sessionKey.normalize("NFKC").trim().toLowerCase();
|
||||
}
|
||||
|
||||
export function isExternalHookSession(sessionKey: string): boolean {
|
||||
const normalized = sessionKey.trim().toLowerCase();
|
||||
const normalized = normalizeHookSessionKey(sessionKey);
|
||||
return (
|
||||
normalized.startsWith("hook:gmail:") ||
|
||||
normalized.startsWith("hook:webhook:") ||
|
||||
@@ -298,7 +304,7 @@ export function isExternalHookSession(sessionKey: string): boolean {
|
||||
* Extracts the hook type from a session key.
|
||||
*/
|
||||
export function getHookType(sessionKey: string): ExternalContentSource {
|
||||
const normalized = sessionKey.trim().toLowerCase();
|
||||
const normalized = normalizeHookSessionKey(sessionKey);
|
||||
if (normalized.startsWith("hook:gmail:")) {
|
||||
return "email";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user