{"record":{"id":"d716d41ae17e97e7","repo":"nodejs/node","slug":"not-in-roots","errorCode":null,"errorMessage":"{} not in roots {}","messagePattern":"(.+?) not in roots (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"deps/v8/tools/adb-d8.py","lineNumber":42,"sourceCode":"import struct\nimport threading\nimport subprocess\nimport SocketServer # TODO(leszeks): python 3 compatibility\n\ndef CreateFileHandlerClass(root_dirs, verbose):\n  class FileHandler(SocketServer.BaseRequestHandler):\n    def handle(self):\n      data = self.request.recv(1024);\n      while data[-1] != \"\\0\":\n        data += self.request.recv(1024);\n\n      filename = data[0:-1]\n\n      try:\n        filename = os.path.abspath(filename)\n\n        if not any(filename.startswith(root) for root in root_dirs):\n          raise Exception(\"{} not in roots {}\".format(filename, root_dirs))\n        if not os.path.isfile(filename):\n          raise Exception(\"{} is not a file\".format(filename))\n\n        if verbose:\n          sys.stdout.write(\"Serving {}\\r\\n\".format(os.path.relpath(filename)))\n\n        with open(filename) as f:\n          contents = f.read();\n          self.request.sendall(struct.pack(\"!i\", len(contents)))\n          self.request.sendall(contents)\n\n      except Exception as e:\n        if verbose:\n          sys.stderr.write(\n            \"Request failed ({})\\n\".format(e).replace('\\n','\\r\\n'))\n        self.request.sendall(struct.pack(\"!i\", -1))\n\n  return FileHandler","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/v8/tools/adb-d8.py#L24-L60","documentation":"adb-d8.py runs a tiny TCP file server on the host that pushes requested files to an Android device running d8. As a security boundary it only serves files under one of the configured root_dirs. If the requested filename, made absolute, doesn't start with any allowed root, it raises to refuse serving outside the jail.","triggerScenarios":"Raised in FileHandler.handle() when `not any(os.path.abspath(filename).startswith(root) for root in root_dirs)` is true. The filename comes from the device's raw request bytes (terminated by NUL).","commonSituations":"The device asks for a source file outside the directory you started the server on (e.g. it wants a system library but you rooted the server at your build out/); path-handling differences where the request uses ../ to escape; root_dirs passed with no trailing slash so prefix matching fails on sibling directories.","solutions":["Start adb-d8.py with a root_dir that contains the file the device is requesting (or its parent).","Make sure root_dirs are specified with a trailing separator so prefix matching is directory-accurate.","On the device side, request paths that are genuinely within the served tree."],"exampleFix":"# before: server rooted at build/, device wants a sibling\npython adb-d8.py --port 5039 /home/me/v8/build\n# after\npython adb-d8.py --port 5039 /home/me/v8","handlingStrategy":"validation","validationCode":"import os\nrequested = os.path.abspath(filename)\nroots = [r if r.endswith(os.sep) else r + os.sep for r in root_dirs]\nassert any(requested.startswith(r) for r in roots), f'{requested} outside allowed roots {roots}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass root_dirs with a trailing separator so prefix matching is directory-accurate.","Start adb-d8.py at a parent directory wide enough to cover every file the device may pull."],"tags":["v8","d8","android","adb","security","file-server"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}