Skip to content

Conversation

benmosher
Copy link

@benmosher benmosher commented Oct 15, 2025

Summary

Hello! I am using Starlette (under FastAPI) to serve some untrusted directories from disk, and as such I have intentional file opening logic that ensures files are not served from outside the untrusted directory. It's similar to the common path check in StaticFiles, but checking the path then opening the file is at risk of TOCTOU attack if a symlink is injected into the path between validation and opening (e.g. either pathsend or the file open within FileResponse). It's a tight squeeze, but definitely possible when the filesystem is writeable, especially by untrusted entities (aka users 😁).

As such, I currently have my own internal adapted version of FileResponse that accepts an open IO[bytes] which was securely opened without any symlink following.

I just wanted to open this draft to see if you would be amenable to a change like this. (happy to add tests if we can arrive at an acceptable approach through discussion!)

Alternative I considered were:

  • path gains a third IO[bytes] type option -- this muddles the implementation IMO
  • opener: Callable[[str | os.PathLike[str]], Awaitable[anyio.AsyncFile]] -- more confusing, muddles exception handling IMO

I am fine to keep rolling with my own internal version, but wondered if this might be generally useful to others. It could also be used in combination with changes to StaticFiles to close that TOCTOU symlink gap (though since StaticFiles is read-only, may not be useful).

Checklist

  • I understand that this PR may be closed in case there was no previous discussion. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant