Constants
CAKEPHP_PATTERNS = [{/\$this->Authentication->/, "CakePHP Authentication component"}, {/\$this->Authorization->authorize/, "CakePHP Authorization"}, {/\$this->loadComponent\s*\(\s*['"]Authentication['"]/, "CakePHP Authentication component"}]
GENERIC_PATTERNS = [{/(?:isset|empty|!\s*isset)\s*\(\s*\$_
SESSION\s*\[\s*['"]user/, "
PHP session user guard"}, {/\$_
SERVER\[['"]
PHP_AUTH_USER['"]/, "
PHP HTTP Basic Auth"}]
Generic PHP auth patterns
LARAVEL_AUTH_CHECKS = [{/Gate::allows\s*\(/, "Laravel Gate authorization"}, {/Gate::authorize\s*\(/, "Laravel Gate authorization"}, {/\$this->authorize\s*\(/, "Laravel Policy authorization"}, {/auth\(\)->check\(\)/, "Laravel auth check"}, {/Auth::check\(\)/, "Laravel Auth::check"}, {/\$request->user\(\)/, "Laravel request user check"}]
Laravel Gate/Policy checks in action body
LARAVEL_CONTROLLER_MIDDLEWARE = [{/\$this->middleware\s*\(\s*['"]auth['"]/, "Laravel controller auth middleware"}, {/\$this->middleware\s*\(\s*['"]auth:/, "Laravel controller auth middleware"}, {/\$this->authorizeResource\s*\(/, "Laravel authorizeResource"}]
Laravel controller middleware
LARAVEL_GROUP_MIDDLEWARE = /['"]middleware['"]\s*=>\s*(?:\[[^\]]*?)?['"](?:auth(?::[\w,]+)?|verified)['"]/
LARAVEL_GROUP_OPEN = /(?:->|::)group\s*\(\s*(?:\[(?:[^\[\]]|\[[^\]]*\])*\]\s*,\s*)?(?:static\s+)?(?:function|fn)\b/
Route::middleware('auth')->group(function () { ... }) and the older
Route::group(['middleware' => 'auth'], function () { ... }): every route
declared inside the closure inherits the middleware. Breeze's
routes/web.php and routes/auth.php are built this way. The middleware value
is one string or one bracketed list; the match must not run past it into
later keys ('middleware' => 'guest', 'prefix' => 'auth').
LARAVEL_ROUTE_MIDDLEWARE = [{/(?:->|::)middleware\s*\(\s*['"]auth['"]/, "Laravel auth middleware"}, {/(?:->|::)middleware\s*\(\s*['"]auth:api['"]/, "Laravel auth:api middleware"}, {/(?:->|::)middleware\s*\(\s*['"]auth:sanctum['"]/, "Laravel Sanctum auth"}, {/(?:->|::)middleware\s*\(\s*['"]auth:web['"]/, "Laravel web auth"}, {/(?:->|::)middleware\s*\(\s*['"]verified['"]/, "Laravel verified middleware"}, {/(?:->|::)middleware\s*\(\s*\[[^\]]*['"]auth['"]/, "Laravel auth middleware"}, {/(?:->|::)middleware\s*\(\s*\[[^\]]*['"]auth:[\w,]+['"]/, "Laravel auth middleware"}]
Laravel middleware patterns.
(?:->|::) so the leading form is recognized too: Route::middleware('auth') ->get('/x', …) is as common as the chained ->middleware('auth'), and
only the chained one used to match. That gap was invisible while the
±3-line window happened to reach the previous route's ->middleware(…)
— a route tagged correctly by accident is still a tagger that cannot read
the form in front of it.
LARAVEL_WITHOUT_AUTH = [{/->withoutMiddleware\s*\(\s*(?:\[[^\]]*)?['"]auth(?::[\w,]+)?['"]/, ""}]
Route::get(...)->withoutMiddleware('auth'): the route opts out of the
auth middleware its group applies.
SLIM_YII_CI_PATTERNS = [{/\->add\s*\(\s*['"]?auth/i, "Slim auth middleware"}, {/\bAuthorization\b.*header/i, "Slim Authorization header check"}, {/\bAccessControl\b/, "Yii AccessControl filter"}, {/\bAuthMethod\b/, "Yii AuthMethod"}, {/\bHttpBearerAuth\b/, "Yii HttpBearerAuth"}, {/\bCompositeAuth\b/, "Yii CompositeAuth"}, {/\bbeforeAction\b.*auth/i, "Yii beforeAction auth"}, {/->before\s*\(\s*['"]?auth/i, "CodeIgniter before auth filter"}, {/\$this->beforeFilter/i, "CodeIgniter beforeFilter"}, {/\bauthFilter\b/i, "CodeIgniter authFilter"}]
Slim / Yii / CodeIgniter additional patterns
STATEMENT_BOUNDARY = /(?:Route|Router)::(?:get|post|put|patch|delete|options|head|any|query|match|addRoute|resource|apiResource)\s*\(|\$\w+\s*->\s*(?:get|post|put|patch|delete|options|head|any|query|map|group)\s*\(\s*['"]\/|\bfunction\s+\w+\s*\(/i
A line that starts a different route or method than the one being
inspected: Route::get('/x', …), $app->post('/x', …), Route::resource,
a named function foo( declaration. Anonymous closures (function () {)
are deliberately excluded — those are part of the current route statement.
Every window this tagger scans is bounded by it. A fixed ±N-line window is
not a statement: two one-line routes stacked on top of each other put the
second's ->middleware('auth') inside the first's window, and the public
route came back tagged as protected.
The $app->get(…) form requires a path literal starting with / so that
an ordinary body call — $request->get('id') — is not mistaken for the
start of the next route and does not cut a scan short.
SYMFONY_NOT_PUBLIC = (/(?!\s*(?:attribute\s*:\s*)?(?:['"]|\\?[\w\\]+::)(?:PUBLIC_ACCESS|IS_AUTHENTICATED_ANONYMOUSLY)\b)/).source
IsGranted('PUBLIC_ACCESS') (and the pre-5.1 IS_AUTHENTICATED_ANONYMOUSLY)
grants every caller, so it is not a guard.
SYMFONY_PATTERNS = [{/#\[IsGranted\s*\(#{SYMFONY_NOT_PUBLIC}/, "Symfony #[IsGranted]"}, {/#\[Security\s*\(\s*(?:expression\s*:\s*)?['"]/, "Symfony #[Security]"}, {/@Security\s*\(\s*['"]/, "Symfony @Security annotation"}, {/@IsGranted\s*\(#{SYMFONY_NOT_PUBLIC}/, "Symfony @IsGranted annotation"}, {/\$this->denyAccessUnlessGranted\s*\(/, "Symfony denyAccessUnlessGranted"}, {/\$this->isGranted\s*\(/, "Symfony isGranted check"}]
Symfony security attributes/annotations