T09 · Insecure Skill Coding Practices
- Location
src/io.js:15- Finding
Predictable Temporary File Allows Symlink-Based Arbitrary File Overwrite
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The package appears to be a real OpenClaw interchange library, but its public file APIs are too broad and include unsafe write behavior that could affect files outside the intended workspace.
Review before installing. This does not look malicious, but it is a foundational file-writing library with raw path access. Only use it with trusted callers, keep interchange paths constrained to a dedicated workspace, avoid passing user-supplied paths directly, and update the flagged dependencies before production use.
src/io.js:15Predictable Temporary File Allows Symlink-Based Arbitrary File Overwrite
src/io.js:15Public File APIs Permit Unrestricted Filesystem Access
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
The declared vitest range resolves to a version with critical advisories involving arbitrary file read and possible execution, but vitest is only a devDependency and is not part of the runtime library surface. This still matters in developer and CI environments, where a vulnerable test tool or UI server could expose sensitive files or enable compromise if used in an unsafe way.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
### 13. No path traversal protection (io.js, indexer.js)
`writeMd`, `atomicWrite`, `readMd` accept arbitrary paths. A skill could write to `../../etc/passwd` or any location. While skills are trusted code, defense-in-depth would restrict writes to within `INTERCHANGE_ROOT`.
**Fix:** Add an optional `assertWithinRoot(filePath)` guard to `writeMd`.
The declared description presents a Markdown/shared interchange library dealing with file serialization, YAML frontmatter, locking, and schema validation. The supplied code does none of those things. Instead, it provides resilience control for external API calls via a circuit breaker pattern. This is a materially different primary purpose and introduces undeclared capabilities unrelated to the declared library functionality.
The declared description emphasizes foundational Markdown interchange features such as atomic writes, deterministic serialization, YAML frontmatter handling, advisory locking, and schema validation. The supplied code chunk does not implement those capabilities. Instead, it contains miscellaneous helper/formatting functions, only one of which tangentially relates to markdown via a table serializer re-export. The presence of slugification, currency formatting, and relative time formatting indicates a materially different purpose from the declared shared .md interchange library. Therefore, the description does not accurately represent this code chunk.
The code chunk is an index file that re-exports library modules. It does support the declared purpose around Markdown interchange, atomic I/O, locking, validation, and deterministic serialization. However, it also declares materially broader capabilities not mentioned in the description, especially database reconciliation and index management, which go beyond a narrowly described '.md interchange library' foundation. Because the declared description omits these significant exported behaviors, the description does not fully accurately represent what the code exposes.
The declared description presents a broad shared interchange library centered on Markdown file IO/integrity features such as atomic writes, deterministic serialization, YAML frontmatter, advisory locking, and schema validation. The supplied code instead implements a narrow reconciliation function that detects drift between a database-state map and parsed file records by comparing IDs and hashes. That behavior is related at a high level to interchange data management, but it does not demonstrate the specific declared capabilities and has a materially different immediate purpose: sync/reconciliation analysis rather than foundational .md interchange operations. Because the code’s actual functionality is not accurately represented by the declared description, this is a mismatch.
js-yaml is a direct production dependency of this package, and the advisories describe CPU exhaustion conditions during parsing of crafted YAML inputs. Because this skill is an interchange library centered on YAML frontmatter, untrusted Markdown/YAML content is core to its function, which makes parser-level denial of service materially relevant.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
The package allows installation of js-yaml 4.1.1, which is flagged with multiple denial-of-service advisories involving YAML parsing and merge-key processing. Because this library explicitly advertises YAML frontmatter and schema validation as core functionality, vulnerable YAML parsing is directly relevant and could let crafted input consume excessive CPU or otherwise destabilize consumers of the skill.
Without declared permissions the skill's intent is opaque and cannot be validated.
The API exposes a skipValidation option that allows callers to bypass frontmatter schema checks entirely. In a shared interchange library that other skills build on, this weakens a central trust boundary and can let malformed or policy-violating metadata be persisted, which may later trigger unsafe behavior in downstream consumers that assume validated input.
* @param {string} filePath - Target file path
* @param {Record<string, any>} frontmatter - Frontmatter fields
* @param {string} content - Markdown body content
* @param {{ force?: boolean, skipValidation?: boolean }} [opts] - Options; force=true skips idempotency check, skipValidation=true skips frontmatter validation
*/
export async function writeMd(filePath, frontmatter, content, opts = {}) {
const lock = await acquireLock(filePath);
This conditional explicitly disables validation when opts.skipValidation is set, creating a straightforward validation-bypass path. Because this module is the foundational I/O layer for other OpenClaw skills, allowing invalid YAML/frontmatter to be written here can propagate tainted state across the ecosystem and undermine assumptions made by higher-level logic.
};
// Validate frontmatter unless explicitly skipped (e.g., internal/test use)
if (!opts.skipValidation) {
const validation = validateFrontmatter(meta);
if (!validation.valid) {
throw new Error(`Invalid frontmatter: ${validation.errors.join('; ')}`);
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
await expect(writeMd(fp, { skill: 'test' }, 'content')).rejects.toThrow(/Invalid frontmatter/);
});
it('allows skipValidation for internal use', async () => {
const fp = path.join(tmpDir, 'skip.md');
await writeMd(fp, { skill: 'test' }, 'content', { skipValidation: true });
expect(readMd(fp).meta.skill).toBe('test');
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
await expect(writeMd(fp, { skill: 'test' }, 'content')).rejects.toThrow(/Invalid frontmatter/);
});
it('allows skipValidation for internal use', async () => {
const fp = path.join(tmpDir, 'skip.md');
await writeMd(fp, { skill: 'test' }, 'content', { skipValidation: true });
expect(readMd(fp).meta.skill).toBe('test');
This markdown file describes atomic file I/O and presents the library as a foundation for reading and writing interchange files, but it does not include any caution that using the write APIs will modify files on disk. Because markdown files should warn about behaviors that could affect user data or system integrity, the omission is a minor safety disclosure gap.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"test:watch": "vitest"
},
"dependencies": {
"js-yaml": "^4.1.0"
},
"devDependencies": {
"vitest": "^3.0.0"
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"js-yaml": "^4.1.0"
},
"devDependencies": {
"vitest": "^3.0.0"
},
"engines": {
"node": ">=18"
The code forces the locale to 'en-US' and the currency to 'USD' in a user-facing formatter. This is a natural-language/locale policy concern because it imposes a specific locale and regional format without any opt-in or indication that the skill is intentionally US-only.
No suspicious patterns detected.