laravel-security
Skill2 starsChanged 50 days agoMITView on GitHub
Audits Laravel (PHP) applications for framework-specific vulnerabilities — mass assignment via missing fillable/guarded, SQL injection through DB::raw/whereRaw/orderByRaw concatenation, Blade raw output XSS, CSRF middleware exclusions, committed APP_KEY enabling cookie-forgery RCE chains, APP_DEBUG in production, routes without auth middleware, path traversal in file downloads, and dev tools (debugbar/telescope) in production dependencies. Use when the project has composer.json with laravel/framework, an artisan file, app/Models, or Blade views.
- Reads credentials
19 other projects use a version of this.
Adopted by
Most recently taken up by
- Rojios/everything-claude-codetheir own version, first seen Nov 8, 2026
- cindovahq/security-skillstheir own version, first seen Nov 8, 2026
- renepf/claude-skillstheir own version, first seen Oct 25, 2026
- davidanthonyn/claude-skillstheir own version, first seen Oct 20, 2026
- STIFLEUR390/agent-skillstheir own version, first seen Oct 16, 2026
- gongyijie85/dsh-ecctheir own version, first seen Oct 13, 2026
Used with
Projects with it also use skill-creator.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
SentrySkillskill-creator
Create new agent skills following the Agent Skills specification. Use when asked to "create a skill", "add a new skill", "write a skill", "make a skill", "build a skill", or scaffold a new skill with SKILL.md. Guides through requirements, writing, registration, and verification.
Also in 4 projects that use this
Other versions19 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 19
- loulanyue/awesome-claude-notes★ 272same name
- Fmarzochi/EGC★ 61same name
- pekral/cursor-rules★ 10same name
- gongyijie85/dsh-ecc★ 8same name
- PUPT-Quantum-Leap/capstone-nlcom-volunteer-management-system★ 4same name
- ronmkr/PromptBook★ 2same name
- wakqasahmed/skills★ 2same name
- junimnjw/everything-claude-code★ 1same name
- NISTALTALSON/essential-claude-skills★ 1same name
- Rojios/everything-claude-code★ 1same name
9 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository23 other files it gives its agents.
- android-code-securitySkill
- auth-reviewSkill
- config-hardeningSkill
- container-iac-securitySkill
- course-platform-securitySkill
- crypto-reviewSkill
- cve-researchSkill
- data-exposureSkill
- dependency-vulnsSkill
- design-threat-reviewSkill
- django-securitySkill
- dotnet-securitySkill
- flow-securitySkill
- flutter-securitySkill
- graphql-securitySkill
- injection-flawsSkill
- llm-securitySkill
- mobile-securitySkill
- rails-securitySkill
- secrets-detectionSkill
- security-auditSkill
- skill-forgeSkill
- spring-securitySkill
The file
We split this skill into the rules it gives an agent
1 rule. 0 are common, 0 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 13 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 61
Every {!! !!} with a variable that traces to user input is a finding — then triage by privilege direction, which sets the severity:
“Common” is measured: kept by at least 6 in 10 of the 13 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Laravel Security
Step 0 — Detect
rg -n "laravel/framework" -g 'composer.json' ; ls artisan app routes config 2>/dev/nullRecord Laravel version (composer.json/lock), PHP version, and whether Sanctum/Passport/Fortify are in use.
Step 1 — Config & env (the Laravel RCE chain)
git ls-files | rg -i '(^|/)\.env($|\.)'
rg -n "APP_DEBUG\s*=\s*true|APP_ENV\s*=\s*production" -g '.env*'
rg -n "APP_KEY" -g '.env*' -g 'config/app.php' | head -3- Committed
.env/APP_KEY→ Critical: leaked APP_KEY lets attackers forge encrypted cookies; with older serializable-cookie sessions or queued-job payloads this chains to RCE via PHP deserialization gadgets. Fix: rotate APP_KEY (php artisan key:generate), purge from history, treat all session data as compromised. APP_DEBUG=truewithAPP_ENV=production→ High (stack traces; historically .env disclosure via error pages).config/session.php:secure/http_onlyfalse → Medium;same_sitenull → Medium.
Step 2 — Mass assignment (privilege escalation)
rg -n "fillable|guarded" app/Models/ | head
rg -n "::create\(|::update\(|forceFill|unguard" app/ routes/ | head -20
rg -n "Model::unguard\(true\)|ShouldAutoSize" app/Providers/ 2>/dev/nullFor each model feeding ::create/update with request data:
- No
$fillable/$guarded(both default open-ish;$guarded=[]explicitly wide) +$request->all()/$request->validated()including role-ish columns (is_admin,role,user_id,price) → Critical (attacker self-promotes by addingis_admin=1to the POST). Model::unguard()globally → same finding, repo-wide.- Fix: explicit
$fillableallowlist +$request->only([...])/ typed FormRequests.
Step 3 — SQL injection
rg -n "DB::raw|whereRaw|orderByRaw|selectRaw|havingRaw|DB::select\(|DB::statement\(" app/ routes/- Raw expressions with concatenation/interpolation of request data → Critical
- Query builder with bindings (
where('name', $req->name)) → safe, note as positive orderBy($request->input('sort'))— column names can't be bound; must be allowlisted → Medium/High
Step 4 — Blade XSS
rg -n '\{!!' -g '*.blade.php' .
rg -n '\{!!' -g '*.blade.php' . | wc -l # census FIRST: know the full inventory sizeCensus, don't sample. Glob to *.blade.php — the bare pattern also matches React/TSX aria-invalid={!!…} noise that crowds out real hits. Run wc -l before reading: every raw echo in the inventory gets an explicit disposition (verified-safe / finding / not-assessed). head-truncating this list is how review-moderation XSS ships to production. For repos >50 hits, triage by author privilege first (below), but never leave the tail unexamined.
Every {!! !!} with a variable that traces to user input is a finding — then triage by privilege direction, which sets the severity:
| Author of the raw content | Viewer of the page | Severity |
| Unprivileged (student/customer/guest form: reviews, tickets, messages, submission text, uploaded filenames) | Privileged (admin/moderator/staff) | Critical — fires in the staff origin → session-riding requests → account takeover. Moderation queues guarantee a privileged viewer opens it. |
| Privileged (admin/instructor-authored: descriptions, embeds, templates) | Unprivileged/everyone | High (public) / Medium (authenticated) |
| Same privilege | same | Medium |
Blade's {{ }} escapes; {!! !!} exists only to bypass. nl2br() is NOT an escape — {!! nl2br($x) !!} is a raw echo. Check {{ $x }} + |raw? (Blade has no |raw; Twig confusion = false positive).
Step 5 — CSRF
rg -n "except" app/Http/Middleware/VerifyCsrfToken.php bootstrap/app.php 2>/dev/null
rg -n "withoutMiddleware|WithoutMiddleware" app/ routes/$exceptwith'*'→ High; with real routes → verify the handler is genuinely webhook-only (state-changing → High)- Laravel 11+:
validateCsrfTokens(except: [...))inbootstrap/app.php
Step 6 — Authorization
rg -n "middleware\(" routes/ | head -20
rg -n "Gate::before|Gate::define|policy|authorize\(" app/ | head -20- State-changing/admin routes without
authmiddleware → High Gate::before(fn () => true)unconditional allow → Critical- Policies existing but not auto-discovered + no
authorize()calls in controllers → flag as "authz unmapped" (Medium, needs verification)
Step 7 — Files, uploads, misc
rg -n "response\(\)->download|Storage::(download|get|put)|\->store\(" app/
rg -n "debugbar|telescope|ignition" composer.json composer.lock 2>/dev/null
rg -n "eval\(|unserialize\(|assert\(" app/download(storage_path('app/' . $request->input(...)))→ path traversal, High- Uploads without
validated()mimes/size rules stored on public disk → Medium/High - debugbar/telescope in require (not require-dev) → Medium
unserializeon user data → Critical (with APP_KEY leak = full RCE chain, cross-reference Step 1)
Step 8 — Feature flags & outbound-email amplification
Plan-constrained tenants are authenticated ADMINS whose capability should be plan-gated — menu-level hiding is cosmetic. (Incident class, 2026-09-23 user report: one trial tenant blasted 1200+ emails in ~2 minutes via an ungated compose route + global-default import flag.) The attacker persona is an admin the PLAN should stop, not one auth should stop.
# flag census: every define + its default, then every use site
rg -n "Feature::(define|active|for)" app/ modules/ config/
# which routes actually carry the feature middleware
rg -n "feature:" routes/ modules/ routes/ app/ 2>/dev/null
# email-triggering endpoints and their throttles
rg -n "Route::(get|post)" routes/ modules/ routes/ | rg -i "send-|verif|subscribe|reset"
rg -n "throttle:" routes/ modules/ routes/
# blast fan-out: jobs that load unbounded sets and send per row
rg -n "::query\(\)->get\(\)|::all\(\)" app/ modules/
rg -n "Mail::to\(|Mail::send\(" app/ modules/
# pennant store + whether deploys purge stored values
rg -n "'store'" config/pennant.php
rg -n "pennant:purge" deploy/ scripts/- Flag gated in UI only — flag checked in Blade/menu or inside the JOB, but its routes lack
->middleware('feature:...')→ Critical: the route is the enforcement point; the in-job check is defense-in-depth, not the gate Feature::define('<capability>', true)for import/email/SMS flags defaulting true globally → High (plan gating absent; per-plan closures are the safe shape)- Pennant staleness — database store + no
pennant:purgein any deploy script → Medium: reverting a default does NOT clear stored per-scope values; any scope resolved during a true-default window keeps true until purged - Blast amplification — one request → N outbound emails: a dispatched job loads
Model::query()->get()unbounded and sends per row, no cap, no routethrottle:→ Critical (one request = whole mailing list; attacker-controlled subject/body = phishing from your own domain). Flow class F9,../flow-security/SKILL.md - Public email-triggering endpoints —
send-verification-link-style GET (side effect on a GET!) orsubscribePOST, public, unthrottled, no captcha → Critical (enumerating IDs over a public sender = mail bomb with zero auth) $request->all()into a compose DTO (free-text subject/body) → High (mass assignment + platform-domain phishing)- Safe shapes:
feature:middleware on the route ANDFeature::activere-checked in the job;->limit()recipient cap + per-tenant daily quota consumed ATOMICALLY inside the job (queued jobs outlive flag flips — the quota check must not be check-then-act on the HTTP side); POST + signed URL +throttle:for verification links; FormRequest for compose; verified-recipients-only targeting
Reporting
Severity table above. Fixes are usually short — give exact code (protected $fillable = ['name','email'];, whereRaw('name = ?', [$name])). Cross-reference dependency CVEs via ../dependency-vulns/SKILL.md (composer.lock).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

