bevyengine / bevyengine/bevy

`UnapprovedPathMode` has loopholes

Open
#23,659 1 comment 0 reactions 0 assignees View on GitHub
A-Assets C-Bug S-Needs-Design
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version and features

53ddd5e615ae15ad796b36724ddd67516bec0c84 (2026/04/03)

## Problem

The asset system can deny access to absolute paths, and relative paths containing `..` and `.`. See [UnapprovedPathMode](https://docs.rs/bevy/latest/bevy/asset/enum.UnapprovedPathMode.html)

This works for `AssetServer::load` and similar - they end up calling `AssetServer::load_with_meta_transform` which does a `AssetPath::is_unapproved` check ([source](https://github.com/bevyengine/bevy/blob/a66cedd6c3ca729530a8a0e4128b41deada99f58/crates/bevy_asset/src/server/mod.rs#L512))

But there's a bunch of load functions that don't do any checks:

- `AssetServer::load_erased`
- `AssetServer::load_untyped`
- `AssetServer::load_untyped_async`
- `AssetServer::load_unknown_type_with_meta_transform`
- `LoadContext::read_asset_bytes`

There's also problems with `NestedLoader`, which is used to load assets within loaders. First, it doesn't inherit the override flag from `load_override` and similar, so `UnapprovedPathMode::Deny` is broken - loads will be falsely rejected. Second, various paths either have no checks or incorrect checks:

- Deferred:
- `should_load_dependencies = true`,
- Static typed.
- Forbid works, but Deny is broken as `NestedLoader<'_, '_, StaticTyped, Deferred>::load` calls `load_with_meta_transform` with `override_unapproved` hard coded to `true`.
- Dynamic and unknown typed.
- Calls `AssetServer::load_erased_with_meta_transform/load_unknown_type_with_meta_transform`, which should do the check (but currently doesn't).
- `should_load_dependencies = false`.
- Calls `get_or_create_path_handle` which doesn't do any checks.
- Immediate:
- No checks.

## Solution?

I started working on some unit tests and fixes - branch [here](https://github.com/bevyengine/bevy/compare/main...greeble-dev:bevy:nested-loader-unapproved-paths). But I've hit pause due to some issues.

First, while most of the problems can be solved with more plumbing and checks, I'm not so sure about `load_override` semantics and `NestedLoader`. Is it actually correct to inherit the parent override? Is this transitive to all dependencies and immediate loads? How does this get routed through the system?

Second, maybe the checks are in the wrong place? Currently they're in `AssetServer`. But what if the checks were in `AssetSource` instead? So `AssetPlugin::unapproved_path_mode` would go away - instead individual asset sources would have their own parameter.

This has some upsides:

- Somewhat centralizes the checks.
- They do get duplicated across sources, but it's harder to miss a check elsewhere since almost everything goes through the source eventually.
- One flaw is `get_or_create_path_handle`, which doesn't go through the source.
- Makes the `AssetServer` less dependent on `Path` and OS specific quirks.
- `AssetSource` becomes the authority for what paths actually mean (#19079).
- Would allow more complex handling, like disallowing problematic unicode in URLs.
- Different sources can have different settings.
- Not sure if this is actually a good thing, but worth exploring?
- Might also remove the need for `UnapprovedPathMode::Deny` and the `NestedLoader` override inheritance.
- The user can map the same path as two different sources with different approvals.
- So instead of calling `load_override("path")` they call `load("my_unapproved_source://path")`.

The big downside is ergonomics. Instead of setting a single `AssetPlugin::unapproved_path_mode`, the user has to set it on each source.

So I'm not sure about solutions, but I can make a PR with failing unit tests if desired.

Contributor guide

Open the contributing guide

Research direction

Start with the AssetServer load methods and crates/bevy_asset/src/server/mod.rs around the is_unapproved check, then trace NestedLoader and the listed dependency-loading paths. Review the unit tests and fixes on the linked nested-loader branch. Done requires agreed load_override and AssetSource semantics plus coverage showing that every listed path handles unapproved paths consistently.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
game-dev, security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.