VYPR
Moderate severityNVD Advisory· Published Nov 13, 2021· Updated Aug 3, 2024

Cross-Site Request Forgery (CSRF) in snipe/snipe-it

CVE-2021-3931

Description

snipe-it is vulnerable to Cross-Site Request Forgery (CSRF)

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Snipe-IT prior to version 5.3.0 was vulnerable to CSRF because state-changing actions like toggling custom field properties used GET requests without CSRF tokens.

Vulnerability

Snipe-IT, a free open-source IT asset/license management system built on Laravel, was vulnerable to Cross-Site Request Forgery (CSRF) in versions prior to the fix committed on 2021-11-13. The vulnerability existed in the custom fields management feature: actions such as toggling a field between required and optional (fields.required, fields.optional) and disassociating a field from a fieldset (fields.disassociate) were previously implemented as GET requests via anchor links with no CSRF token verification. This meant any authenticated user could be tricked into performing these state changes without their consent [1][2][3][4].

Exploitation

An attacker can craft a malicious web page or email that, when visited by an authenticated Snipe-IT administrator while their session is active, automatically triggers a GET request to one of the vulnerable endpoints (e.g., making a custom field required or optional, or removing a field from a fieldset). No additional authentication or user interaction beyond visiting the attacker-controlled page is required, as the victim's browser will include their existing session cookies. The attacker does not need network access to the Snipe-IT server itself; they only need to lure an authenticated administrator to their malicious content [2][3][4].

Impact

Successful exploitation allows an attacker to modify custom field configurations in Snipe-IT without the victim's knowledge. Specifically, the attacker can change whether a field is required or optional, and remove a field from a fieldset. This could lead to data integrity issues, as fields may be unexpectedly removed or their requirements altered, potentially causing data loss or weakening asset tracking accuracy. The attack does not grant the attacker direct access to sensitive data, but it can corrupt the structured asset data managed by the system [2][3][4].

Mitigation

The vulnerability was fixed by converting the vulnerable GET-based actions to POST requests with CSRF token validation. The fix was committed on 2021-11-13 in commit 0d811d067c8e064252c0143c39d6cd4c3133679e and is included in Snipe-IT version 5.3.0 and later [2][3][4]. Users should upgrade to at least version 5.3.0 immediately. No workaround is available for older versions. The issue was reported via huntr.dev and is not listed on the CISA KEV.

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
snipe/snipe-itPackagist
<= 5.3.1

Affected products

2

Patches

1
0d811d067c8e

Turn cusotm fields required/optional/remove into POST requests

https://github.com/snipe/snipe-itsnipeNov 5, 2021via ghsa
2 files changed · +19 12
  • resources/views/custom_fields/fieldsets/view.blade.php+16 9 modified
    @@ -57,21 +57,28 @@
                   <td>{{$field->element}}</td>
                   <td>{{ $field->field_encrypted=='1' ?  trans('general.yes') : trans('general.no') }}</td>
                     <td>
    +                  
                         @if ($field->pivot->required)
    -                        <a href="{{ route('fields.optional', [$custom_fieldset->id, $field->id]) }}">
    -                            <i class="fa fa-check text-success" aria-hidden="true"></i>
    -                            <span class="sr-only">Required - click to make optional</span>
    -                        </a>
    +                    <form method="post" action="{{ route('fields.optional', [$custom_fieldset->id, $field->id]) }}">
    +                      @csrf 
    +                      <button type="submit" class="btn btn-link"><i class="fa fa-check text-success" aria-hidden="true"></i></button>
    +                      </form>
    +
                         @else
    -                        <a href="{{ route('fields.required', [$custom_fieldset->id, $field->id]) }}">
    -                            <i class="fa fa-times text-danger" aria-hidden="true"></i>
    -                            <span class="sr-only">Optional - click to make required</span>
    -                        </a>
    +
    +                      <form method="post" action="{{ route('fields.required', [$custom_fieldset->id, $field->id]) }}">
    +                      @csrf 
    +                      <button type="submit" class="btn btn-link"><i class="fa fa-times text-danger" aria-hidden="true"></i></button>
    +                      </form>
                         @endif
    +                    
                     </td>
                   <td>
                     @can('update', $custom_fieldset)
    -                <a href="{{ route('fields.disassociate', [$field, $custom_fieldset->id]) }}" class="btn btn-sm btn-danger">Remove</a>
    +                <form method="post" action="{{ route('fields.disassociate', [$field, $custom_fieldset->id]) }}">
    +                  @csrf 
    +                  <button type="submit" class="btn btn-sm btn-danger">Remove</button>
    +                </form>
                     @endcan
                   </td>
                 </tr>
    
  • routes/web/fields.php+3 3 modified
    @@ -7,17 +7,17 @@
     
     Route::group([ 'prefix' => 'fields','middleware' => ['auth'] ], function () {
     
    -    Route::get('required/{fieldset_id}/{field_id}',
    +    Route::post('required/{fieldset_id}/{field_id}',
             ['uses' => 'CustomFieldsetsController@makeFieldRequired',
                 'as' => 'fields.required']
         );
     
    -    Route::get('optional/{fieldset_id}/{field_id}',
    +    Route::post('optional/{fieldset_id}/{field_id}',
             ['uses' => 'CustomFieldsetsController@makeFieldOptional',
                 'as' => 'fields.optional']
         );
     
    -    Route::get('{field_id}/fieldset/{fieldset_id}/disassociate',
    +    Route::post('{field_id}/fieldset/{fieldset_id}/disassociate',
             ['uses' => 'CustomFieldsController@deleteFieldFromFieldset',
             'as' => 'fields.disassociate']
         );
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.