fix(prompts-core): block prompt path traversal

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-05-24 17:50:18 +09:00
parent 74d5f7018d
commit 436c618706
4 changed files with 46 additions and 10 deletions
+17 -1
View File
@@ -1,7 +1,7 @@
import { describe, expect, test } from "bun:test"
import { dirname, join } from "node:path"
import { fileURLToPath } from "node:url"
import { loadPrompt, PromptFileNotFoundError } from "./loader"
import { loadPrompt, PromptFileNotFoundError, PromptPathTraversalError } from "./loader"
import type { PromptSource } from "./types"
const fixtureSource: PromptSource = {
@@ -50,6 +50,22 @@ describe("loadPrompt", () => {
expect(expectError(error).message).toContain("test-prompt/missing")
})
test("#given prompt name escapes source directory #then rejects path traversal", async () => {
const error = await captureError(() =>
loadPrompt({ source: fixtureSource, name: "../test-prompt", variant: "default" })
)
expect(error).toBeInstanceOf(PromptPathTraversalError)
})
test("#given variant escapes source directory #then rejects path traversal", async () => {
const error = await captureError(() =>
loadPrompt({ source: fixtureSource, name: "test-prompt", variant: "../../outside" })
)
expect(error).toBeInstanceOf(PromptPathTraversalError)
})
test("#given runtime injection #then replaces placeholder in body", async () => {
const prompt = await loadPrompt({
source: fixtureSource,