Uploaded image for project: 'Observium'
  1. Observium
  2. OBS-5183

API Token Revoke Fails with CSRF Error - Missing requesttoken Hidden Field in Revoke Form

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • Major
    • None
    • None
    • Default
    • None
    • Observium Pro, Ubuntu 20.04, Nginx 1.18, PHP 7.4-FPM

    Description

      Summary

      When attempting to revoke an API token on the /api_tokens/ page, a CSRF validation error occurs 100% of the time. The token is never revoked. The root cause is a missing requesttoken hidden field in the revoke form.

      Symptoms

      The following errors appear when clicking the Revoke button:

      WARNING. Possible CSRF attack with EMPTY request token.
      Invalid request token. Please try again.
      

      The error occurs 100% of the time regardless of browser, session, or user account.

      Root Cause

      The revoke form in html/pages/api_tokens.inc.php generates a POST form for each token but is missing the requesttoken hidden field that Observium's CSRF protection requires.

      The Broken Code (around line ~175):

      $actions = '<form method="post" style="display: inline;" ';
      $actions .= 'onsubmit="return confirm(\'Are you sure you want to revoke this token?\')">';
      $actions .= '<input type="hidden" name="action" value="revoke">';
      $actions .= '<input type="hidden" name="token_id" value="' . $token['token_id'] . '">';
      // requesttoken field is MISSING here
      $actions .= '<button type="submit" class="btn btn-xs btn-danger">';
      $actions .= '<i class="fa fa-ban"></i> Revoke';
      $actions .= '</button>';
      $actions .= '</form>';
      

      What Happens:

      1. User clicks "Revoke" button
      2. # Form POSTs to /api_tokens/ with only action=revoke&token_id=X
      3. # request_token_valid($vars) in api_tokens.inc.php checks for $vars['requesttoken']
      4. # Field is empty/missing → CSRF check fails → error is shown

        Evidence from HAR capture:

      POST https://observium.xxx.com/api_tokens/
      Body: action=revoke&token_id=2
      # requesttoken field is completely absent
      # 

      How Observium's CSRF System Works:

      • On login, authenticate.inc.php generates a token: bin2hex(random_bytes(32))
      • * Token is stored in $_SESSION['requesttoken']
      • * Token is registered as a meta tag: register_html_meta('csrf-token', $_SESSION['requesttoken'])
      • * observium.js reads: var csrfToken = $('meta[name="csrf-token"]').attr('content')
      • * JS injects it into AJAX requests automatically
      • * For regular HTML forms, the token must be manually added as a hidden field
      • * api_tokens.inc.php uses a regular HTML form but never adds the hidden field

        Fix

      Add the missing requesttoken hidden field to the revoke form:

      $actions .= '<input type="hidden" name="action" value="revoke">';
      $actions .= '<input type="hidden" name="token_id" value="' . $token['token_id'] . '">';
      $actions .= '<input type="hidden" name="requesttoken" value="' . $_SESSION['requesttoken'] . '">';  // ADDED
      

      Other Pages That Handle This Correctly

      For reference, other Observium pages correctly include the requesttoken in their forms:

      • html/includes/print/search.inc.php — adds requesttoken to search forms
      • * html/pages/user_edit.inc.php — passes requesttoken through form actions
      • * html/pages/preferences.inc.php — validates requesttoken on all POST actions
        api_tokens.inc.php follows the same CSRF validation pattern at the top of the file but the form builder omits the field. This appears to be an oversight in the initial implementation of the API tokens feature.

      Maintenance Note

      This fix will be overwritten by Observium updates. After any update, verify with:

      grep "requesttoken" /opt/observium/html/pages/api_tokens.inc.php
      

      Attachments

        Activity

          People

            adama Adam Armstrong
            Sliman Siman M.
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: