Skip to content

Broken Access Control in AI OpenRouter Gateway: CVE Research

Created November 6, 2026 • Last updated November 7, 2026 • 5 min read • 129 views

Joshua

HackIndex Creator

CWE-862 Missing Authorization

AI OpenRouter Gateway, a Laravel and Filament package, ships a documented config option to restrict who may reach its admin UI. The option is read from the environment into config and never consumed anywhere, so the gate does nothing. Every authenticated Filament panel user, regardless of role, can reach the full gateway UI: mint API tokens, change system prompts, models and runtime settings, and read all invocation telemetry. Found during a HackIndex audit of open source Laravel packages.

Summary of the AI Gateway Authorization Issue

The package exposes its admin UI through a Filament plugin: an integration registry, two settings pages, a token manager, an invocation log and an API docs page. Its config advertises a single switch, filament.authorize, described as the gate for the whole UI. An operator who reads the config and sets it, exactly as documented, gains no protection. Nothing in the package ever evaluates that value, and the sensitive pages carry no access check of their own. The intended restriction is silently absent.

How the AI Gateway Authorization Bug Works

The config documents a gate for the whole UI

config/ai-gateway.php defines the switch and documents exactly what it is for.

'filament' => [
    'navigation_group' => 'AI & Automation',
    'navigation_sort' => 50,
    'cluster' => null,
    // Gate for the whole UI. A closure/invokable or a Gate ability name.
    // null = visible to anyone who can access the panel.
    'authorize' => env('AI_GATEWAY_FILAMENT_GATE', null),
],

An operator reads this, sets AI_GATEWAY_FILAMENT_GATE=access-ai-gateway, and defines that ability for admins only. The config now holds the ability name. The operator believes the UI is restricted to admins.

Nothing ever reads that value

The plugin that registers the UI never consults filament.authorize. src/Filament/AiGatewayPlugin.php registers the resources and pages and stops there.

public function register(Panel $panel): void
{
    $panel
        ->resources([
            AiIntegrationResource::class,
            AiInvocationResource::class,
        ])
        ->pages([
            GeneralSettings::class,
            ApiTokens::class,
            ApiDocs::class,
        ]);
}

A search across the package finds no read of ai-gateway.filament.authorize anywhere. The value travels from the environment into config and is never used to authorize anything.

The sensitive pages carry no access check

Filament lets a resource or page gate itself with canAccess(). The gateway's sensitive surfaces do not. The token manager, the settings page and the integration registry define no canAccess(), so they inherit Filament's default: any user who can reach the panel can open them. The only page that defines canAccess() is the read-only API docs page, and it checks whether the HTTP API is enabled, not who the user is. The documented role gate is nowhere in that decision.

The result is unrestricted access

Put together: the gate the config promises does not exist, and the pages have no fallback guard. Every authenticated panel user reaches every gateway page. On a site with more than one staff role, a low-privilege user who can sign into the panel for any unrelated reason gains full control of the AI gateway.

Who can do this

Any user who can authenticate to the Filament panel, whatever their role. No admin rights, no special permission. The precondition is on the application, not the attacker: the site runs the gateway plugin and has more than one class of panel user, which is the exact scenario the authorize gate exists to handle. An operator who set the documented gate is still exposed, because the gate is never enforced.

Proof of Concept

A panel with the plugin installed and the documented gate configured for admins only:

// config: the gate is set exactly as documented
// AI_GATEWAY_FILAMENT_GATE=access-ai-gateway

// AppServiceProvider::boot(), the ability the operator defines
Gate::define('access-ai-gateway', fn (User $user) => $user->is_admin);

Signed in as a non-admin staff user, the gate correctly denies the ability, yet the page grants access:

Gate::forUser($staff)->allows('access-ai-gateway')   // false
ApiTokens::canAccess()                               // true  (as $staff)

The non-admin user opens the AI Gateway navigation group and reaches every page: creates a Sanctum token carrying the gateway invoke ability, edits system prompts and model settings, and reads the full invocation log. The gate returns false and the UI opens anyway.

Tested environment:

  • AI OpenRouter Gateway (andrecorugda/ai-openrouter-gateway), affected through the latest release v2.0.2

  • Laravel Framework 12.71.0

  • Filament 3.3.57

  • PHP 8.5.12

Impact

Broken access control over the entire AI gateway for any authenticated panel user. Such a user can:

  • Mint Sanctum API tokens that carry the gateway invoke ability, then call the HTTP API as if authorized.

  • Change system prompts, model selection and runtime settings, redirecting or poisoning every AI call the application makes.

  • Read all invocation telemetry, including prompts and responses that may contain sensitive data.

The operator who wired the documented gate has no signal that it does nothing, so the exposure sits unnoticed.

Severity Assessment

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N (7.1, High)

Metric

Value

Reason

Attack Vector

Network

The panel is reached over HTTP.

Attack Complexity

Low

Open the page. No conditions to win.

Privileges Required

Low

Any authenticated panel user.

User Interaction

None

No second party needed.

Scope

Unchanged

The gateway UI and the panel share the application's own authorization context.

Confidentiality

Low

Configuration and invocation telemetry become readable.

Integrity

High

System prompts, models and settings can be rewritten, and API tokens minted.

Availability

None

No direct denial of the application itself.

Fix for the AI Gateway Authorization Issue

Enforce the gate the config already documents.

  • In the plugin, read config('ai-gateway.filament.authorize') and apply it. Register the resources and pages behind that ability, or set each page's and resource's canAccess() to evaluate it.

  • Where the value is a Gate ability name, call Gate::allows() with it. Where it is a closure or invokable, call it. Where it is null, keep the documented default of panel-wide visibility.

  • Add a test that a user who fails the ability cannot reach the token, settings and integration pages, so the gate cannot silently regress.

References