{"record":{"id":"e9b96f1b942c5546","repo":"databendlabs/databend","slug":"access-denied-target-is-outside-allowed-directo","errorCode":null,"errorMessage":"Access denied: {target} is outside allowed directories","messagePattern":"Access denied: (.+?) is outside allowed directories","errorType":"exception","errorClass":"PermissionError","httpStatus":null,"severity":"error","filePath":"src/query/script_udf_support/src/transform_udf_script.rs","lineNumber":586,"sourceCode":"        if path:\n            ALLOWED_BASES.add(Path(path))\n    for prefix in (sys.prefix, sys.exec_prefix, sys.base_prefix, sys.base_exec_prefix):\n        if prefix:\n            base_path = Path(prefix)\n            ALLOWED_BASES.add(base_path)\n            ALLOWED_BASES.add(base_path / f\"lib/python{sys.version_info.major}.{sys.version_info.minor}\")\n\n    _original_open = open\n    _original_os_open = os.open if hasattr(os, 'open') else None\n\n    def _ensure_allowed(file_path: Path, target: str):\n        for base in ALLOWED_BASES:\n            try:\n                file_path.relative_to(base)\n                return\n            except ValueError:\n                continue\n        raise PermissionError(f\"Access denied: {target} is outside allowed directories\")\n\n    def safe_open(file, mode='r', **kwargs):\n        file_path = Path(file).resolve()\n        _ensure_allowed(file_path, file)\n        return _original_open(file, mode, **kwargs)\n\n    def safe_os_open(path, flags, mode=0o777):\n        file_path = Path(path).resolve()\n        _ensure_allowed(file_path, path)\n        return _original_os_open(path, flags, mode)\n\n    builtins.open = safe_open\n    if _original_os_open:\n        os.open = safe_os_open\n\n    dangerous_modules = ['subprocess', 'os.system', 'eval', 'exec', 'compile']\n    for module in dangerous_modules:\n        if module in sys.modules:","sourceCodeStart":568,"sourceCodeEnd":604,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/script_udf_support/src/transform_udf_script.rs#L568-L604","documentation":"Raised by the script-UDF Python sandbox's _ensure_allowed guard when a file open targets a path that is not relative to any directory in ALLOWED_BASES (registered allowed roots plus interpreter prefix directories). It is a deliberate sentinel security check that blocks UDF scripts from reading or writing files outside the whitelisted directories; the offending path is reported in {target}.","triggerScenarios":"A key like 'notanumber/queue/x' or a seq overflowing u64 is passed to PermitKey::parse_key.","commonSituations":"Manually crafted keys; corrupted/truncated first segment; an older writer format that did not prefix with a numeric seq.","solutions":["Check the failing key text in the wrapped inner error and confirm the first segment is a plain decimal u64.","Fix the code path that generates the seq prefix; it must write the u64 seq as the first segment.","Migrate keys written by incompatible versions."],"exampleFix":"// before\nassert!(\"abc/queue/x\".parse_key_ok());\n// after\nlet seq: u64 = key.split('/').next().unwrap().parse().map_err(|_| skip_key())?;","handlingStrategy":"validation","validationCode":"let seq_ok = key.split('/').next().map(|s| s.parse::<u64>().is_ok()).unwrap_or(false);\nif !seq_ok { return skip(); }","typeGuard":"fn seq_of(key: &str) -> Option<u64> { key.split('/').next()?.parse().ok() }","tryCatchPattern":"match PermitKey::parse_key(key) { Err(e) if e.to_string().starts_with(\"failed to parse seq\") => { log_corrupt(key); continue; }, other => other? }","preventionTips":["Write seq numbers with a single canonical u64 Display path","Validate keys after deserializing from the meta store","Add a migration test when changing key formats"],"tags":["rust","meta-service","key-parsing","integer-parse"],"backgroundTag":"invalid-argument-format","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}