{"record":{"id":"c1206df193517598","repo":"vercel-labs/agent-browser","slug":"invalid-system-dependency-name-json-stringify-n","errorCode":null,"errorMessage":"Invalid system dependency name: ${JSON.stringify(name)}","messagePattern":"Invalid system dependency name: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@agent-browser/sandbox/src/vercel.ts","lineNumber":353,"sourceCode":"    );\n  })) as Record<string, unknown>;\n  const Sandbox = mod.Sandbox;\n  if (typeof Sandbox !== \"function\" && typeof Sandbox !== \"object\") {\n    throw new Error(\"@vercel/sandbox did not export Sandbox.\");\n  }\n  return Sandbox as VercelSandboxConstructor;\n}\n\nfunction defaultEnv(): Readonly<Record<string, string | undefined>> {\n  const globalWithProcess = globalThis as typeof globalThis & {\n    readonly process?: { readonly env?: Readonly<Record<string, string | undefined>> };\n  };\n  return globalWithProcess.process?.env ?? {};\n}\n\nfunction formatDnfPackageName(name: string): string {\n  if (!SAFE_DNF_PACKAGE_NAME.test(name)) {\n    throw new Error(`Invalid system dependency name: ${JSON.stringify(name)}`);\n  }\n  return quoteShellArg(name);\n}\n","sourceCodeStart":335,"sourceCodeEnd":357,"githubUrl":"https://github.com/vercel-labs/agent-browser/blob/548b159b30eef119ccf6846c8bc807d0eaa3f6f8/packages/@agent-browser/sandbox/src/vercel.ts#L335-L357","documentation":"formatDnfPackageName (vercel.ts:351-355) validates each entry of options.systemDependencies against SAFE_DNF_PACKAGE_NAME (/^[A-Za-z0-9._+][A-Za-z0-9._+-]*$/, vercel.ts:50) before splicing names into the `dnf install` shell line (vercel.ts:126-129). Names are interpolated into a shell command, so anything that is not a bare RPM package name, including version constraints, globs, whitespace, or a leading dash, throws. JSON.stringify in the message shows the exact rejected value.","triggerScenarios":"Passing systemDependencies entries such as \"nss >= 3.0\" (spaces and comparison operators), \"nss*\" (glob), \"\" (empty string fails the first-character class), \"-flag\" (leading dash), \"chromium@latest\" or \"group:base\" (@ and : are not allowed), or a name with trailing whitespace. The default CHROMIUM_SYSTEM_DEPS list always passes; only user-supplied systemDependencies arrays can trigger it.","commonSituations":"Copying dnf/apt spec strings from Dockerfiles (e.g. `nss-3.90.0-1.el9.x86_64` is fine but `nss >= 3.79` is not); npm-style package@version habits; forgetting installSystemDependencies exists and hand-rolling dependency lists from documentation snippets; untrimmed strings from config files.","solutions":["Pass bare dnf package names only: trim the string and strip version constraints, globs, and architecture suffix qualifiers that contain @ : / or spaces (letters, digits, dot, plus, hyphen, underscore are accepted).","Use the built-in default list: omit systemDependencies (it defaults to CHROMIUM_SYSTEM_DEPS in vercel.ts:22-48) and only override it with a curated array of bare names.","If the value came from config/user input, validate each name against /^[A-Za-z0-9._+][A-Za-z0-9._+-]*$/ (plus .trim()) before handing it to withAgentBrowserSandbox/createAgentBrowserSnapshot, and reject early with your own error naming the index.","When you truly need a versioned install, pre-install that package yourself via sandbox.runCommand(\"dnf\", [...]) with explicit args instead of relying on systemDependencies."],"exampleFix":"// before\nawait createAgentBrowserSandbox({\n  systemDependencies: [\"nss >= 3.79\", \"gtk3\"],\n});\n\n// after\nawait createAgentBrowserSandbox({\n  systemDependencies: [\"nss\", \"gtk3\"],\n});","handlingStrategy":"validation","validationCode":"const SAFE_DNF_PACKAGE_NAME = /^[A-Za-z0-9._+][A-Za-z0-9._+-]*$/;\n\nfunction normalizeSystemDependencies(names: readonly string[]): readonly string[] {\n  return names.map((name) => {\n    const trimmed = name.trim();\n    if (!SAFE_DNF_PACKAGE_NAME.test(trimmed)) {\n      throw new Error(`Invalid system dependency name: ${JSON.stringify(trimmed)}`);\n    }\n    return trimmed;\n  });\n}\n\n// run BEFORE withAgentBrowserSandbox / createAgentBrowserSandbox\nconst deps = normalizeSystemDependencies([\"nss\", \"gtk3\"]);","typeGuard":"function isSafeDnfPackageName(name: string): boolean {\n  return /^[A-Za-z0-9._+][A-Za-z0-9._+-]*$/.test(name);\n}\n\nfunction assertSafeSystemDependencies(names: readonly string[]): void {\n  names.forEach((name, index) => {\n    if (!isSafeDnfPackageName(name)) {\n      throw new Error(`systemDependencies[${index}] is not a bare dnf package name: ${name}`);\n    }\n  });\n}","tryCatchPattern":"try {\n  await createAgentBrowserSandbox({ systemDependencies: deps });\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith(\"Invalid system dependency name:\")) {\n    // message carries JSON.stringify(name); surface it to config validation, do not retry\n    throw new Error(`Fix systemDependencies config: ${error.message}`);\n  }\n  throw error;\n}","preventionTips":["Default to the built-in CHROMIUM_SYSTEM_DEPS list; only override with bare package names copied from `dnf list` output, not from Dockerfile spec strings.","Never put version constraints, globs, or npm-style name@version entries in systemDependencies; pre-install versioned packages via sandbox.runCommand instead.","Trim config-sourced strings and validate against /^[A-Za-z0-9._+][A-Za-z0-9._+-]*$/ at config load time so bad names fail at startup with an index.","Treat this throw as a security guard: it blocks shell injection, so never try to quote or escape your way around it."],"tags":["validation","shell-injection","system-dependencies","sandbox","dnf"],"backgroundTag":null,"analyzedSha":"548b159b30eef119ccf6846c8bc807d0eaa3f6f8","analyzedAt":"2026-08-16T10:12:14.925Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}