forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathruntime-config-serialize.test.ts
More file actions
60 lines (53 loc) · 2.45 KB
/
Copy pathruntime-config-serialize.test.ts
File metadata and controls
60 lines (53 loc) · 2.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { describe, expect, it } from "vitest";
import { serializeRuntimeConfig } from "./runtime-config-serialize";
// Pin a security-critical path: the inline-injected runtime config
// lands inside a <script>...</script> block in the root layout. A
// hostile env value containing the closing-script substring would
// otherwise break out and let the attacker inject arbitrary HTML.
// JSON.stringify does NOT escape `<` by default, so we MUST escape
// it to `<` here. U+2028 / U+2029 must also be escaped because
// the JS string literal parser treats them as line terminators in
// older engines.
//
// Tokenizer note: we build the test inputs via String.fromCharCode
// so the literal U+2028 / U+2029 codepoints never appear in this
// source file (some editors / build pipelines reject them).
const LS = String.fromCharCode(0x2028);
const PS = String.fromCharCode(0x2029);
describe("serializeRuntimeConfig (shell-docs)", () => {
it("escapes `<` so the closing-script substring cannot appear in the output", () => {
const malicious = { baseUrl: "</script><script>alert(1)</script>" };
const serialized = serializeRuntimeConfig(malicious);
expect(serialized).not.toContain("</script>");
expect(serialized).toContain("\\u003c");
});
it("escapes U+2028 (LINE SEPARATOR) to \\u2028", () => {
const cfg = { baseUrl: `before${LS}after` };
const serialized = serializeRuntimeConfig(cfg);
expect(serialized).not.toContain(LS);
expect(serialized).toContain("\\u2028");
});
it("escapes U+2029 (PARAGRAPH SEPARATOR) to \\u2029", () => {
const cfg = { baseUrl: `before${PS}after` };
const serialized = serializeRuntimeConfig(cfg);
expect(serialized).not.toContain(PS);
expect(serialized).toContain("\\u2029");
});
it("round-trips a normal config via JSON.parse", () => {
const cfg = {
baseUrl: "https://docs.example.com",
shellUrl: "https://shell.example.com",
posthogKey: "phc_real",
};
const serialized = serializeRuntimeConfig(cfg);
// The browser receives `window.__SHOWCASE_CONFIG__=<serialized>;`
// and evaluates it. JSON.parse accepts the escaped output
// identically (the JS engine resolves < / <LS> / <PS>).
expect(JSON.parse(serialized)).toEqual(cfg);
});
it("does not double-escape already-safe characters", () => {
const cfg = { baseUrl: "https://docs.copilotkit.ai" };
const serialized = serializeRuntimeConfig(cfg);
expect(serialized).toBe(JSON.stringify(cfg));
});
});