Zammad Security Testing: Admin Credentials, API Token, Ticket Data, and LDAP Integration

Zammad is a widely deployed open-source helpdesk and customer support ticketing platform, particularly popular in Europe and among German-speaking organizations. As a customer support hub, Zammad contains high-value data: all customer and internal support tickets with full conversation history, customer contact information including email and phone, LDAP/Active Directory bind credentials, and the passwords for all configured email channels (IMAP/SMTP). Key assessment areas: the Zammad REST API token provides full ticket and user enumeration; LDAP bind credentials are stored in the settings database table; email channel IMAP and SMTP passwords are stored in the channels table; the Rails secret_key_base in Zammad configuration enables session cookie forgery; and the Elasticsearch backend may be exposed without authentication in default configurations. This guide covers systematic Zammad security assessment.

Table of Contents

  1. API Token Access and User Enumeration
  2. Ticket Data and Customer Information Access
  3. LDAP, Email, and Configuration Credential Extraction
  4. Zammad Security Hardening

API Token Access and User Enumeration

# Zammad — API token authentication and user enumeration
ZAMMAD_URL="https://zammad.example.com"
API_TOKEN="your-zammad-api-token"

# Test API access — verify token and current user
curl -s "${ZAMMAD_URL}/api/v1/users/me" \
  -H "Authorization: Token token=${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Current user: {d.get(\"login\")} name={d.get(\"firstname\")} {d.get(\"lastname\")}')
print(f'Role IDs: {d.get(\"role_ids\")} (1=admin, 2=agent)')
print(f'Email: {d.get(\"email\")}')
" 2>/dev/null

# Enumerate all users — customers and agents
curl -s "${ZAMMAD_URL}/api/v1/users?expand=true&per_page=200" \
  -H "Authorization: Token token=${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
users=json.load(sys.stdin)
print(f'Users: {len(users)}')
for u in users:
    roles = u.get('role_ids',[])
    print(f'  [{u.get(\"id\")}] {u.get(\"login\")} email={u.get(\"email\")} roles={roles} org={u.get(\"organization_id\")}')
" 2>/dev/null

# Enumerate all organizations — customer company list
curl -s "${ZAMMAD_URL}/api/v1/organizations?per_page=200" \
  -H "Authorization: Token token=${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
orgs=json.load(sys.stdin)
print(f'Organizations: {len(orgs)}')
for o in orgs[:20]:
    print(f'  [{o.get(\"id\")}] {o.get(\"name\")} domain={o.get(\"domain\")} shared={o.get(\"shared\")}')
" 2>/dev/null

Ticket Data and Customer Information Access

# Zammad ticket enumeration — complete support history
ZAMMAD_URL="https://zammad.example.com"
API_TOKEN="your-zammad-api-token"

# List all tickets with full details
curl -s "${ZAMMAD_URL}/api/v1/tickets?expand=true&per_page=100" \
  -H "Authorization: Token token=${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
tickets=json.load(sys.stdin)
print(f'Tickets: {len(tickets)}')
for t in tickets[:20]:
    print(f'  [{t.get(\"id\")}] {t.get(\"title\")} state={t.get(\"state\")} priority={t.get(\"priority\")}')
    print(f'    Customer: {t.get(\"customer_id\")} org={t.get(\"organization_id\")} group={t.get(\"group\")}')
    print(f'    Created: {t.get(\"created_at\")} updated={t.get(\"updated_at\")}')
" 2>/dev/null

# Get ticket articles (actual message content)
TICKET_ID="1"
curl -s "${ZAMMAD_URL}/api/v1/ticket_articles/by_ticket/${TICKET_ID}?expand=true" \
  -H "Authorization: Token token=${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
articles=json.load(sys.stdin)
print(f'Ticket articles: {len(articles)}')
for a in articles:
    print(f'  from={a.get(\"from\")} to={a.get(\"to\")} type={a.get(\"type\")}')
    print(f'  Body: {a.get(\"body\",\"\")[:150]}')
" 2>/dev/null

LDAP, Email, and Configuration Credential Extraction

# Zammad credential extraction — LDAP, email channels, Rails secret
# Zammad stores sensitive config in PostgreSQL settings and channels tables

# Rails application configuration — secret_key_base
grep -r "secret_key_base\|database_password" \
  /etc/zammad/ /opt/zammad/config/ 2>/dev/null | head -20
# secret_key_base — signs Rails session cookies; leakage enables session forgery

# Direct database access — LDAP and email channel credentials
PGPASSWORD="zammad_db_password" psql -U zammad -d zammad 2>/dev/null << 'EOF'
-- LDAP bind credentials
SELECT name, preferences
FROM settings
WHERE name IN ('ldap_config', 'user_show_password_login', 'auth_ldap');

-- Email channel credentials (IMAP/SMTP passwords)
SELECT area, options
FROM channels
WHERE area IN ('Email::Account', 'Email::Outbound');
EOF
# Reveals LDAP bind_dn, bind_pw for Active Directory integration
# Reveals IMAP passwords for all configured mailboxes
# Reveals SMTP credentials for outbound email delivery

# Zammad API — list configured channels (admin token required)
curl -s "${ZAMMAD_URL}/api/v1/channels?expand=true" \
  -H "Authorization: Token token=${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
channels=json.load(sys.stdin)
for c in channels:
    opts = c.get('options',{}) or {}
    inbound = opts.get('inbound',{}) or {}
    print(f'Channel: {c.get(\"area\")} adapter={inbound.get(\"adapter\")} host={inbound.get(\"host\")} user={inbound.get(\"user\")}')
" 2>/dev/null

Zammad Security Hardening

Zammad Security Hardening Checklist:
Security TestMethodRisk
API token ticket and customer data enumerationGET /api/v1/tickets and /api/v1/users with API token — returns all support tickets with customer information, conversation history, and contact details; complete CRM data exposure including organization relationshipsCritical
LDAP bind credential extractionPostgreSQL query on settings table — LDAP bind_pw for Active Directory integration; service account credentials with read access to all AD users, groups, and organizational unitsCritical
Email channel password extractionPostgreSQL query on channels table — IMAP and SMTP passwords for all configured mailboxes; enables reading all incoming support emails and sending emails as the Zammad system accountHigh
Rails secret_key_base extraction for session forgeryRead /etc/zammad/ or deployment config files — secret_key_base enables crafting valid Rails session cookies for any user, bypassing Zammad authentication entirely including admin accountsCritical
Ticket article content disclosureGET /api/v1/ticket_articles/by_ticket/{id} — returns full conversation bodies including customer-submitted information that frequently contains passwords, license keys, and sensitive system data shared with supportHigh

Automate Zammad Security Testing

Ironimo tests Zammad deployments for API token ticket and customer data enumeration, LDAP bind credential extraction from the settings table, email channel IMAP/SMTP password access, Rails secret_key_base extraction for session forgery, Elasticsearch unauthenticated backend access, webhook configuration credential disclosure, admin API channel enumeration, and two-factor authentication enforcement verification.

Start free scan