Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/auth/getApiKeyAccountId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ export async function getApiKeyAccountId(request: NextRequest): Promise<string |

try {
const keyHash = hashApiKey(apiKey, PRIVY_PROJECT_SECRET);
console.log("[getApiKeyAccountId] key prefix:", apiKey.slice(0, 12) + "...");
console.log("[getApiKeyAccountId] hash:", keyHash);
const apiKeys = await selectAccountApiKeys({ keyHash });
console.log("[getApiKeyAccountId] matched keys:", apiKeys?.length ?? "null");
Comment on lines +32 to +35
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Security concern: Logging 12 characters of an API key exposes too much of the secret.

Logging apiKey.slice(0, 12) reveals a significant portion of the credential. Depending on key format and entropy distribution, this could meaningfully narrow down the key space or violate compliance policies around secrets in logs (Vercel logs may be accessible to broader teams).

Additionally, logging the full keyHash enables cross-log correlation and could theoretically aid offline attacks if the key space is constrained.

Recommendations:

  1. Mask more aggressively—show only the last 4 characters: "..." + apiKey.slice(-4)
  2. Consider gating this diagnostic logging behind an environment variable (e.g., DEBUG_AUTH=true) so it doesn't persist in production once the issue is resolved.
  3. Add a // TODO: Remove diagnostic logging after fix: add logging to POST /api/sandboxes #411 investigation comment to ensure cleanup.
🔒 Proposed safer masking
-    console.log("[getApiKeyAccountId] key prefix:", apiKey.slice(0, 12) + "...");
-    console.log("[getApiKeyAccountId] hash:", keyHash);
+    // TODO: Remove diagnostic logging after `#411` investigation
+    console.log("[getApiKeyAccountId] key suffix:", "..." + apiKey.slice(-4));
     const apiKeys = await selectAccountApiKeys({ keyHash });
-    console.log("[getApiKeyAccountId] matched keys:", apiKeys?.length ?? "null");
+    console.log("[getApiKeyAccountId] matched keys:", apiKeys?.length ?? "null");

If you need the hash for correlation, consider logging only a truncated portion:

console.log("[getApiKeyAccountId] hash prefix:", keyHash.slice(0, 8) + "...");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/auth/getApiKeyAccountId.ts` around lines 32 - 35, In getApiKeyAccountId,
stop logging sensitive portions of the API key and hash: replace the
apiKey.slice(0,12) log with a masked form showing only the last 4 characters
(e.g., "..." + apiKey.slice(-4)) and log only a truncated hash prefix (e.g.,
keyHash.slice(0,8) + "..."); gate all diagnostic console.log calls (the ones
referencing apiKey and keyHash and the matched keys count around
selectAccountApiKeys) behind an environment flag like DEBUG_AUTH so they only
run when enabled, and add a TODO comment "// TODO: Remove diagnostic logging
after `#411` investigation" next to the gated logs for cleanup tracking.


if (apiKeys === null) {
console.error("[ERROR] selectAccountApiKeys returned null");
Expand Down
1 change: 1 addition & 0 deletions lib/sandbox/createSandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export async function createSandbox(
params.source && "type" in params.source && params.source.type === "snapshot";

// Pass params directly to SDK - it handles all the type variants
console.log("[createSandbox] Creating sandbox with params:", JSON.stringify(params, null, 2));
const sandbox = await Sandbox.create(
hasSnapshotSource
? {
Expand Down
3 changes: 3 additions & 0 deletions lib/sandbox/createSandboxPostHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { processCreateSandbox } from "@/lib/sandbox/processCreateSandbox";
export async function createSandboxPostHandler(request: NextRequest): Promise<NextResponse> {
const validated = await validateSandboxBody(request);
if (validated instanceof NextResponse) {
const errorBody = await validated.clone().json();
console.error("[POST /api/sandboxes] Validation/auth failed:", errorBody);
return validated;
}

Expand All @@ -33,6 +35,7 @@ export async function createSandboxPostHandler(request: NextRequest): Promise<Ne
{ status: 200, headers: getCorsHeaders() },
);
} catch (error) {
console.error("[POST /api/sandboxes] Error creating sandbox:", error);
const message = error instanceof Error ? error.message : "Failed to create sandbox";
return NextResponse.json(
{ status: "error", error: message },
Expand Down
18 changes: 14 additions & 4 deletions lib/sandbox/processCreateSandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export async function processCreateSandbox(
const { accountId, prompt } = input;

const snapshotId = await getValidSnapshotId(accountId);
console.log("[processCreateSandbox] accountId:", accountId, "snapshotId:", snapshotId ?? "none");

let result;

Expand All @@ -49,19 +50,28 @@ export async function processCreateSandbox(
source: { type: "snapshot", snapshotId },
});
result = createResult.response;
} catch {
const freshResult = await createSandbox({});
result = freshResult.response;
} catch (snapshotError) {
console.error("[processCreateSandbox] Snapshot creation failed:", snapshotError);
try {
const freshResult = await createSandbox({});
result = freshResult.response;
} catch (freshError) {
console.error("[processCreateSandbox] Fresh fallback also failed:", freshError);
throw freshError;
}
}
} else {
const freshResult = await createSandbox({});
result = freshResult.response;
}

await insertAccountSandbox({
const insertResult = await insertAccountSandbox({
account_id: accountId,
sandbox_id: result.sandboxId,
});
if (insertResult.error) {
console.error("[processCreateSandbox] insertAccountSandbox failed:", insertResult.error);
}

// Trigger the prompt execution task if a prompt was provided
let runId: string | undefined;
Expand Down
Loading