# Securing Laravel
> The essential security resource for Laravel developers.
Public Ghost content for AI and LLM tooling. Use `/llms-full.txt` for consolidated page and post context.
Append `.md` to any post or page URL to get the content in Markdown (for example, `/example-post.md`).
## Pages
- [4,000 Subscribers Celebration! π](https://securinglaravel.com/4000.md) - Nice work, you found it! π Since Securing Laravel has just hit 4,000 subscribers, it feels right to give a matching discount on premium subscriptions! I considered 40% off, but percentages are boring and overused. So instead, how about $40 off yearly, or $4 off monthly? Now that you're here, it'sβ¦
- [Welcome to Securing Laravel!](https://securinglaravel.com/about.md) - Hey there, I'm Stephen Rees-Carter, the creator of Securing Laravel. It's awesome to meet you and I want to welcome you to our community! I started Securing Laravel (then called Laravel Security In Depth) back in August 2021 as a way to share my security knowledge with the Laravel community, alongsβ¦
- [Sponsor Securing Laravel](https://securinglaravel.com/sponsor.md) - Want to get your brand in front of thousands of Laravel developers every week, while supporting security education across the Laravel ecosystem? Sponsoring Securing Laravel is the perfect way to do both. Every week* I publish a new Laravel Security Tip, covering a wide range of security topics to hβ¦
- [Start a 7 Day Trial](https://securinglaravel.com/start-a-7-day-trial.md) - Hey there! Due to limitations with this platform, I can't send you to a shiny sales page that offers 7-day trials and lets you pick which billing cycle you'd prefer when the trial ends. So you're stuck with two boring buttons... Start a 7-day trial on monthly billingStart a 7-day trial on yearly biβ¦
- [Stephen Is Uncontactable Sale?! π±](https://securinglaravel.com/stephen-is-uncontactable-sale.md) - I haven't done a sale on Securing Laravel in a while, and I will be disconnected from the internet until Saturday, so now is the perfect time for a sale, right?? I really don't like doing things normally, so this just feels right! π
## Posts
- [Security Tip: Do You Know Your SameSite Cookies?](https://securinglaravel.com/security-tip-do-you-know-your-samesite-cookies.md) - [Tip #133] SameSite=Lax is the Laravel default, and it quietly protects you from CSRF. So why do I keep finding SameSite=None in the apps I audit? Let's talk about what it does and how to use it safely.
- [In Depth: Three Reasonable Decisions, One Critical Vulnerability](https://securinglaravel.com/in-depth-three-reasonable-decisions-one-critical-vulnerability.md) - [In Depth #41] What do you get when you combine an API, SameSite=None, and a Session cookie?
- [Security Tip: Have You Heard Of Slopsquatting?](https://securinglaravel.com/security-tip-have-you-heard-of-slopsquatting.md) - [Tip #132] Your AI agent hallucinates a package name, confidently installs it, and keeps working - except an attacker registered that exact name, packed with malware. Welcome to slopsquatting.
- [Security Tip: Safely Updating Dependencies](https://securinglaravel.com/security-tip-safely-updating-dependencies.md) - [Tip #131] Updating packages used to be a no-brainer, but now you need to be careful. Updates may be malicious. But not updating leaves vulns unpatched. So what do you do??? π€·
- [In Depth: Version Numbers Are Vanity Labels](https://securinglaravel.com/in-depth-version-numbers-are-vanity-labels.md) - [In Depth #40] We trust version numbers to mean a specific, fixed release - but they're really just labels pointing at a commit, and an attacker can quietly move them. Let's dig into tag hijacking, the attack behind tj-actions and Laravel-Lang. π
- [Security Tip: Secure Your Repositories with Laravel Moat](https://securinglaravel.com/security-tip-secure-your-repositories-with-laravel-moat.md) - [Tip #130] Laravel Moat is a new tool that assesses the security posture of your GitHub repositories and recommends ways to tighten the controls protecting them.
- [Security Tip: The Signed URL Trap](https://securinglaravel.com/security-tip-the-signed-url-trap.md) - [Tip #129] I love Signed URLs, but there is one very subtle trap you can accidentally fall into...
- [In Depth: Don't Trust Public Livewire Properties](https://securinglaravel.com/in-depth-dont-trust-public-livewire-properties.md) - [In Depth #39] Public Properties may look like PHP class properties, but they're really hidden form fields, just waiting for your input... π
- [Security Tip: Stop Putting Actions on GET Requests!](https://securinglaravel.com/security-tip-stop-putting-actions-on-get-requests.md) - [Tip #128] Do you know the difference between GET and POST requests, and why it's so important that GET requests only ever retrieve data?
- [Security Tip: Your JWT Might Be a Forever Key!](https://securinglaravel.com/security-tip-your-jwt-might-be-a-forever-key.md) - [Tip #127] Without an `exp` claim, a JWT can remain valid forever, turning a leaked token into permanent access.
- [Security Tip: Validate Config at Boot](https://securinglaravel.com/security-tip-validate-config-at-boot.md) - [Tip #126] Rather than checking for essential config when it's used, throw the checks in your Service Provider - you'll know about configuration failures before your users get a weird error.
- [In Depth: Email Verification Isn't as Simple as You Think](https://securinglaravel.com/in-depth-email-verification-isnt-as-simple-as-you-think.md) - [In Depth #38] You can't trust an email address you haven't verified, so why are you storing them in your database?
- [Security Tip: Consider All Routes, Not Just Web!](https://securinglaravel.com/security-tip-consider-all-routes-not-just-web.md) - [Tip #125] routes/web.php is boring and reliable, and routes/api.php is fancy, but have you forgotten one?
- [Security Tip: Update your packages! (Yes, this again!)](https://securinglaravel.com/security-tip-update-your-packages-yes-this-again.md) - [Tip #124] I know I say this all the time (especially on stage!), but apparently not everyone heard me, so here we go again...
- [Security Tip: How Should APIs Respond to HTTP?](https://securinglaravel.com/security-tip-how-should-apis-respond-to-http.md) - [Tip #123] If an API client tries to connect via unencrypted HTTP, what should your API do: redirect to HTTPS, disable HTTP, offer a swift rebuke, or take matters into it's own hands?
- [Security Tip: Bypassing Content-Security-Policy with !](https://securinglaravel.com/security-tip-bypassing-content-security-policy-with-base.md) - [Tip #122] Content Security Policies are awesome, but if you haven't fully configured all of your directives, it's possible to redirect requests, inherit Nonces, and get juicy CSP-bypassing XSS! π
- [Security Tip: When Is XSS Not Strictly XSS? (But Still Bad!)](https://securinglaravel.com/security-tip-when-is-xss-not-strictly-xss-but-still-bad.md) - [Tip #121] Technically, XSS involves injecting malicious Javascript, but sometimes you don't need any JS to get up to mischief! π
- [4 years of Securing Laravel! π](https://securinglaravel.com/4-years.md) - I almost missed it, but it's time to celebrate 4 years of Securing Laravel!
- [Security Tip: Password Resets and MFA?](https://securinglaravel.com/security-tip-password-resets-and-mfa.md) - [Tip #120] How should we safely handle resetting forgotten passwords without compromising the protection that MFA provides?
- [Security Tip: Account Recovery for MFA?](https://securinglaravel.com/security-tip-account-recovery-for-mfa.md) - [Tip #119] What happens if your users lose their MFA tokens, and they never saved their recovery codes? Can you safely give them back access to their accounts?
- [Security Tip: 2FA Isn't Just For Logins!](https://securinglaravel.com/security-tip-2fa-isnt-just-for-logins.md) - [Tip #118] Account passwords are easy to compromise, so why are you relying on them to verify users within your app? If your users log in with a 2FA Token, then they should be able to prove it before performing other sensitive activities too.
- [In Depth: Setting up Two-Factor Authentication!](https://securinglaravel.com/in-depth-setting-up-two-factor-authentication.md) - [In Depth #37] It's time to finally fulfil one of the most common requests for an In Depth article: setting up 2FA! π So let's add some TOTP 2FA to our boring user/pass auth login!
- [Security Tip: Do I Have a Vulnerable Package Installed?](https://securinglaravel.com/security-tip-do-i-have-a-vulnerable-package-installed.md) - [Tip #117] It's easy to say "Update if it's installed!", but how do you actually know if a package is installed, since it may not appear in composer.json?! Also, how did it even get there??!! π€¨
- [Laravel Security Notice: Livewire v3 Remote Code Execution Vulnerability!](https://securinglaravel.com/security-notice-livewire-v3-rce.md) - [Notice #4] Livewire v3 is vulnerable to an RCE (Remote Command Execution) during component property update hydration in specific scenarios. β οΈ Update your Livewire ASAP! β οΈ
- [Security Tip: Add Authorisation at the Start!](https://securinglaravel.com/security-tip-add-authorisation-at-the-start.md) - [Tip #116] Is it a "premature optimisation" to add authorisation to your app before you know how your authorisation will be structured?
- [Security Tip: Scoping orWhere Can Be Disastrous!](https://securinglaravel.com/security-tip-scoping-orwhere-can-be-disastrous.md) - [Tip #115] Let's take a look at why something as simple and "harmless" as an orWhere can introduce a huge privacy risk to your application, and how you can avoid it!
- [In Depth: A Deep Dive into Laravel's New Starter Kits! (pt 2)](https://securinglaravel.com/in-depth-a-deep-dive-into-laravels-new-starter-kits-pt-2.md) - [In Depth #36] It's time to review the Livewire Volt, Vue, and React Starter Kits! Let's see what vulnerabilities are hiding under the surface, and just how easy it is to fix them... π§
- [Security Tip: Eloquent Casting to HtmlString!](https://securinglaravel.com/security-tip-eloquent-casting-to-htmlstring.md) - [Tip #114] One of my favourite Laravel features, the humble HtmlString, is now available as an Eloquent Cast - which should make it much more accessible! π But there is a catch... π
- [Security Tip: Don't Generate Your Own Passwords!](https://securinglaravel.com/security-tip-dont-generate-your-own-passwords.md) - [Tip #113] "Don't Roll Your Own Crypto" applies to password generators too! It's way too easy to unknowingly lower your entropy by trying to be clever... π±
- [Security Tip: Don't Use phpinfo()!](https://securinglaravel.com/security-tip-dont-use-phpinfo.md) - [Tip #112] It may seem like a harmless debugging tool, with a bunch of boring config values and version numbers, but phpinfo() is a goldmine of sensitive data - even when it's "protected" in an admin account! π
- [In Depth: A Deep Dive into Laravel's New Starter Kits! (pt 1)](https://securinglaravel.com/in-depth-a-deep-dive-into-laravels-new-starter-kits-pt-1.md) - [In Depth #35] Let's take a dive into the security of Laravel's new Starter Kits to see how they handle authentication, what security features they include, and what areas could be improved! π€
- [Security Tip: What Can We Learn from CommonMark's XSS?](https://securinglaravel.com/security-tip-what-can-we-learn-from-commonmarks-xss.md) - [Tip #111] The recently patched XSS in CommonMark's Attributes extension offers an interesting look at what happens when two different features conflict, one being a security feature, the other a knowingly vulnerable extension.
- [Security Tip: OTPs Need Rate Limiting Too!](https://securinglaravel.com/security-tip-otps-need-rate-limiting-too.md) - [Tip #110] This is your periodic reminder that Rate Limiting is essential, and for more than just your user/password form! Make sure you've got it on your OTP, or someone will come along and brute-force that 6-digit code.
- [Security Tip: Yes, Your .Env Is Secure Enough!](https://securinglaravel.com/security-tip-yes-your-env-is-secure-enough.md) - [Tip #109] I get asked this all the time, so it's time to set the record straight: there is nothing insecure about storing your credentials in a .env, as long as you keep your .env protected!
- [In Depth: What Actually Is MFA?](https://securinglaravel.com/in-depth-what-actually-is-mfa.md) - [In Depth #34] MFA, 2FA, 2SV, DFA... Something you know/have/are... Let's figure out this MFA thing and why it's so important.
- [Security Tip: Temporary Local File URLs!](https://securinglaravel.com/security-tip-temporary-local-file-urls.md) - [Tip #108] Temporary URLs for file access is an essential piece of the security puzzle, which up until recently were only available out-of-the-box for the S3 driver. Now you can easily generate them for local files too!
- [Security Tip: Excluding SVGs from Image Validation!](https://securinglaravel.com/security-tip-excluding-svgs-from-image-validation.md) - [Tip #107] Laravel 12 introduced a seemingly minor change - image validation now excludes SVGs by default. π€ Let's take a look at why this is so important! π€
- [Security Tip: Limiting bcrypt Passwords to 72 Bytes!](https://securinglaravel.com/security-tip-limiting-bcrypt-passwords-to-72-bytes.md) - [Tip #106] Laravel 12 gives us the ability to reject passwords longer than 72 bytes for bcrypt, but you need to turn it on manually. Oh, and don't forget to add a validation rule, or you'll be throwing suspicious 500 server errors! π±
- [Security Tip: Run Your CSP in Local Development!](https://securinglaravel.com/security-tip-run-your-csp-in-local-development.md) - [Tip #105] These are my top 3 tips for getting started with a Content Security Policy - as proven by a friend who went from failing security scans to passing with flying colours.
- [Security Tip: Type Coercion in Broadcast Routes!](https://securinglaravel.com/security-tip-type-coercion-in-broadcast-routes.md) - [Tip #104] It's easy for type juggling to sneak into authorisation callbacks, especially when types are ambiguous, and if you're not careful, you may be leaving a massive hole waiting to be exploited! π±
- [In Depth: Common Authorisation Failures!](https://securinglaravel.com/in-depth-common-authorisation-failures.md) - [In Depth #33] Let's explore a number of common ways developers fail authorisation in Laravel apps, and what you need to watch out for so you don't make the same mistakes!
- [Security Tip: Don't Roll Your Own Crypto!](https://securinglaravel.com/security-tip-dont-roll-your-own-crypto.md) - [Tip #103] It's story time! Let's look at the SHA-3 competition as a reminder that crypto is hard... π±
- [Security Tip: Do You Have an Upgrade Plan?](https://securinglaravel.com/security-tip-do-you-have-an-upgrade-plan.md) - [Tip #102] In less than 2 weeks, Laravel 10.x will no longer be supported, and PHP 8.1 has less than 12 months left! Do you have an upgrade plan?
- [Security Tip: Should You Limit Password Lengths?](https://securinglaravel.com/security-tip-should-you-limit-password-lengths.md) - [Tip #101] Password length limits are often a sign of a legacy backend or insecure hashing, but did you know bcrypt only hashes the first 72 characters? It raises the question, should we be limiting password lengths when using bcrypt too? π€
- [In Depth: Five Ways to Fail at Authentication](https://securinglaravel.com/in-depth-five-ways-to-fail-at-authentication.md) - [In Depth #32] Let's explore 5 different "Authentication Fails" that I've come across, as a reminder for why it's so important to get authentication right.
- [Security Tip: What If You Hashed Null?](https://securinglaravel.com/security-tip-what-if-you-hashed-null.md) - [Tip #100] One of the fun parts of doing my security audits is coming across unexpected code that looks exploitable, and trying it out myself to see what possibilities exist.
- [Security Tip: Please Stop Hardcoding Admin Domains!](https://securinglaravel.com/security-tip-please-stop-hardcoding-admin-domains.md) - [Tip #99] Let me tell you a story about a time when a single missing character allowed me to escalate my privileges and gain admin access, despite all the protections designed to stop me! π
- [Security Tip: strip_tags() Won't Save You from XSS!](https://securinglaravel.com/security-tip-strip_tags-wont-save-you-from-xss.md) - [Tip #98] XSS doesn't just hide in