babalae/better-genshin-impact · error · UnauthorizedAccessException
访问路径 '{relativePath}' 被拒绝
Error message
访问路径 '{relativePath}' 被拒绝 What it means
Thrown by FileAccessBridge.ReadFile when the resolved full path is not inside the configured allowed directory (IsPathAllowed returns false). This is the webview-facing sandbox guard preventing scripts from reading arbitrary files via the bridge.
Source
Thrown at BetterGenshinImpact/Core/Script/WebView/FileAccessBridge.cs:62
try
{
var fullPath = Path.GetFullPath(path);
var normalizedPath = fullPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
return normalizedPath.StartsWith(_normalizedAllowedPath, StringComparison.OrdinalIgnoreCase);
}
catch
{
return false;
}
}
public string ReadFile(string relativePath)
{
try
{
var fullPath = Path.Combine(_allowedDirectory, relativePath);
if (!IsPathAllowed(fullPath))
throw new UnauthorizedAccessException($"访问路径 '{relativePath}' 被拒绝");
if (!File.Exists(fullPath))
throw new FileNotFoundException($"文件 '{relativePath}' 不存在");
return File.ReadAllText(fullPath, Encoding.UTF8);
}
catch (Exception ex)
{
throw new Exception($"读取文件失败: {ex.Message}");
}
}
public void WriteFile(string relativePath, string content)
{
try
{
var fullPath = Path.Combine(_allowedDirectory, relativePath);
if (!IsPathAllowed(fullPath))View on GitHub (pinned to a7cb36712d)
Solutions
- Ensure webview callers pass strictly relative paths within the allowed directory; strip leading separators and '..' segments at the JS boundary.
- Strengthen IsPathAllowed with a trailing-separator check to prevent prefix collisions (see error 134).
- If the allowed directory moved, reconstruct FileAccessBridge with the new path.
- Log the offending relativePath and resolved fullPath when denied, for auditing.
Example fix
// before
private bool IsPathAllowed(string path)
{
try
{
var fullPath = Path.GetFullPath(path);
var normalizedPath = fullPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
return normalizedPath.StartsWith(_normalizedAllowedPath, StringComparison.OrdinalIgnoreCase);
}
catch { return false; }
}
// after (trailing-separator containment)
private bool IsPathAllowed(string path)
{
try
{
var fullPath = Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
+ Path.DirectorySeparatorChar;
var root = _normalizedAllowedPath + Path.DirectorySeparatorChar;
return fullPath.StartsWith(root, StringComparison.OrdinalIgnoreCase);
}
catch { return false; }
} Defensive patterns
Strategy: validation
Validate before calling
// Harden the sandbox check before calling ReadFile
relativePath = relativePath.Replace('\\', '/').TrimStart('/');
if (relativePath.Contains(".."))
throw new UnauthorizedAccessException("路径含 .. 段"); Type guard
static bool IsPathWithinAllowed(string allowedRoot, string fullPath)
{
var root = allowedRoot.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
+ Path.DirectorySeparatorChar;
return fullPath.StartsWith(root, StringComparison.OrdinalIgnoreCase);
} Try / catch
catch (UnauthorizedAccessException ex) when (ex.Message.Contains("被拒绝"))
{
_logger.LogWarning("WebView 沙箱拒绝读取: {Msg}", ex.Message);
throw;
} Prevention
- Sanitize relativePath at the JS boundary (strip '..', leading separators).
- Use trailing-separator containment in IsPathAllowed.
- Audit denied reads by logging the resolved path.
When it happens
Trigger: ReadFile(relativePath) computes Path.Combine(_allowedDirectory, relativePath); IsPathAllowed(fullPath) normalizes and checks StartsWith(_normalizedAllowedPath). If false, it throws UnauthorizedAccessException — path traversal attempt or absolute path that escapes the sandbox.
Common situations: A webview script passes '../../something' or an absolute path; relativePath uses '..' to leave the allowed dir; the allowed dir was moved/renamed since the bridge was constructed; case/prefix mismatch (the StartsWith check is OrdinalIgnoreCase so case is fine, but a sibling dir prefix collision can occur).
Related errors
- 文件路径 '{path}' 越界访问!
- 当前JS脚本不允许使用HTTP请求,请在调度器通用设置中启用“JS HTTP权限”
- 文件 '{relativePath}' 不存在
- 不被 Locator 支持的识别类型: {RecognitionObject.RecognitionType}
- 当前JS脚本没有配置允许请求的URL,请在脚本的manifest.json中配置http_allowed_urls
AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13).
Data as JSON: /api/errors/8e42a195df90d112.
Report an issue: GitHub.