Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Don't Just Patch — MOTTAINAI! Learn Security fr...

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Don't Just Patch — MOTTAINAI! Learn Security from Laravel CVE Diffs

More Decks by コドモン開発チーム

Other Decks in Technology

Transcript

  1. Laravel Live Japan 2026.5.27 CoDMON Inc. / Akito Tsukahara Don't

    Just Patch — MOTTAINAI! Learn Security from Laravel CVE Diffs
  2. ?id[]=1&id[]=2 SQL Binding Misalignment Vulnerability CVE-2021-21263 / Disclosed in 2021

    You updated without noticing — and you're protected without noticing.
  3. 4 CoDMON Inc. Software Engineer 11 years as a PHP

    developer. I grew up on PHP. Father of a 1-year-old and a toy poodle. My favorite framework? Laravel, of course! Akito Tsukahara @AkitoTsukahara
  4. 6 01 Two case studies   • A Query Builder pitfall

      • A Host header pitfall 02 A workflow you can start tomorrow INDEX
  5. CVE-2021-21263 Disclosed in 2021 CVSS 7.5 High The vulnerable code

    — a pattern you'd write every day // Get ID from the request $id = $request->input('id'); // Pass it straight into the query User::where('id', $id)->first(); What happens When an array is passed to where('id', $id), Laravel flattens it internally and binds only the first value → the bindings shift out of alignment, and an unintended query is executed. Attack scenario Normal request GET /users?id=1 → $id = '1' (scalar) Malicious request GET /users?id[]=1&id[]=2 → $id = ['1', '2'] (array)
  6. The fix in Laravel core — stricter array handling //

    src/Illuminate/Database/Query/Builder.php - $this->addBinding(is_array($value) ? Takeaways - head(Arr::flatten($value)) : $value, 'where'); + $this->addBinding(is_array($value) ? + head($value) : $value, 'where'); Prepared statements are not a silver bullet They rely on the assumption that input types match expectations. The moment an array arrives where a scalar is expected, that assumption collapses. What to watch for in code review Before passing a request value into where(), is it guaranteed to be a scalar? (FormRequest validation, (int) cast, type check ...etc CVE-2021-21263 Disclosed in 2021 CVSS 7.5 High
  7. The vulnerable code — building the password reset URL ->action(

    'Reset Password', route('password.reset', $this->token) ) Where's the vulnerability in this code? CVE-2017-9303 Disclosed in 2017 CVSS 6.1 Medium
  8. Attacker POST /password/reset Host: evil.example.com ← spoofed Reset request Laravel

    route() builds the URL from the Host header → https://evil.example.com/reset?token=xxx Reset email sent Victim Opens the fake URL and resets their password → Account takeover complete The attack pattern CVE-2017-9303 Disclosed in 2017 CVSS 6.1 Medium
  9. The fix in Laravel core — use a config-based host

    - ->action('Reset Password', route('password.reset', $this->token)) Takeaways + ->action('Reset Password', + url(config('app.url').route('password.reset', $this->token, false))) HTTP request headers can be manipulated by attackers Never trust the request's host for outgoing URLs. Use server config (e.g., config('app.url')). What to watch for in code review Email links, cookie domain settings, redirect targets — always verify any hostname that leaves your app. // src/Illuminate/Auth/Notifications/ResetPassword.php CVE-2017-9303 Disclosed in 2017 CVSS 6.1 Medium
  10. diffを読む習慣の作り⽅ — 5ステップ 明⽇から始める実践フ ロー Five steps to make diff-reading

    a habit 1 Dependabot alert Receive the alert 2 *GHSA page Get a rough picture of the vulnerability 3 Summarize with generative AI Sketch the initial map 4 Read the PR diff yourself ★The main event — review the fix 5 Write it up in your daily notes Make the lesson stick Building a habit of reading diffs — 5 steps * GitHub Security Advisory
  11. Prompt — actual sample > https://github.com/advisories/GHSA-rc8x-jrrc-frfv Summarize the vulnerability at

    this URL. Cover the attack pattern, which implementation was at fault, and what fix was effective. If there's any notable discussion, include that too. AI response — actual sample ## CVE-2017-9303 / Host Header Injection ### Attack Pattern An attacker sends a password reset request with a spoofed header like `Host: evil.example.com`. ─── truncated ─── ### Notable Discussion A middleware-based fix was initially considered, but the adopted approach was to generate URLs from `config('app.url')` instead. ❸ Summarize with generative AI — a real example 【ポイント】 Keep it rough If a perfect prompt feels like a chore, you'll just put it off. The AI's answer is just a map Use the summary as a starting point — then go read the PR and the fix commit yourself.
  12. Four lenses for reading a diff and grasping the real

    intent of the fix 🗂 Which layer is being changed 1 Middleware? Validator? Auth? Encrypter? → Map it to Laravel's directory structure See which layer the fix affects The shape of the removed and added lines A one-line swap? An added argument? A whole function rewritten? → The shape of the diff itself tells the story of the fix Judge the significance of the fix by its scale Changes in the test code Tests reveal which inputs triggered the bug before the fix → Confirm the reproduction conditions Understand the attack scenario through the test cases Commit message & PR description Why the author chose this fix, and how it compares to alternatives → Understand the context and the reasoning Grasp the intent correctly ❹ Read the PR diff yourself — 4 things to look for 2 3 4
  13. Recent CVEs I've read CVE-2026-23524 2026/01 RCE via unserialize() through

    Redis in Reverb [Reverb] unserialize() called via Redis Other recent CVEs I've read — take a look if you're curious CVE-2025-54068 2025/07 RCE via property hydration [Livewire] Listed in the CISA KEV catalog CVE-2025-27515 2025/03 File validation bypass (files.*) [Core] Predictable internal identifiers become an    attack surface CVE-2024-13918 / 13919 2025/03 XSS on the debug page / XSS via route parameters [Core] Don't carve out exceptions to escaping
  14. Where you didn't notice, that's exactly where the lessons hide.

    Are you really just going to update — and move on?