fix(@angular/build): skip HTML fallback for dotfile requests#32774
fix(@angular/build): skip HTML fallback for dotfile requests#32774instantraaamen wants to merge 2 commits intoangular:mainfrom
Conversation
The HTML fallback middleware currently rewrites dotfile requests (e.g., /.env, /.npmrc) to /index.html, returning 200 instead of 404. This change skips the SPA fallback when the last URL path segment starts with a dot, providing a small defense-in-depth improvement for the dev server. Made-with: Cursor
There was a problem hiding this comment.
Code Review
This pull request enhances security by preventing the dev server from serving index.html for requests to dotfiles (e.g., /.env). The change correctly identifies such requests and skips the HTML fallback, resulting in a 404 response instead of a 200. The implementation is sound, but I've suggested a minor improvement to make the logic for extracting the filename from the URL path more robust by using the standard path module, which also handles edge cases like trailing slashes correctly.
| if (req.url) { | ||
| // No fallback for dotfile requests (e.g., .env, .npmrc) | ||
| const pathname = req.url.split('?')[0]; | ||
| const lastSegment = pathname.substring(pathname.lastIndexOf('/') + 1); |
There was a problem hiding this comment.
For improved readability and robustness, consider using path.posix.basename to extract the last segment of the URL path. This is more declarative than manual string manipulation.
It also correctly handles paths with trailing slashes. For example, with the current implementation, a request for /.env/ would result in an empty lastSegment and would not be blocked. path.posix.basename('/.env/') correctly returns .env, ensuring such requests are also handled as intended.
You would need to add the following import at the top of the file:
import { basename } from 'node:path/posix';| const lastSegment = pathname.substring(pathname.lastIndexOf('/') + 1); | |
| const lastSegment = basename(pathname); |
Apply Gemini Code Assist suggestion: use basename from node:path/posix instead of manual string manipulation. This is more readable and correctly handles trailing slashes (e.g., /.env/ -> .env). Made-with: Cursor
Description
Currently, the Angular dev server's HTML fallback middleware rewrites requests for dotfiles (such as
/.env,/.npmrc,/.htpasswd) to/index.htmland returns a200 OKresponse. This happens becausepath.extname()treats leading-dot filenames as extensionless (e.g.,extname('.env')returns''), solookupMimeTypeFromRequestreturnsundefinedand these requests fall through the existing MIME type check to the SPA fallback logic.While the actual file contents are not leaked (the response body is the Angular app's
index.html), returning200for sensitive dotfiles is not ideal. Explicitly skipping the SPA fallback for dotfile requests would be a small defense-in-depth improvement, especially when the dev server is exposed to the network via--host.This PR adds a check in
angularHtmlFallbackMiddlewareto skip the HTML fallback for requests where the last path segment starts with.(e.g.,/.env,/.npmrc). The check usesurl.split('?')[0], which is the same pattern already used internally bylookupMimeTypeFromRequest. Instead of rewriting to/index.html, these requests are passed tonext(), which will result in a404from downstream middleware.Motivation
I noticed this behavior while researching how various frameworks handle sensitive file access on their dev servers. The Angular dev server already has good protection through its strict
server.fs.allowconfiguration, but adding this small check makes the behavior more explicit and prevents dotfile URLs from being silently rewritten toindex.html.Changes
html-fallback-middleware.ts: Added a dotfile check at the top of theif (req.url)block, before the MIME type check. Requests for paths whose last segment starts with.(e.g.,/.env) are no longer rewritten to/index.html.Before
After
Normal Angular routes continue to work as expected (e.g.,
GET /dashboard→200withindex.html).Made with Cursor