Skip to content

Commit d4c4f4c

Browse files
fix(infra): validate file-sourced data before outbound network requests
Sanitize cluster_id path segments in weaviate.ts and validate URLs in status.ts before making network requests with file-sourced data. Fixes code-scanning #10, #11 Generated with oh-my-agent Co-Authored-By: First Fluke <our.first.fluke@gmail.com>
1 parent e759f0f commit d4c4f4c

2 files changed

Lines changed: 22 additions & 6 deletions

File tree

apps/infra/freemium/scripts/status.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ const HACKATHON_DIR = join(__dirname, "..");
77
const STATE_FILE = join(HACKATHON_DIR, ".weaviate-state.json");
88
const TIMEOUT_MS = 5_000;
99

10+
function validateUrl(value: string, name: string): string {
11+
const parsed = URL.parse(value);
12+
if (!parsed || !["http:", "https:"].includes(parsed.protocol ?? "")) {
13+
throw new Error(`Invalid ${name} URL: ${value}`);
14+
}
15+
return parsed.href;
16+
}
17+
1018
// ---------------------------------------------------------------------------
1119
// Types
1220
// ---------------------------------------------------------------------------
@@ -119,7 +127,7 @@ async function checkVercelProject(
119127
projectId: string,
120128
token: string,
121129
): Promise<{ ok: boolean; error?: string }> {
122-
const url = `https://api.vercel.com/v9/projects/${projectId}`;
130+
const url = validateUrl(`https://api.vercel.com/v9/projects/${encodeURIComponent(projectId)}`, "Vercel API");
123131
try {
124132
const res = await fetchWithTimeout(url, {
125133
headers: { Authorization: `Bearer ${token}` },
@@ -134,7 +142,7 @@ async function checkVercelProject(
134142
async function checkSupabase(
135143
projectId: string,
136144
): Promise<{ ok: boolean; error?: string }> {
137-
const url = `https://${projectId}.supabase.co`;
145+
const url = validateUrl(`https://${encodeURIComponent(projectId)}.supabase.co`, "Supabase");
138146
try {
139147
const res = await fetchWithTimeout(url);
140148
if (res.status < 500) return { ok: true };
@@ -147,7 +155,7 @@ async function checkSupabase(
147155
async function checkWeaviate(
148156
weaviateUrl: string,
149157
): Promise<{ ok: boolean; error?: string }> {
150-
const base = weaviateUrl.replace(/\/$/, "");
158+
const base = validateUrl(weaviateUrl, "Weaviate").replace(/\/$/, "");
151159
const url = `${base}/.well-known/ready`;
152160
try {
153161
const res = await fetchWithTimeout(url);

apps/infra/freemium/scripts/weaviate.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
77
const STATE_FILE = join(__dirname, "..", ".weaviate-state.json");
88
const WCD_BASE_URL = "https://api.wcs.weaviate.io/v1";
99

10+
function validatePathSegment(value: string, name: string): string {
11+
const sanitized = encodeURIComponent(value);
12+
if (!sanitized || sanitized.includes("..") || sanitized.includes("/")) {
13+
throw new Error(`Invalid ${name}: ${value}`);
14+
}
15+
return sanitized;
16+
}
17+
1018
interface WeaviateState {
1119
cluster_id: string;
1220
url: string;
@@ -106,7 +114,7 @@ async function commandUp(apiKey: string, clusterName: string): Promise<void> {
106114
if (state?.cluster_id) {
107115
const check = await apiRequest<unknown>(
108116
"GET",
109-
`/clusters/${state.cluster_id}`,
117+
`/clusters/${validatePathSegment(state.cluster_id, "cluster_id")}`,
110118
apiKey,
111119
);
112120

@@ -163,7 +171,7 @@ async function commandDown(apiKey: string): Promise<void> {
163171

164172
const del = await apiRequest<unknown>(
165173
"DELETE",
166-
`/clusters/${state.cluster_id}`,
174+
`/clusters/${validatePathSegment(state.cluster_id, "cluster_id")}`,
167175
apiKey,
168176
);
169177

@@ -191,7 +199,7 @@ async function commandStatus(apiKey: string): Promise<void> {
191199

192200
const result = await apiRequest<unknown>(
193201
"GET",
194-
`/clusters/${state.cluster_id}`,
202+
`/clusters/${validatePathSegment(state.cluster_id, "cluster_id")}`,
195203
apiKey,
196204
);
197205

0 commit comments

Comments
 (0)