mirror of
https://github.com/nocobase/nocobase.git
synced 2026-09-22 06:30:48 +08:00
* fix(plugin-workflow-javascript): fix security issue * fix(plugin-workflow-javascript): fix path assertion under windows in test case * fix(plugin-workflow-javascript): sanitize module function return values to close return-value bypass Extend the sandbox hardening to also sanitize objects returned by wrapped module functions (including Promise resolutions), so that prototype-chain traversal via return values (e.g. crypto.createHash().update.constructor) cannot reach the host Function constructor. - Add sanitizeReturnValue() that sanitizes sync return values and thenable resolutions before they re-enter the sandbox - Wire sanitizeReturnValue() into the function wrapper inside sanitizeForSandbox() so every module function call goes through it - Walk the prototype chain up to MAX_PROTO_DEPTH=3 in the object branch so methods defined on the object's own prototype (e.g. Hash.prototype.update, Stats.prototype.isFile) are also exposed as hardened null-proto wrappers rather than raw host-realm functions - Add resolveProperty() helper that reads accessor-descriptor properties (getters) by invoking desc.get — required for lazy-getter module exports such as mathjs.evaluate Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(plugin-workflow-javascript): sanitize exceptions and Promises from module calls Address two P1 bypasses reported in PR review: P1.1 — Module function exceptions: the function wrapper now wraps fn(...args) in try/catch and calls sanitizeError() before re-throwing, so a host-realm Error caught inside the sandbox (e.g. from path.join(null)) no longer exposes e.constructor.constructor → host Function. P1.2 — Host Promise exposed to sandbox: sanitizeReturnValue() no longer returns the raw host Promise (whose .constructor chain reaches host Function). It now builds a null-prototype clean thenable that intercepts onFulfilled/onRejected callbacks, sanitizing resolved values via sanitizeForSandbox() and errors via sanitizeError() before they reach sandbox code. Also adds sanitizeError() helper shared by both fixes, and extends the test suite with: - P1.1 security test: path.join(null) throw chain is blocked - P1.2 security test: fs.promises.readdir Promise constructor chain is blocked - Functional regression: fs.promises.readdir still returns usable data after sanitization (note: result is a null-proto object; Array.isArray returns false but indexed access and .length work — raw Arrays cannot be returned safely as their __proto__.constructor chain leads back to host Function) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(plugin-workflow-javascript): restore array iteration for sanitized module return values Arrays returned by module functions were converted to null-prototype plain objects, which broke for...of, spread ([...arr]), and destructuring — the three most common ways to consume arrays in modern JavaScript. Add a special-case Array branch in sanitizeForSandbox() that: - copies indexed elements and length to a null-proto object (preserving security: no Array.prototype.constructor chain exposure) - attaches a safe Symbol.iterator backed by a null-proto iterator whose .next() results are also null-proto objects — no host-realm chain at any level, so the iterator cannot be used to reach the host Function constructor After this change: const entries = await fs.promises.readdir('.') for (const e of entries) { ... } // works const arr = [...entries] // works; arr is a real sandbox Array const [first] = entries // works entries.length / entries[0] // works (unchanged) Array.isArray(entries) // still false (by design, host Array is unsafe) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(plugin-workflow-javascript): json round-trip script return value before postMessage The script node result is always stored in the database as JSON and re-parsed by subsequent workflow nodes, so JavaScript-specific semantics (null prototypes, Symbols, functions) carry no meaning at the postMessage boundary. Add toJsonResult() that applies JSON.parse(JSON.stringify(value)) to the final script return value before postMessage, ensuring: - null-prototype objects produced by sanitizeForSandbox are converted to proper plain objects / Arrays (Array.isArray works correctly in downstream nodes) - function-valued properties are silently dropped (expected for serialized data) - the result is always structured-clone compatible Note: sanitizeForSandbox + Symbol.iterator are still required for values used within the script during execution (e.g. iterating a module-returned array before returning the result). toJsonResult() only normalises the boundary value. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(plugin-workflow-javascript): fix security issues --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>