pbakaus/impeccable · error
Svelte-component source file escapes project root
Error message
Svelte-component source file escapes project root
What it means
Thrown by resolveSourceFile() in live/svelte-component.mjs when the resolved relative path escapes the project root (starts with '..') or is absolute after path.relative(). This is the path-traversal sandbox guard: it prevents a sourceFile like '../../etc/passwd' or a symlink-anchored absolute resolution from reading outside cwd. It runs after the emptiness/absolute check and before the existence check.
Source
Thrown at skill/scripts/live/svelte-component.mjs:449
return null;
}
export function readManifest(manifestPath) {
const data = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
return {
...data,
manifestPath,
};
}
export function resolveSourceFile(sourceFile, cwd = process.cwd()) {
if (!sourceFile || path.isAbsolute(sourceFile)) {
throw new Error('Invalid svelte-component source file');
}
const full = path.resolve(cwd, sourceFile);
const rel = path.relative(cwd, full);
if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) {
throw new Error('Svelte-component source file escapes project root');
}
if (!fs.existsSync(full)) {
throw new Error('Svelte-component source file not found: ' + sourceFile);
}
return full;
}
function appendCssToSvelteStyle(lines, cssLines) {
const closeIdx = findLastStyleCloseLine(lines);
const prepared = ['', ...cssLines.map((line) => (line.trim() === '' ? '' : ' ' + line.trimStart()))];
if (closeIdx === -1) {
return [...lines, '', '<style>', ...prepared.slice(1), '</style>'];
}
return [
...lines.slice(0, closeIdx),
...prepared,
...lines.slice(closeIdx),
];View on GitHub (pinned to d14711ae3d)
Solutions
- Point sourceFile at a path inside the configured project root (cwd).
- If the component genuinely lives in a sibling package, set cwd to the workspace root that contains both, or copy/symlink the component into the project.
- Remove leading '../' segments and confirm the resolved file sits under cwd.
Example fix
// before (cwd = /proj/app)
resolveSourceFile('../shared/Foo.svelte', cwd)
// after (cwd = /proj)
resolveSourceFile('shared/Foo.svelte', cwd) Defensive patterns
Strategy: validation
Validate before calling
const full = path.resolve(cwd, sourceFile);
const rel = path.relative(cwd, full);
if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) {
throw new Error('sourceFile escapes project root: ' + sourceFile);
} Type guard
function isWithinRoot(p: string, root: string): boolean {
const rel = path.relative(root, path.resolve(root, p));
return !!rel && !rel.startsWith('..') && !path.isAbsolute(rel);
} Prevention
- Configure cwd as the workspace root that contains every component you reference.
- Reject '../' in user-supplied component paths at the input boundary.
- Document that the adapter is project-scoped by design.
When it happens
Trigger: resolveSourceFile(sourceFile, cwd) is called with a relative path containing '../' segments that resolve above cwd, e.g. '../shared/Foo.svelte' when cwd is /proj/app and the target lands in /proj/shared (outside /proj/app). Also triggered by absolute rel results on edge-case roots.
Common situations: Monorepo component lives in a sibling package and the caller passes a workspace-relative path instead of one relative to the configured cwd; cwd was set incorrectly (too narrow); user attempts to import a component from outside the project on purpose (not supported — the adapter scopes to the project).
Related errors
- Invalid svelte-component source file
- Svelte-component source file escapes project root
- Invalid svelte-component source file
- Svelte-component source file not found: ${sourceFile}
- Svelte-component source file not found: ${sourceFile}
AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13).
Data as JSON: /api/errors/b04546192c62cd6e.
Report an issue: GitHub.