Last updated: 2026-05-15
Cyber Command Center is a free cybersecurity training tracker. This policy documents the current security model, data lifecycle, incident reporting process, and known limits so the product's security posture is explicit instead of implied.
This is a portfolio and training workflow project. It is not currently a certified enterprise platform, a managed SOC service, or a system for storing sensitive client data, lab credentials, exploit material, payment details, or production incident evidence.
Security reports are in scope for:
- The React/Vite web app in this repository.
- The self-hosted Fastify API under
api/. - The PostgreSQL schema under
api/migrations/. - Authentication, guest mode, account sync, progress tracking, task notes, study session logging, export, and deletion.
- Deployment configuration in
netlify.toml,Dockerfile,api/Dockerfile,docker-compose.remote.yml, and static policy pages underpublic/.
Out of scope:
- Third-party learning platforms linked from the curriculum.
- Denial-of-service testing, spam, social engineering, physical attacks, or attacks against accounts you do not own.
- Findings that require storing real secrets, client data, malware, payment data, or private incident data in the app.
- Account identity: user ID, email address, optional display name, and optional Google OAuth subject.
- Session state: hashed session tokens and CSRF token hashes in the backend database.
- Training progress: completed task IDs and completion timestamps.
- Task notes: free-text notes entered by the user.
- Study sessions: timer labels, duration, dates, and created timestamps.
- Guest data: local browser keys
ccc_progress,ccc_notes, andccc_sessions.
- Browser guest mode is local-only. Guest progress, notes, and session data stay in
localStorageand are not synced by the app. - Signed-in mode sends account progress, notes, and session logs to the self-hosted API at
https://c3-api.mdpstudio.com.au. - PostgreSQL is reachable only from the private Docker network. It must not expose a public host port.
- The browser never receives database credentials, Google client secrets, SMTP secrets, service-role keys, or backup credentials.
- Netlify serves the static frontend and applies the security headers configured in
netlify.toml.
- Optional guest mode lets users avoid account creation.
- Email/password auth and Google OAuth are handled by the self-hosted API.
- Passwords are stored only as bcrypt hashes.
- Session cookies are
HttpOnly,Securein production,SameSite=Lax, and backed by hashed server-side session tokens. - State-changing signed-in routes require a valid session, an allowed
Origin, and a CSRF token. - API data routes derive the user from the session, not from client-provided user IDs.
- Account deletion runs server-side and deletes the user row, cascading app data through PostgreSQL foreign keys.
- Password reset tokens are hashed in the database, short-lived, and single-use.
- Google OAuth validates state, nonce, issuer, audience, expiry, and verified email before login.
- Notes are rendered through React text nodes and textarea values, not raw HTML injection paths.
- External curriculum links use
target="_blank"withrel="noopener noreferrer". - Netlify security headers set frame denial, MIME sniffing protection, strict referrer policy, and a restrictive permissions policy.
- A
Content-Security-Policy-Report-Onlyheader is shipped fromnetlify.tomlandnginx.conf, restricted to the frontend, Google Fonts, andhttps://c3-api.mdpstudio.com.au.
- There is no formal compliance certification, uptime SLA, DPA, SSO/SAML, audit-log export, or enterprise admin console.
- The backend must not be treated as production-ready until the remote Docker health check, Cloudflare Tunnel route, backup restore test, Supabase import dry-run, and migrated-user smoke tests pass.
- The CSP remains report-only until production smoke tests pass. After that, promote it to enforcing
Content-Security-Policy. - SMTP is required for production password reset emails.
AUTH_LOG_RESET_LINKS=trueis development-only. - Incident response is currently manual.
- Task notes are free text. Users should not store passwords, API keys, customer data, private lab flags, payment data, or live incident evidence in notes.
The current policy is shipped as Content-Security-Policy-Report-Only from both netlify.toml and nginx.conf.
default-src 'self',object-src 'none',frame-ancestors 'none',base-uri 'self'.script-src 'self'.style-src 'self' 'unsafe-inline' https://fonts.googleapis.com.font-src 'self' https://fonts.gstatic.com data:.img-src 'self' data: https:.connect-src 'self' https://c3-api.mdpstudio.com.au.form-action 'self' https://accounts.google.com.report-uri https://c3-api.mdpstudio.com.au/api/csp-report.
The signed-in dashboard exposes a Privacy Controls section with two actions:
- Export My Data: downloads a JSON snapshot of the user's profile, task progress, task notes, and study sessions. In guest mode, the same button dumps the
ccc_progress,ccc_notes, andccc_sessionslocalStorage keys. - Delete My Account: opens a "type DELETE to confirm" modal. On confirmation it calls the backend deletion route, deletes the account and user-scoped app data, clears guest localStorage keys defensively, and reloads. In guest mode the same flow clears localStorage and reloads.
Deleted records may remain in provider-managed backups for the normal backup retention window.
- Stored data: progress, notes, and session logs in browser
localStorage. - Storage location: the user's browser only.
- Retention: until the user clears site data, browser storage, or the browser profile.
- Deletion path: clear browser storage for
https://c3.mdpstudio.com.auor use the Privacy Controls panel in guest mode. - Sync: none.
- Stored data: account identity, hashed password if email/password is used, Google subject if OAuth is used, task progress, task notes, study sessions, sessions, reset tokens, and CSP reports.
- Storage location: self-hosted PostgreSQL in Docker on the remote PC.
- Retention: kept until the user deletes the account or the project owner removes the account/data.
- Deletion path: Privacy Controls panel or manual owner action.
- Backup note: deleted records may remain in backups for the configured backup retention window.
- Do not request or store payment details.
- Do not request or store client-private material.
- Do not request or store lab credentials, API keys, passwords, seed phrases, SSH keys, cloud secrets, or exchange keys.
- Do not use task notes as an incident evidence repository.
Report security issues to meidie@mdpstudio.com.au with the subject:
Security report: Cyber Command Center
Include:
- Affected URL or file path.
- Steps to reproduce.
- Expected result and actual result.
- Browser/device details if relevant.
- Screenshots or logs with secrets removed.
- Whether you tested in guest mode or a signed-in account you own.
Do not include passwords, API keys, private account data, payment details, client data, or third-party platform secrets. Do not publicly disclose an unfixed issue until it has been triaged.
Response is best effort for a portfolio project. Security reports are prioritized over feature requests, and the current target is to acknowledge actionable reports within five business days.
Before shipping security-sensitive changes:
- Confirm
.env,.env.production, migration exports, and secrets are untracked. - Run
npm test. - Run
npm run build. - Run
npm audit. - Run
npm run api:migrateagainst the target database. - Verify
/api/healthlocally and throughhttps://c3-api.mdpstudio.com.au. - Verify migrated Google and email users can access their data.
- Verify backup creation and one restore dry run.
- Re-check the CSP directive list in
netlify.tomlandnginx.confwhen adding any new external script, style, font, image host, API host, OAuth provider, or form action.