Skip to content

[beta] [flutter_tools] Contain web asset server path resolution to its search roots - #195201

Merged
auto-submit[bot] merged 2 commits into
flutter:flutter-3.50-candidate.0from
mdebbar:cherry-pick-194064-to-beta
Oct 26, 2026
Merged

auto-submit[bot] merged 2 commits into
flutter:flutter-3.50-candidate.0from
mdebbar:cherry-pick-194064-to-beta

Conversation

@mdebbar

@mdebbar mdebbar commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Cherry-pick of #194064 to beta (flutter-3.50-candidate.0).

Impact Description:

Tightens how the web development server in flutter_tools maps request paths to files, so every lookup stays within the directory it is meant to serve from. It also stops some malformed request paths from throwing out of the request handler.

This only affects development with flutter run on web, not deployed apps.

Changelog Description:

#194064 When running a web app with flutter run, the development server resolves some request paths incorrectly.

Workaround:

None.

Risk:

What is the risk level of this cherry-pick?

  • Low
  • Medium
  • High

Test Coverage:

Are you confident that your fix is well-tested by automated tests?

  • Yes
  • No

Validation Steps:

In packages/flutter_tools, run test/general.shard/web/devfs_web_test.dart and test/general.shard/web/web_asset_server_test.dart. All tests pass on this branch, and the new tests fail without the fix.

Note: web_asset_server.dart needed a small manual merge because #194053 isn't on the 3.50 branch. The logic is the same as on master.

…h roots (flutter#194064)

`flutter_tools`' web asset servers resolve the incoming request path
against each of their search roots with `Uri.resolve`. That treats the
request path as a URI *reference* rather than as a path, and a reference
carrying a scheme, an authority or an absolute path replaces the base
instead of resolving below it. The result of a lookup is therefore not
guaranteed to be inside the root that was being searched, and nothing
downstream checks that it is.

This PR makes the containment explicit instead of relying on the shape
of the request path.

Two helpers are added to `web_server_utilities.dart`:

* `isRelativeRequestPath` rejects a request path that is not a relative
reference: one with a scheme or a Windows drive letter in its first
segment, an authority, an absolute path, a backslash, or a NUL.
* `resolveRequestPathUnder` resolves against a given root and returns
the result only when it lands inside that root, compared with
`path.isWithin` so the comparison is per-component and case-insensitive
on Windows.

Every `resolve()` call in `ReleaseAssetServer.handle` and
`WebAssetServer.handleRequest` now goes through the helper, so each
search root keeps its own boundary: the canvaskit fallback, the built
asset fallback, the project `web` directory, and the roots consulted by
`_resolveDartFile`. `.` and `..` segments are deliberately still
accepted and handled by the containment check, so a request path that
normalizes back inside the root keeps working. A
`/packages/<package>/<path>` request is resolved the same way below that
package's `packageUriRoot`, looked up by name, instead of through a
`package:` URI built from the request segments. `ReleaseAssetServer`
checks a root's allowed extensions against the request path before
resolving it, so regular asset requests skip resolution for the
source-map-only roots.

This also keeps exceptions from escaping the handler. On `master` today,
`GET /..%2F..%2F..%2Ftmp/foo` throws `UnsupportedError: Illegal path
character` out of `toFilePath`, because the decoded segment contains a
separator and so names no file path at all. Likewise `GET
/packages/foo.dart` throws an `ArgumentError` out of
`PackageConfig.resolve`. Both are now answered like any other path that
does not resolve inside a root.

`ReleaseAssetServer does not serve files outside of the project` is
extended with the reference shapes that resolve outside a search root,
and `WebAssetServer does not serve files outside of the project` is
added as the debug-handler equivalent, including `dartSourceContents`
and `/packages/` requests with an absolute path or nothing after the
package name. Both fail against unmodified `lib/` and pass with the
change. Positive tests cover a package path with a dot segment that
stays inside the package root, and nested build output paths, including
an asset name containing a colon in a later segment, which stays valid
in a relative reference and must keep working.

`dart analyze` and `dart format` are clean on the five touched files.
Rebased on current `master`; locally both web suites
(`devfs_web_test.dart`, `web_asset_server_test.dart`) pass in full, 84
tests. The 4 failures I mentioned in an earlier version of this
description came from running them without `FLUTTER_ROOT` set.

There is no public issue tracking this; it came out of maintainer
feedback rather than a filed report. Happy to open one if the process
needs the link.

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant in-code documentation (doc comments with
`///`).
- [x] If this PR introduces a new feature or capability, I created and
linked a website documentation issue or PR in [flutter/website] (or
verified none is needed).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[flutter/website]: https://github.com/flutter/website
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
@mdebbar mdebbar added the cp: review Cherry-picks in the review queue label Oct 23, 2026
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Oct 23, 2026
@flutter-dashboard

Copy link
Copy Markdown

This pull request was opened from and to a release candidate branch. This should only be done as part of the official Flutter release process. If you are attempting to make a regular contribution to the Flutter project, please close this PR and follow the instructions at Tree Hygiene for detailed instructions on contributing to Flutter.

Reviewers: Use caution before merging pull requests to release branches. Ensure the proper procedure has been followed.

@github-actions github-actions Bot added the tool Affects the "flutter" command-line tool. See also t: labels. label Oct 23, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces path traversal defenses in the Flutter web asset servers (ReleaseAssetServer and WebAssetServer) by adding utility functions isRelativeRequestPath and resolveRequestPathUnder to validate request paths and ensure resolved file paths reside strictly within their designated root directories. The asset servers are updated to use these utilities when resolving canvaskit, assets, packages, SDKs, and source maps, and extensive tests are added to verify that files outside the project roots are not served. I have no feedback to provide as there are no review comments to evaluate.

reidbaker
reidbaker previously approved these changes Oct 26, 2026
@reidbaker reidbaker added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 26, 2026
@auto-submit
auto-submit Bot merged commit 6630731 into flutter:flutter-3.50-candidate.0 Oct 26, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD cp: review Cherry-picks in the review queue tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants