T09 · Insecure Skill Coding Practices
- Location
scripts/hatch.js:145- Finding
Unvalidated Execution of an External JavaScript Module
- Content
View full analysis
Vulnerability Details
File Location:
scripts/hatch.js, lines 14–15 and 145–148
Vulnerability Type: Untrusted local JavaScript module execution
Risk Level: MediumVulnerable code:
js var EXT_DIR = path.join(os.homedir(), ".openclaw", "extensions", "buddy-companion"); var SPRITES_PATH = path.join(EXT_DIR, "sprites.js");js function loadSprites() { try { return require(SPRITES_PATH); } catch (_) { return { renderSprite: function () { return ["(???)"]; }, renderFace: function (b) { return "(" + b.eye + ")"; } }; } }Technical Analysis
The Skill dynamically loads
~/.openclaw/extensions/buddy-companion/sprites.jswith Node.jsrequire(). Requiring a JavaScript module executes its top-level code; it does not merely load passive sprite data.The target module is outside the audited Skill package, and the loader does not validate its canonical path, ownership, permissions, integrity, or provenance. Consequently, any process or actor capable of replacing that file can introduce arbitrary JavaScript that will execute when
loadSprites()is reached.The function is invoked by the handlers for
/buddy,/buddy pet, and/buddy stats. The broadcatchblock does not prevent malicious top-level code from running before an exception occurs and may conceal a compromised or malformed module by silently returning fallback renderers.Attack Path
- An attacker first obtains the ability to create or modify
~/.openclaw/extensions/buddy-companion/sprites.js, such as through another compromised extension or a process running under the same account. - The attacker places malicious top-level JavaScript in that file.
- The user invokes
/buddy,/buddy pet, or/buddy stats. - The relevant command handler calls
loadSprites(). require(SPRITES_PATH)loads and executes the attacker-controlled module.- The payload runs with the operating-system permissions and accessible environment of the Agent process.
This ...[truncated 712 chars]
- An attacker first obtains the ability to create or modify
- Remediation
View remediation
Remediation Suggestions
- Bundle the sprite renderer within the audited Skill and load it using a path anchored to
__dirname, rather than loading executable code from a mutable directory under the user's home folder. - Prefer a passive data format such as JSON for sprite definitions. Parse the data and render it using trusted code included in the Skill.
- If an external executable module is unavoidable:
- Resolve and verify its canonical path before loading it.
- Reject symbolic links and unexpected file types.
- Validate file ownership and permissions.
- Verify the file against a pinned cryptographic digest or authenticated signature.
- Restrict loading to an explicitly installed and trusted component.
- Validate that
renderSpriteandrenderFaceare functions before calling them.
- Replace the silent broad exception handler with narrowly scoped error handling and security-relevant logging. Avoid suppressing evidence that an external module failed or behaved unexpectedly.
- Run the Skill with least privilege and isolate it from sensitive files and environment variables to reduce the impact of any compromised renderer.
- Bundle the sprite renderer within the audited Skill and load it using a path anchored to
