Skip to content

fix(roles): degrade instead of 500 when the roles header is absent - #1605

Open
azuretek wants to merge 1 commit into
linuxserver:2.xfrom
azuretek:fix/roles-header-missing-500
Open

fix(roles): degrade instead of 500 when the roles header is absent#1605
azuretek wants to merge 1 commit into
linuxserver:2.xfrom
azuretek:fix/roles-header-missing-500

Conversation

@azuretek

@azuretek azuretek commented Sep 8, 2026

Copy link
Copy Markdown

Fixes #1604.

Problem

In roles mode AppServiceProvider reads $_SERVER[config('app.auth_roles_http_header')] with no guard, inside a view()->composer('*') callback. Any request that arrives without the roles header returns HTTP 500, and because the composer is registered against every view, no page renders at all. A container healthcheck, a probe on the published port, or a request made before the proxy is configured each produce:

ErrorException: Undefined array key "HTTP_X_TOKEN_USER_ROLES"
at app/Providers/AppServiceProvider.php:95

Change

Coalesce the header to an empty string before splitting it. That fails closed on the in_array immediately below: an absent header is no roles, never the admin role.

ItemController::dash() reads the same header through the request object, which returns null instead of throwing, so it does not fatal, but it then passes null to explode(), deprecated as a string argument since PHP 8.1. Same coalesce there.

The long line is wrapped as a side effect, which drops one file from the phpcs report.

Test

tests/Feature/RolesHeaderMissingTest.php, 4 cases: the page renders, it fails closed on admin controls, it shows no tiles, and the admin role still works when the header is present.

On 2.x without the change, 3 of the 4 fail with the production error, and the case that supplies the header passes:

   FAIL  Tests\Feature\RolesHeaderMissingTest
  ⨯ dash still renders when the roles header is absent
  ⨯ a request without the roles header gets no admin controls
  ⨯ a request without the roles header gets no dashboard tiles
  ✓ the admin role is still honoured when the header is present

  ErrorException: Undefined array key "HTTP_X_ROLES" in app/Providers/AppServiceProvider.php:95
  Tests:    3 failed, 1 passed

With the change, all 4 pass.

Suite and linter, php artisan test and ./vendor/bin/phpcs --report=summary:

2.x this branch
tests 152 passed, 1 skipped, 362 assertions 156 passed, 1 skipped, 369 assertions
phpcs 16 errors, 9 warnings, 8 files 16 errors, 9 warnings, 7 files

The 4 added tests are the whole test difference. The phpcs count is unchanged; the file count drops by one because the wrapped line no longer exceeds 120 characters.

Live verification

Built as an overlay on the stock linuxserver/heimdall image we run and A/B'd against a copy of our live config:

probe stock patched
GET / with no roles header 500 200
GET / as the admin role 200, controls shown 200, controls shown

The view composer reads $_SERVER[AUTH_ROLES_HTTP_HEADER] unguarded, so
any request that reaches Heimdall without passing through the reverse
proxy returns a 500 rather than a dashboard. That covers a container
healthcheck, a probe on the published port, and the window before the
proxy is configured. Every view goes through this composer, so no page
renders at all:

  ErrorException: Undefined array key "HTTP_X_TOKEN_USER_ROLES"
  at app/Providers/AppServiceProvider.php:95

Coalesce the missing header to an empty string, which fails closed on
the admin check that follows. Do the same in ItemController::dash(),
where the header is passed straight to explode() and null has been
deprecated as a string argument since PHP 8.1.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

Roles mode returns 500 for any request that arrives without the roles header

2 participants