| Version | Supported |
|---|---|
main (latest) |
Yes |
If you discover a security issue, do not open a public GitHub issue. Instead, email the maintainers directly:
Include:
- A description of the vulnerability
- Steps to reproduce
- What you think the impact is
We will acknowledge within 48 hours and provide a fix timeline within one week.
This application is a FastAPI + Jinja2 + ECharts dashboard deployed on Vercel with a Neon Postgres database. It validates student GitHub accounts and builds their analytics from synced profile data — accounts are linked through OAuth during onboarding and refreshed by scheduled syncs (there is no spreadsheet upload step).
- Google OAuth (primary) — college-domain gated via
ALLOWED_OAUTH_DOMAINSenv var;hdandemail_verifiedclaims are always enforced server-side. - Email/password (fallback) — PBKDF2-SHA256 with 120,000 iterations and per-password random salt.
- GitHub & LinkedIn OAuth — account linking only (not login); CSRF-protected via HMAC-signed state nonces.
- Sessions — HMAC-SHA256 signed cookie tokens with 7-day TTL,
httponly,secure, andsamesite=laxflags. - Roles —
admin,faculty,student. Admin/faculty are bootstrapped viapython -m app.seed_users; public signup is student-only.
All secrets are loaded from environment variables or .env.local (gitignored). The app auto-loads .env.local at startup (app/env.py). Under pytest the loader is a no-op.
| Secret | Source |
|---|---|
AUTH_SECRET |
Session HMAC key; if unset, a random per-process key is generated (sessions don't survive restarts) |
GITHUB_TOKEN |
GitHub API calls; increases rate limit from 60 to 5,000 req/hr |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
Google OAuth |
DATABASE_URL / DATABASE_URL_UNPOOLED |
Neon Postgres connection strings |
CRON_SECRET |
Authenticates Vercel cron triggers (constant-time HMAC comparison) |
UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN |
API response cache |
Never hardcode secrets in any tracked file. The secrets file (.env.local) is in .gitignore.
- All SQL queries use parameterized placeholders (psycopg3
%sfor Postgres, SQLite?). - User input IDs (ticket IDs, limits) are cast to
int()before use; limits are clamped tomax(1, min(limit, 1000)). - HTML output is escaped via the
escape()helper (app/ui_helpers.py). - File uploads (support-ticket attachments, profile images) are validated for size (20 MB limit) and type by magic bytes, not just the file extension.
- GitHub API responses are cached with SHA-256 keyed on URL + token; the token is never stored in plaintext.
- Database connection URLs are redacted before logging (only hostname is shown).
The following headers are set on all responses via vercel.json:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadX-Content-Type-Options: nosniffX-Frame-Options: DENYX-XSS-Protection: 1; mode=blockReferrer-Policy: strict-origin-when-cross-origin
If the domain is proxied through Cloudflare, the recommended settings are:
- WAF Managed Ruleset enabled; rate limiting on
/api/*and/login - SSL/TLS mode: Full (strict); Minimum TLS version: 1.2
- Bot Fight Mode enabled
- DNSSEC enabled; all relevant DNS records proxied (orange-clouded)
- Sensitive paths (
/api/*,/admin/*) excluded from caching with Browser Integrity Check enabled
- Exposure of tokens or secrets in code, logs, error messages, or API responses
- Unsafe handling of user-supplied data (arbitrary code execution, XSS, SQL injection)
- Server-side request forgery through the GitHub API integration
- Authentication or authorization bypass (session forgery, role escalation)
- OAuth state validation bypass (CSRF on OAuth flows)
- Insecure cookie attributes (missing
secure,httponly, orsamesiteflags)
- Client-side CSS/visual issues
- Rate limiting on the GitHub API (an inherent platform constraint, not a bug in this app)
- Denial of service via large file uploads (mitigated by the 20 MB upload limit)
Dependencies are pinned in requirements.txt with exact versions. Dependabot and CodeQL are enabled on the repository. If you discover a known vulnerability in a pinned dependency, report it using the process above and we will evaluate an upgrade.