{"record":{"id":"a99b0766769f5fa2","repo":"openmediavault/openmediavault","slug":"the-field-path-contains-forbidden-two-dot-symbols","errorCode":null,"errorMessage":"The field 'path' contains forbidden two-dot symbols.","messagePattern":"The field 'path' contains forbidden two-dot symbols\\.","errorType":"exception","errorClass":"OMV\\Exception","httpStatus":null,"severity":"error","filePath":"deb/openmediavault/usr/share/openmediavault/engined/rpc/folderbrowser.inc","lineNumber":70,"sourceCode":"     *   or 'mntent'.\n     *   \\em path The relative directory path.\n     * @param context The context of the caller.\n     * @return array An array of directory names.\n     * @ŧhrow \\OMV\\Exception\n     */\n    public function get($params, $context)\n    {\n        // Validate the RPC caller context.\n        $this->validateMethodContext($context, [\n            \"role\" => OMV_ROLE_ADMINISTRATOR\n        ]);\n        // Validate the parameters of the RPC service method.\n        $this->validateMethodParams($params, \"rpc.folderbrowser.get\");\n        // The field 'path' may not contain the characters '..'. This is\n        // because of security reasons: the given canonicalized absolute\n        // path MUST be below the given shared folder/mount point.\n        if (1 == preg_match(\"/\\.\\./\", $params['path'])) {\n            throw new \\OMV\\Exception(\n                \"The field 'path' contains forbidden two-dot symbols.\"\n            );\n        }\n        switch ($params['type']) {\n            case \"sharedfolder\":\n                // Get the absolute shared folder path.\n                $rootPath = \\OMV\\Rpc\\Rpc::call(\"ShareMgmt\", \"getPath\", [\n                    \"uuid\" => $params['uuid']\n                ], $context);\n                break;\n            case \"mntent\":\n                // Get the mount point configuration object.\n                $db = \\OMV\\Config\\Database::getInstance();\n                $object = $db->get(\n                    \"conf.system.filesystem.mountpoint\",\n                    $params['uuid']\n                );\n                $rootPath = $object->get(\"dir\");","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/openmediavault/openmediavault/blob/dce610eb66f624c640d0eb7ce401ddd65b763520/deb/openmediavault/usr/share/openmediavault/engined/rpc/folderbrowser.inc#L52-L88","documentation":"The openmediavault folderbrowser RPC rejects any 'path' parameter containing the substring '..' before processing the request. Because the given canonicalized absolute path must remain below the shared folder/mount point, '..' sequences would allow path traversal outside the permitted root, so the engine throws this exception as a hard security guard.","triggerScenarios":"Calling the rpc.folderbrowser service method (e.g. get) with params['path'] containing '..' anywhere, such as '/sharedfolder/../../etc', typically from naive string concatenation of user input.","commonSituations":"A plugin or script passes a user-typed relative path into the folderbrowser RPC; a client attempts directory traversal to escape the shared folder root; legacy code from an older API that tolerated relative paths.","solutions":["Canonicalize the path with realpath() and verify it stays under the shared folder before calling the RPC.","Reject any input containing '..' client-side with a friendly message.","Pass only absolute canonical paths already below the shared folder/mount point.","If access outside the shared folder is genuinely needed, use a mechanism with explicit permissions rather than folderbrowser."],"exampleFix":"// before\n$rpc->call('FolderBrowser', 'get', ['path' => $userPath, 'type' => 'sharedfolder']);\n// after\n$real = realpath($userPath);\nif ($real === false || str_contains($real, '..') || !str_starts_with($real, $sharedFolderPath)) {\n    throw new \\InvalidArgumentException('path must stay inside the shared folder');\n}\n$rpc->call('FolderBrowser', 'get', ['path' => $real, 'type' => 'sharedfolder']);","handlingStrategy":"validation","validationCode":"$real = realpath($path);\nif ($real === false || str_contains($real, '..') || !str_starts_with($real, $sharedFolderPath)) {\n    throw new \\InvalidArgumentException('path escapes shared folder');\n}","typeGuard":"function isSafeSubPath(string $path, string $root): bool {\n    $r = realpath($path);\n    $base = realpath($root);\n    return $r !== false && $base !== false\n        && !str_contains($r, '..')\n        && str_starts_with($r, rtrim($base, '/') . '/');\n}","tryCatchPattern":"try {\n    $result = $rpc->call('FolderBrowser', 'get', $params);\n} catch (\\OMV\\Exception $e) {\n    if (str_contains($e->getMessage(), 'forbidden two-dot')) {\n        throw new UserInputError('Path may not contain ..');\n    }\n    throw $e;\n}","preventionTips":["Always canonicalize with realpath() before passing paths to RPCs.","Reject '..' in user input at the UI layer with a clear message.","Verify paths start with an allowlisted root before submission.","Never build paths by raw concatenation of user input."],"tags":["path-traversal","security","php","rpc"],"backgroundTag":"path-traversal-blocked","analyzedSha":"dce610eb66f624c640d0eb7ce401ddd65b763520","analyzedAt":"2026-09-15T09:48:09.960Z","contentChangedAt":"2026-09-15T09:48:09.960Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}