fix(security): restrict dev asset bridge, electron navigation, and secret file access - #1
Closed
devin-ai-integration[bot] wants to merge 1 commit into
Closed
Conversation
…cret file access Reject non-loopback callers on the dev asset bridge, keep the Electron renderer on its own document, add a Tauri CSP, and store launcher API keys owner-only. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Security scan of the repo found four issues worth fixing; the dev asset bridge is the significant one.
1. Dev asset bridge was an unauthenticated local file-read API with wildcard CORS (
src-tauri/src/dev_asset_bridge.rs). It serves/load-text-asset?rootPath=…&assetPath=…,/load-image-data-url?path=…, etc. from arbitrary caller-supplied paths and answered every request withAccess-Control-Allow-Origin: *, so any page the developer visited could read local files throughhttp://127.0.0.1:5187, andMODFORGE_EVENT_ASSET_BRIDGE_ADDRcould put it on a routable interface. Now:The
Hostcheck is what blocks DNS rebinding (evil.example→127.0.0.1); theOrigincheck blocks a plain cross-origin read from a remote page. A missingOrigin(curl, non-browser) is allowed, matching prior local-tooling behavior.2. Electron renderer could navigate anywhere while holding the privileged preload bridge (
electron/main.ts).preload.cjsexposesinvokeCommand(command, args)plus dialogs and amodforge-asset://local/<abs path>protocol that reads any absolute path, andipcMainhandlers do not check the sender — so a navigation to a remote page (mod link, redirect) would have inherited all of it. Newelectron/navigation-policy.ts+ wiring keeps the renderer on its own document, sendshttp(s)targets to the system browser, and denieswebviewattachment:openInSystemBrowseronly forwardshttp:/https:, sojavascript:/file:/modforge-asset:targets are dropped rather than handed toshell.openExternal.3.
tauri.conf.jsonhad"csp": null, i.e. no CSP for the Tauri host. Set a policy that keepsscript-srcto'self', allowsasset:/data:/blob:images andipc:connections, and blocksobject-src/frame-src/form-action. Worth a sanity check in a packaged Windows/macOS build — I can only run the Electron host on Linux, so this policy is reviewed but not runtime-verified.4. Launcher settings hold the Nexus API key in plaintext with default permissions. AI provider keys already go to the OS keyring, but
launcher-settings.jsonkeepsnexusApiKeyon disk, previously world-readable.write_secret_file(new,infrastructure/fs/secret_file.rs) writes it and then chmods to0600on Unix, no-op on Windows.Also scanned, no change needed
rusqlitequeries inlocalization/usage.rsandknowledge/store.rsbuildWHEREclauses from static column literals with?placeholders andparams_from_iter; facets are matched against an allowlist. No user data reaches SQL text."nexus-key","secret-marker"). Launcher logs recordapiKeyPresentflags, not values.sanitize_archive_entry_pathrejects absolute and..components for zip/tar/7z/rar;open_launcher_url_in_browserallows onlyhttp/https;NexusModsBbcode.sanitizeUrlallows onlyhttp/httpsplus restricted image data URIs.pnpm auditreports 28 advisories (9 high), but every finding is a dev-only transitive — the vulnerableelectron@23.3.13isreact-devtools' own copy, not the shippedelectron@^43; the rest areelectron-builder/tailwind-lint/vite-plussubtrees (brace-expansion,postcss,tar,fast-uri,cross-spawn,got,esbuild). Fixing them means overriding transitives across major lines (e.g.brace-expansion1.x/2.x → 5.0.8, published today), so I left the lockfile alone rather than risk the toolchain for non-shipped code.Follow-ups not taken here
ipcMainhandlers still trust any sender; with navigation locked down this is defense-in-depth, but asenderFrame/command-allowlist check would close it properly.modforge-asset://local/…reads any absolute path; scoping it to the game/app data roots would remove the primitive entirely.nexusApiKeyto the keyring (like AI keys) would beat file permissions, but needs a migration.sandbox: falseon the mainBrowserWindow.Validation
cargo fmt+cargo check --all-features: clean (one pre-existingunused import: Contextwarning ininfrastructure/shell.rs).cargo test --lib dev_asset_bridge(5),secret_file_tests(3), launchersettings_tests(5): pass.vp test run electronNavigationPolicy(3): pass.vp lint .: 0 errors (2 pre-existing warnings).vp fmt --check: clean.tsc -p tsconfig.electron.jsonandtsconfig.app.json: clean.Link to Devin session: https://app.devin.ai/sessions/f8f86045ce3a43a1a372bd7b205b411e
Requested by: @Arborsm