UNPKG

@tanstack/ai-code-mode

Version:

Secure TypeScript Code Mode for TanStack AI agents to execute sandboxed tool orchestration programs.

106 lines (105 loc) 3.7 kB
const DANGEROUS_WORDS = /* @__PURE__ */ new Set([ "password", "passwd", "pwd", "passcode", "secret", "token", "credential", "credentials", "authorization", "jwt", "bearer" ]); const COMPOUND_PATTERNS = [ "apikey", "accesskey", "authkey", "privatekey", "clientsecret", "webhooksecret" ]; function splitIntoWords(name) { return name.replace(/[_\-\s]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/\s+/).filter(Boolean); } function looksLikeSecret(name) { const words = splitIntoWords(name); if (words.some((w) => DANGEROUS_WORDS.has(w))) return true; const normalized = name.replace(/[_\-\s]/g, "").toLowerCase(); return COMPOUND_PATTERNS.some((p) => normalized.includes(p)); } function resolveRef(ref, root) { const match = ref.match(/^#\/(\$defs|definitions)\/(.+)$/); if (!match) return void 0; const bucket = match[1]; const key = match[2]; return key === void 0 ? void 0 : root[bucket]?.[key]; } function findSecretParams(schema, root, seen, path, found) { if (!schema || typeof schema !== "object" || seen.has(schema)) return; seen.add(schema); if (schema.properties && typeof schema.properties === "object") { for (const [paramName, sub] of Object.entries(schema.properties)) { if (looksLikeSecret(paramName)) { found.push({ path: [...path, paramName], name: paramName }); } findSecretParams(sub, root, seen, [...path, paramName], found); } } if (Array.isArray(schema.items)) { schema.items.forEach( (s, i) => findSecretParams(s, root, seen, [...path, `[${i}]`], found) ); } else if (schema.items && typeof schema.items === "object") { findSecretParams(schema.items, root, seen, [...path, "[]"], found); } if (schema.additionalProperties && typeof schema.additionalProperties === "object") { findSecretParams(schema.additionalProperties, root, seen, path, found); } for (const key of ["anyOf", "oneOf", "allOf"]) { const arr = schema[key]; if (Array.isArray(arr)) { arr.forEach((s) => findSecretParams(s, root, seen, path, found)); } } if (typeof schema.$ref === "string") { const target = resolveRef(schema.$ref, root); if (target) findSecretParams(target, root, seen, path, found); } } function buildMessage(toolName, paramPath) { return `[TanStack AI Code Mode] Tool "${toolName}" has parameter "${paramPath.join(".")}" that looks like a secret. Code Mode executes LLM-generated code — any value passed through this parameter is accessible to generated code and could be exfiltrated. Keep secrets in your server-side tool implementation instead of passing them as tool parameters.`; } function warnIfBindingsExposeSecrets(tools, options = {}) { const { handler = "warn", dedupCache } = options; if (handler === "ignore") return; for (const tool of tools) { const schema = tool.inputSchema; if (!schema) continue; const found = []; findSecretParams(schema, schema, /* @__PURE__ */ new Set(), [], found); for (const entry of found) { const dedupKey = `${tool.name}::${entry.path.join(".")}`; if (dedupCache) { if (dedupCache.has(dedupKey)) continue; dedupCache.add(dedupKey); } const info = { toolName: tool.name, paramName: entry.name, paramPath: entry.path }; if (typeof handler === "function") { handler(info); } else if (handler === "throw") { throw new Error(buildMessage(tool.name, entry.path)); } else { console.warn(buildMessage(tool.name, entry.path)); } } } } export { warnIfBindingsExposeSecrets }; //# sourceMappingURL=validate-bindings.js.map