fix(sessions): guard withSessionStoreLock against undefined storePath (#14717) (openclaw#14755) thanks @lailoo
Verified: - pnpm build - pnpm check - pnpm test:macmini Co-authored-by: lailoo <20536249+lailoo@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -299,6 +299,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Fixes
|
||||
|
||||
- Gateway/OpenResponses: harden URL-based `input_file`/`input_image` handling with explicit SSRF deny policy, hostname allowlists (`files.urlAllowlist` / `images.urlAllowlist`), per-request URL input caps (`maxUrlParts`), blocked-fetch audit logging, and regression coverage/docs updates.
|
||||
- Sessions: guard `withSessionStoreLock` against undefined `storePath` to prevent `path.dirname` crash. (#14717)
|
||||
- Security: fix unauthenticated Nostr profile API remote config tampering. (#13719) Thanks @coygeek.
|
||||
- Security: remove bundled soul-evil hook. (#14757) Thanks @Imccccc.
|
||||
- Security/Audit: add hook session-routing hardening checks (`hooks.defaultSessionKey`, `hooks.allowRequestSessionKey`, and prefix allowlists), and warn when HTTP API endpoints allow explicit session-key routing.
|
||||
|
||||
@@ -714,6 +714,11 @@ async function withSessionStoreLock<T>(
|
||||
fn: () => Promise<T>,
|
||||
opts: SessionStoreLockOptions = {},
|
||||
): Promise<T> {
|
||||
if (!storePath || typeof storePath !== "string") {
|
||||
throw new Error(
|
||||
`withSessionStoreLock: storePath must be a non-empty string, got ${JSON.stringify(storePath)}`,
|
||||
);
|
||||
}
|
||||
const timeoutMs = opts.timeoutMs ?? 10_000;
|
||||
const staleMs = opts.staleMs ?? 30_000;
|
||||
// `pollIntervalMs` is retained for API compatibility with older lock options.
|
||||
|
||||
23
src/config/sessions/store.undefined-path.test.ts
Normal file
23
src/config/sessions/store.undefined-path.test.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Regression test for #14717: path.dirname(undefined) crash in withSessionStoreLock
|
||||
*
|
||||
* When a channel plugin passes undefined as storePath to recordSessionMetaFromInbound,
|
||||
* the call chain reaches withSessionStoreLock → path.dirname(undefined) → TypeError crash.
|
||||
* After fix, a clear Error is thrown instead of an unhandled TypeError.
|
||||
*/
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { updateSessionStore } from "./store.js";
|
||||
|
||||
describe("withSessionStoreLock storePath guard (#14717)", () => {
|
||||
it("throws descriptive error when storePath is undefined", async () => {
|
||||
await expect(
|
||||
updateSessionStore(undefined as unknown as string, (store) => store),
|
||||
).rejects.toThrow("withSessionStoreLock: storePath must be a non-empty string");
|
||||
});
|
||||
|
||||
it("throws descriptive error when storePath is empty string", async () => {
|
||||
await expect(updateSessionStore("", (store) => store)).rejects.toThrow(
|
||||
"withSessionStoreLock: storePath must be a non-empty string",
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user