This document outlines the security measures, best practices, and known considerations for Forecaster Arena.
Forecaster Arena is a research benchmark platform that:
- Does NOT handle real money (paper trading only)
- Does NOT collect user data beyond admin authentication
- Does NOT expose sensitive user information
- Does handle API keys and authentication secrets
All secrets are stored in .env.local which:
- ✅ Is gitignored (
.env*.localin.gitignore) - ✅ Has restricted permissions (
600- owner read/write only) - ✅ Is never committed to version control
- ✅ Uses placeholder values in
.env.example
Required Secrets:
| Secret | Purpose | Generation |
|---|---|---|
OPENROUTER_API_KEY |
LLM API access | From https://openrouter.ai/settings/keys |
CRON_SECRET |
Cron endpoint authentication | openssl rand -hex 32 |
ADMIN_PASSWORD |
Admin dashboard access | Strong password (12+ chars) |
Current Implementation:
- CRON_SECRET is stored in both:
/opt/forecasterarena/.env.local(permissions: 600, owner: www-data)/etc/cron.d/forecasterarena(permissions: 644, owner: root)
Security Considerations:
/etc/cron.d/forecasterarena has 644 permissions, making the CRON_SECRET readable by all users on the system.
Risk Assessment:
- Impact: Low-Medium (allows unauthorized triggering of cron endpoints)
- Likelihood: Low (requires local system access)
- Mitigation: Single-user system, no sensitive data exposure
Recommended Improvements:
-
Option 1: Restrict crontab permissions (Simple)
sudo chmod 600 /etc/cron.d/forecasterarena
Note: Some cron implementations require 644 permissions
-
Option 2: Use wrapper script (More secure)
# Create /usr/local/bin/forecaster-cron.sh #!/bin/bash source /opt/forecasterarena/.env.local curl -s -X POST "$1" -H "Authorization: Bearer $CRON_SECRET" # Crontab entry becomes: */5 * * * * root /usr/local/bin/forecaster-cron.sh http://localhost:3010/api/cron/sync-markets
-
Option 3: IP-based authentication (Most secure)
- Allow cron endpoints only from localhost
- Verify
X-Forwarded-Foror remote address in API routes
All /api/cron/* endpoints require:
Authorization: Bearer {CRON_SECRET}Implementation:
- Constant-time comparison (prevents timing attacks)
- Returns 401 if missing or invalid
- Logs failed authentication attempts
Code Reference: Each cron route validates via:
const authHeader = req.headers.get('authorization');
const expectedAuth = `Bearer ${process.env.CRON_SECRET}`;
if (authHeader !== expectedAuth) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}Admin endpoints (/api/admin/*) use:
- Password-based authentication
- HTTP-only session cookies
- Constant-time password comparison
Session Security:
- Cookie:
forecaster-admin-session - Attributes:
HttpOnly,Secure(in production),SameSite=Strict - Expiration: Session-based (cleared on browser close)
- Generate strong
CRON_SECRET:openssl rand -hex 32 - Set strong
ADMIN_PASSWORD(12+ characters, mixed case, numbers, symbols) - Obtain valid
OPENROUTER_API_KEY - Set
NODE_ENV=production - Verify
.env.localhas 600 permissions - Verify
.env.localis gitignored - Consider restricting
/etc/cron.d/forecasterarenapermissions
- Verify no default secrets in use (check console warnings)
- Test cron endpoints return 401 without valid auth
- Test admin login with correct and incorrect passwords
- Verify API keys are not exposed in logs
- Check file permissions on database and backups
- Rotate
CRON_SECRETif exposed (update both .env.local and crontab) - Rotate
ADMIN_PASSWORDperiodically - Monitor API costs and usage patterns
- Review system logs for suspicious activity
Limitation: Designed for single-server deployment, not multi-tenant.
Implications:
- No user isolation between agents (intentional - they're all part of the benchmark)
- Admin dashboard has single password (not multi-user)
- Cron jobs run as root or www-data
Acceptable because:
- Research platform, not production service
- No real money or sensitive user data
- Single administrator expected
Limitation: Database file must be readable by web server user.
Implications:
- File permissions allow www-data to read/write
- No row-level security or access control
- Backups are plain copies (not encrypted)
Acceptable because:
- All data is public (will be published in research)
- No PII or financial data
- Single-server deployment
Limitation: CRON_SECRET visible in crontab file.
Implications:
- Any user on system can read secret
- Secret must match between crontab and app
- Changing secret requires updating both files
Mitigation:
- Single-user or trusted server environment
- File permissions restrict .env.local
- Consider wrapper script (see recommendations above)
If you discover a security vulnerability, please:
- Do NOT open a public GitHub issue
- Email: [security contact - add if available]
- Include:
- Description of vulnerability
- Steps to reproduce
- Potential impact assessment
- Suggested fix (if available)
We will respond within 48 hours and work on a fix.
-
Never commit secrets
- Use environment variables
- Check
.gitignoreincludes.env*.local - Use
.env.examplefor documentation only
-
Validate all inputs
- Use TypeScript for type safety
- Validate API request bodies
- Sanitize SQL queries (use parameterized queries)
-
Handle errors securely
- Don't expose stack traces in production
- Log errors server-side
- Return generic error messages to clients
-
Use constant-time comparisons
- For password/secret comparison
- Prevents timing attacks
- Example:
secureCompare(a, b)nota === b
- Keep dependencies updated:
npm audit - Review dependency changes before updating
- Pin critical dependency versions
- Use
npm ciin production (notnpm install)
- All queries use parameterized statements
- Foreign key constraints enforced
- Transactions for multi-step operations
- Regular backups (automated via cron)
Data Collected:
- Admin session cookies (temporary, not PII)
- LLM decision logs (prompts and responses - no PII)
- Market data from Polymarket (public information)
- System logs (API calls, errors - no PII)
Data NOT Collected:
- User personal information
- User financial information
- User behavioral tracking
- Third-party analytics
Conclusion: Minimal privacy concerns. All data is either public or operational.
OpenRouter:
- Respect rate limits
- Use API key securely
- Monitor costs
- Attribution in research publications
Polymarket:
- Public API, no authentication required
- Respect rate limits (500 req/hour)
- No data scraping beyond stated purpose
- Market data used for research only
- Generate new secret:
openssl rand -hex 32 - Update
.env.local - Update
/etc/cron.d/forecasterarena - Restart application:
sudo systemctl restart forecaster-arena(orpm2 restart) - Monitor logs for unauthorized cron calls
- Review recent cron job executions
- Change password in
.env.local - Restart application
- Clear all admin sessions
- Review admin dashboard access logs
- Revoke key at https://openrouter.ai/settings/keys
- Generate new key
- Update
.env.local - Restart application
- Monitor API usage for suspicious activity
- Review recent API costs
- Stop application immediately
- Assess extent of compromise
- Restore from known-good backup
- Review all recent changes
- Check for data exfiltration
- Rotate all secrets
- Document incident for analysis
| Date | Auditor | Findings | Status |
|---|---|---|---|
| 2024 | Internal | Default secrets, timing attacks | Fixed |
| - | - | Crontab permissions | Documented |
Last Updated: 2025-12-11 Version: 1.0