Skip to content

Add 4 Laravel security rules: raw SQL, open redirect, mass assignment, weak hashing#3808

Open
momenbasel wants to merge 2 commits intosemgrep:developfrom
momenbasel:laravel-security-rules
Open

Add 4 Laravel security rules: raw SQL, open redirect, mass assignment, weak hashing#3808
momenbasel wants to merge 2 commits intosemgrep:developfrom
momenbasel:laravel-security-rules

Conversation

@momenbasel
Copy link
Copy Markdown

Summary

Adds 4 new security rules for Laravel/PHP applications with corresponding test files:

# Rule Severity CWE Detection
1 laravel-raw-db-statement ERROR CWE-89 Tainted user input in DB::statement/select/insert/update/delete/raw
2 laravel-unvalidated-redirect WARNING CWE-601 Open redirect via redirect() with unvalidated $request->input()
3 laravel-mass-assignment-fillable-star ERROR CWE-915 $fillable = ['*'] wildcard bypassing mass assignment protection
4 laravel-weak-password-hash ERROR CWE-328 md5()/sha1()/crypt() for passwords instead of Hash::make()

Each rule includes a .php test file with ruleid: and ok: annotations.

Context

The existing Laravel security ruleset has 11 rules. These additions cover critical gaps:

  • Rule 1 complements existing laravel-sql-injection (which covers whereRaw/orderByRaw) by detecting DB:: facade methods (statement, select, insert, update, delete, raw) with tainted input. Includes sanitizers for type casting (intval, (int)).
  • Rule 2 is entirely new - no open redirect detection existed for Laravel.
  • Rule 3 complements laravel-dangerous-model-construction (which catches $guarded = []) by detecting the $fillable = ['*'] wildcard variant.
  • Rule 4 is entirely new - detects insecure password hashing in authentication contexts.

Test Plan

  • Run semgrep --test php/laravel/security/ to validate all rule/test pairs pass
  • Verify each ruleid: annotation triggers and each ok: annotation does not
  • Test against open-source Laravel applications for false positive rate

…ssignment, and weak hashing

- laravel-raw-db-statement: Detects DB::statement/DB::raw/DB::select with string concatenation
- laravel-unvalidated-redirect: Detects redirect() with unvalidated user input
- laravel-mass-assignment-fillable-star: Detects $fillable = ['*'] wildcard
- laravel-weak-password-hash: Detects md5/sha1/crypt for password hashing instead of Hash::make
…bool

The taint rule was flagging type-cast variables as vulnerable. PHP type
casts like (int), (float), and (bool) effectively sanitize user input
for SQL injection since the result is always a safe scalar type.
Copilot AI review requested due to automatic review settings April 8, 2026 21:32
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds four new Semgrep security rules to the existing Laravel/PHP ruleset, each with a dedicated .php test fixture using ruleid: / ok: annotations to validate matching behavior.

Changes:

  • Add a taint-mode rule to detect user-controlled input flowing into raw DB::statement/select/insert/update/delete/raw SQL usage.
  • Add a rule to detect potential open redirects via redirect() / Redirect::to() when fed from request input or superglobals.
  • Add rules to detect risky Eloquent configuration ($fillable = ['*']) and weak/nonstandard password hashing patterns (md5/sha1/crypt).

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
php/laravel/security/laravel-raw-db-statement.yaml New taint rule for raw DB facade SQL sinks.
php/laravel/security/laravel-raw-db-statement.php Test cases for raw DB facade SQL sinks.
php/laravel/security/laravel-unvalidated-redirect.yaml New pattern rule for request-driven redirects (open redirect).
php/laravel/security/laravel-unvalidated-redirect.php Test cases for request-driven redirects.
php/laravel/security/laravel-mass-assignment-fillable-star.yaml New pattern rule for $fillable = ['*'] in Eloquent models.
php/laravel/security/laravel-mass-assignment-fillable-star.php Test cases for $fillable = ['*'] and safe variants.
php/laravel/security/laravel-weak-password-hash.yaml New pattern rule for weak/nonstandard password hashing usage.
php/laravel/security/laravel-weak-password-hash.php Test cases for weak hashing patterns and safe Laravel hashing APIs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +18 to +23
pattern-sanitizers:
- patterns:
- pattern-either:
- pattern: intval(...)
- pattern: (int) $X
- pattern: (float) $X
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pattern-sanitizers treats htmlspecialchars(...) as a SQL-injection sanitizer, but it does not prevent SQL injection and will create false negatives. Also, the tests include a safe (int) cast (safe_cast in the paired .php file) but this rule doesn’t list casts as sanitizers, so the ok: case may still be reported. Remove htmlspecialchars(...) from sanitizers and add integer-cast sanitizers (e.g., (int) ..., (integer) ..., and/or intval(...) only).

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +31
class AnotherSafeModel extends Model
{
/**
* Using guarded to block specific fields is also acceptable.
*/
// ok: laravel-mass-assignment-fillable-star
protected $fillable = ['title', 'body', 'slug'];
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docblock says this model is safe because it uses guarded, but the code actually uses $fillable. This is misleading in a rule test file (it documents expected safe patterns) and should be corrected to match the implementation (or change the example to actually use $guarded).

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +51
owasp:
- A01:2021 - Broken Access Control
- A04:2025 - Broken Access Control
technology:
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OWASP metadata is inconsistent with the rest of the Laravel security rules: other rules label “Broken Access Control” as A01:2025, but this rule uses A04:2025. Please align this to the numbering used elsewhere in php/laravel/security/*.yaml for the same OWASP category to keep metadata consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +16
message: >-
A weak hashing function (`md5`, `sha1`, or `crypt`) is used on a variable whose
name suggests it contains a password. These algorithms are not designed for password
hashing and are vulnerable to brute-force and rainbow table attacks.
Use Laravel's `Hash::make()` or the `bcrypt()` helper instead, which use bcrypt
with a secure cost factor by default.
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message groups crypt() with inherently weak hashes (md5/sha1) and states it is “not designed for password hashing”. In PHP, crypt() can be configured to use strong schemes (e.g., bcrypt with $2y$...), so flagging all crypt($password, ...) usages as “weak” is misleading and likely to cause noisy findings. Consider either removing crypt() from this rule, narrowing it to clearly weak crypt usages, or adjusting the rule id/message to focus on “non-Laravel password hashing API” rather than “weak hashing”.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants