Skip to content

fix(http): honor X-Forwarded-Prefix when proxy strips the prefix#9614

Merged
mudler merged 2 commits into
mudler:masterfrom
Dennisadira:fix/x-forwarded-prefix-asset-urls
May 13, 2026
Merged

fix(http): honor X-Forwarded-Prefix when proxy strips the prefix#9614
mudler merged 2 commits into
mudler:masterfrom
Dennisadira:fix/x-forwarded-prefix-asset-urls

Conversation

@Dennisadira
Copy link
Copy Markdown
Contributor

Summary

Closes #9145.

The React UI failed to load when LocalAI was exposed through a reverse proxy that strips the matched path prefix before forwarding (e.g. Caddy's handle_path /localai/*). Two issues combined to break this:

  1. BaseURL ignored X-Forwarded-Prefix when StripPathPrefix had nothing to strip. It only computed a prefix from the request path the middleware had rewritten, so when the proxy already stripped the prefix upstream the base URL came back without one. Extracted a BasePathPrefix(c) helper and added an X-Forwarded-Prefix header fallback so the prefix is recovered in either flow.
  2. Even with <base href> correct, path-absolute references bypass it. Per the HTML spec, URLs starting with / resolve against the base origin, not the base path, so the ="/assets/..." and ="/favicon.svg" references emitted by the build went straight to the origin and bypassed the proxy prefix. serveIndex now rewrites those references to include the prefix when one is present.

Test plan

  • go test ./core/http/middleware/... — 19/19 specs pass, including new BaseURL cases for the pre-stripped path scenario (with and without trailing slash on the header).
  • New integration test in core/http/app_test.go asserts both <base href> and asset URLs are correct when the prefix arrives only via X-Forwarded-Prefix.
  • Manual verification behind Caddy handle_path with the reproducer from X-Forwarded-Prefix no longer works #9145.

🤖 Generated with Claude Code

Dennisadira and others added 2 commits May 13, 2026 19:34
Closes mudler#9145.

Two related issues kept the React UI from loading when a reverse proxy
rewrites a sub-path with prefix-stripping (e.g. Caddy `handle_path`):

1. `BaseURL` only computed a prefix from the path StripPathPrefix had
   removed, so when the proxy strips the prefix before forwarding, the
   request arrives without it and the base URL was returned without a
   prefix. Extract a `BasePathPrefix` helper and add an
   `X-Forwarded-Prefix` header fallback so the prefix is recovered.
2. `<base href>` only changes how relative URLs resolve; the build
   emits path-absolute references like `/assets/...` and
   `/favicon.svg`, which still resolve against the origin and bypass
   the proxy prefix. Rewrite those references in the served
   `index.html` so the browser requests them through the proxy.

Adds unit coverage for `BaseURL` with a pre-stripped path and an
end-to-end test for the proxy-stripped scenario.

Assisted-by: Claude:claude-opus-4-7
…ePathPrefix

BasePathPrefix consumed X-Forwarded-Prefix directly, so a value the
codebase elsewhere rejects (e.g. "//evil.com") slipped through and was
interpolated into the SPA index.html — both into the path-absolute asset
URL rewrite in serveIndex (turning "/assets/..." into "//evil.com/assets/...",
a protocol-relative URL that loads JS from a foreign origin) and into
<base href>. Route the header through the existing SafeForwardedPrefix
validator that StripPathPrefix and prefixRedirect already use, and
HTML-escape the prefix before injecting it into the asset rewrite as
defense in depth against attribute breakout.

Tests cover //evil.com, backslashes, control chars, CR/LF and a missing
leading slash; the integration test asserts an unsafe prefix can't poison
asset URLs.

Signed-off-by: Ettore Di Giacinto <[email protected]>
Assisted-by: claude-code:claude-opus-4-7-1m [Read] [Edit] [Bash]
@mudler mudler force-pushed the fix/x-forwarded-prefix-asset-urls branch from 8cce6da to 348557a Compare May 13, 2026 19:39
@mudler mudler merged commit c2fe0a6 into mudler:master May 13, 2026
54 checks passed
@mudler mudler added the bug Something isn't working label May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

X-Forwarded-Prefix no longer works

2 participants