@juspay/neurolink 9.87.4 → 9.88.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## [9.88.1](https://github.com/juspay/neurolink/compare/v9.88.0...v9.88.1) (2026-07-15)
2
+
3
+ ### Bug Fixes
4
+
5
+ - **(tools):** sandbox built-in file tools to the working directory ([4fc8520](https://github.com/juspay/neurolink/commit/4fc8520dbc024dec826a69a5f8264af7a25ff0e1))
6
+
7
+ ## [9.88.0](https://github.com/juspay/neurolink/compare/v9.87.4...v9.88.0) (2026-07-15)
8
+
9
+ ### Features
10
+
11
+ - **(cli):** implement memory subcommand for conversation management ([76219be](https://github.com/juspay/neurolink/commit/76219beaa90cddc17a71f765dc5c89a6b0ceae39))
12
+
13
+ ### Bug Fixes
14
+
15
+ - **(file-detector):** normalize extension matching ([967df4b](https://github.com/juspay/neurolink/commit/967df4b3ee205b9122a2a965971eae52a47872bd))
16
+
1
17
  ## [9.87.4](https://github.com/juspay/neurolink/compare/v9.87.3...v9.87.4) (2026-07-15)
2
18
 
3
19
  ### Bug Fixes
@@ -56,6 +56,12 @@ export declare const directAgentTools: {
56
56
  path: string;
57
57
  includeHidden: boolean;
58
58
  }, {
59
+ success: boolean;
60
+ error: string;
61
+ path?: undefined;
62
+ items?: undefined;
63
+ count?: undefined;
64
+ } | {
59
65
  success: boolean;
60
66
  path: string;
61
67
  items: {
@@ -14,6 +14,28 @@ function truncateOutput(output) {
14
14
  }
15
15
  return output;
16
16
  }
17
+ /**
18
+ * Contain a built-in file tool to the process working directory.
19
+ *
20
+ * Returns the resolved absolute path when it lies inside `process.cwd()`, or an
21
+ * `error` string otherwise. This is the sandbox for the default-enabled
22
+ * `readFile` / `writeFile` / `listDirectory` / `analyzeCSV` tools: without it an
23
+ * agent can pass an absolute path (`/etc/passwd`) or `../` traversal and reach
24
+ * arbitrary files. The previous guard (`!resolvedPath.startsWith(cwd) &&
25
+ * !path.isAbsolute(filePath)`) was always false for absolute paths, so it never
26
+ * fired. The `cwd + path.sep` suffix prevents a sibling-prefix bypass
27
+ * (`/home/app` vs `/home/app-evil`).
28
+ */
29
+ function resolveWithinCwd(filePath) {
30
+ const resolvedPath = path.resolve(filePath);
31
+ const cwd = path.resolve(process.cwd());
32
+ if (resolvedPath !== cwd && !resolvedPath.startsWith(cwd + path.sep)) {
33
+ return {
34
+ error: `Access denied: "${filePath}" resolves outside the working directory`,
35
+ };
36
+ }
37
+ return { path: resolvedPath };
38
+ }
17
39
  // Runtime Google Search tool creation - bypasses TypeScript strict typing
18
40
  function createGoogleSearchTools() {
19
41
  const searchTool = {};
@@ -71,15 +93,13 @@ export const directAgentTools = {
71
93
  }),
72
94
  execute: async ({ path: filePath }) => {
73
95
  try {
74
- // Security check - prevent reading outside current directory for relative paths
75
- const resolvedPath = path.resolve(filePath);
76
- const cwd = process.cwd();
77
- if (!resolvedPath.startsWith(cwd) && !path.isAbsolute(filePath)) {
78
- return {
79
- success: false,
80
- error: `Access denied: Cannot read files outside current directory`,
81
- };
96
+ // Sandbox: contain reads to the working directory (blocks absolute-path
97
+ // escape and ../ traversal).
98
+ const guard = resolveWithinCwd(filePath);
99
+ if ("error" in guard) {
100
+ return { success: false, error: guard.error };
82
101
  }
102
+ const resolvedPath = guard.path;
83
103
  const content = fs.readFileSync(resolvedPath, "utf-8");
84
104
  const stats = fs.statSync(resolvedPath);
85
105
  return {
@@ -113,7 +133,12 @@ export const directAgentTools = {
113
133
  }),
114
134
  execute: async ({ path: dirPath, includeHidden }) => {
115
135
  try {
116
- const resolvedPath = path.resolve(dirPath);
136
+ // Sandbox: contain directory listing to the working directory.
137
+ const guard = resolveWithinCwd(dirPath);
138
+ if ("error" in guard) {
139
+ return { success: false, error: guard.error };
140
+ }
141
+ const resolvedPath = guard.path;
117
142
  const items = fs.readdirSync(resolvedPath);
118
143
  const filteredItems = includeHidden
119
144
  ? items
@@ -229,15 +254,13 @@ export const directAgentTools = {
229
254
  }),
230
255
  execute: async ({ path: filePath, content, mode }) => {
231
256
  try {
232
- const resolvedPath = path.resolve(filePath);
233
- const cwd = process.cwd();
234
- // Security check
235
- if (!resolvedPath.startsWith(cwd) && !path.isAbsolute(filePath)) {
236
- return {
237
- success: false,
238
- error: `Access denied: Cannot write files outside current directory`,
239
- };
257
+ // Sandbox: contain writes to the working directory (blocks absolute-path
258
+ // escape and ../ traversal).
259
+ const guard = resolveWithinCwd(filePath);
260
+ if ("error" in guard) {
261
+ return { success: false, error: guard.error };
240
262
  }
263
+ const resolvedPath = guard.path;
241
264
  // Check if file exists for create mode
242
265
  if (mode === "create" && fs.existsSync(resolvedPath)) {
243
266
  return {
@@ -326,11 +349,12 @@ export const directAgentTools = {
326
349
  try {
327
350
  // Resolve file path
328
351
  logger.debug(`[analyzeCSV] Resolving file: ${filePath}`);
329
- const path = await import("path");
330
- // Resolve path (support both relative and absolute)
331
- const resolvedPath = path.isAbsolute(filePath)
332
- ? filePath
333
- : path.resolve(process.cwd(), filePath);
352
+ // Sandbox: contain CSV reads to the working directory.
353
+ const guard = resolveWithinCwd(filePath);
354
+ if ("error" in guard) {
355
+ return { success: false, error: guard.error };
356
+ }
357
+ const resolvedPath = guard.path;
334
358
  logger.debug(`[analyzeCSV] Resolved path: ${resolvedPath}`);
335
359
  // Parse CSV using streaming from disk (memory efficient)
336
360
  logger.info(`[analyzeCSV] Starting CSV parsing (max ${maxRows} rows)...`);