Skip to content

Security: fercarballo/performance-reliability-testing-suite

Security

SECURITY.md

Security Policy

This is a portfolio / demonstration project. It is designed to run locally or in CI with synthetic data only. It is not hardened for production exposure on the public internet. That said, security was treated as a first-class concern and the repository is built to pass an audit on the things that matter for a public repo: no secrets, no real data, minimal-privilege CI, and dependency/secret/image scanning.

What is and isn't a secret here

Value Status
JWT_SECRET=dev-only-secret-change-me Not a secret. A clearly-labelled local-only placeholder. Real deployments must inject a strong secret via the environment.
password123 (synthetic users) Not a secret. A shared password for deterministic, fake users. No real account uses it.
POSTGRES_PASSWORD=telco Not a secret. Local-only database credential for the compose stack.
.env Never committed. Git-ignored; only .env.example (placeholders) is tracked.

No real customer data exists anywhere in this project — all data is generated by a deterministic synthetic generator.

Controls in place

  • No secrets in git. .gitignore excludes .env and all real env files; .gitleaks.toml + a CI secret-scanning job guard against accidental commits.
  • Dependency scanning. npm audit (production deps), GitHub Dependency Review on PRs, and Dependabot updates (npm, GitHub Actions, Docker).
  • SAST. CodeQL (javascript-typescript) on push/PR and weekly.
  • Container scanning. Trivy scans the API image for HIGH/CRITICAL CVEs.
  • Least-privilege CI. Workflows default to contents: read; jobs elevate only what they need (e.g. CodeQL's security-events: write). Checkout uses persist-credentials: false.
  • Hardened runtime. The API container runs as a non-root user (USER node), uses Helmet for HTTP security headers, validates all input with Zod, and redacts secrets (password, tokens, authorization) from logs.
  • AuthN/AuthZ. JWT-based auth; a customer can only access their own resources (cross-customer access returns 403).
  • Idempotent payments. A UNIQUE idempotency key prevents double-charges, correct even under concurrent retries.

Deliberate, documented trade-offs

These are intentional choices for a performance lab, called out so they are not mistaken for oversights:

  • Fast password hashing (SHA-256), not bcrypt/argon2. A slow KDF would dominate login latency and the load test would measure the hash, not the system. A real product MUST use a slow, salted KDF. See apps/api/src/security/password.ts.
  • Fault injection endpoint (/admin/faults). Powerful and intentionally unauthenticated for demo convenience, but only mounted when NODE_ENV !== 'production' and ENABLE_FAULTS=true. It cannot exist in a production build, auto-expires every rule, and audits every activation.
  • Permissive CORS (origin: true) and anonymous Grafana. Local-demo conveniences. Both must be locked down for any real deployment.

If you deploy this for real (don't, but if you must)

  1. Inject a strong JWT_SECRET and real database credentials via a secrets manager — never the defaults.
  2. Set NODE_ENV=production and ENABLE_FAULTS=false (the /admin/faults surface disappears).
  3. Replace the fast password hash with argon2id/bcrypt.
  4. Restrict CORS to known origins; put Grafana behind real auth.
  5. Terminate TLS at a reverse proxy; do not expose Postgres/Redis ports.

Reporting a vulnerability

This is a personal demo repository. If you spot something, please open a GitHub issue (for non-sensitive findings) or contact the maintainer directly for anything sensitive. There is no production system at risk.

There aren't any published security advisories