Do not open a public issue for a security problem.
Report privately through GitHub's private vulnerability reporting: go to the Security tab of this repository and choose Report a vulnerability. If that is unavailable, contact a maintainer privately and ask for a secure channel before sending details.
Please include: what you found, the steps to reproduce it, the affected version or commit, and the impact you believe it has.
Expected response times. Acknowledgement within 5 working days, an initial assessment within 10 working days, and a fix or a documented mitigation before any public disclosure. Please give us a reasonable window to ship a fix before disclosing publicly.
Only the latest commit on main receives security fixes. There are no
maintained release branches.
Work through this before exposing an instance to anything other than localhost.
-
DJANGO_SECRET_KEYis set to a unique, randomly generated value. Generate one with:python -c "from django.core.management.utils import get_random_secret_key as k; print(k())" -
OPENAI_API_KEYis set from your secret store, not committed to the repo and not baked into an image layer. -
.envis not committed. Confirm withgit check-ignore -v .env. - No
VITE_-prefixed variable holds a secret — Vite inlines them into the public JavaScript bundle at build time.
-
DEBUG=False. WithDEBUG=Truethe app falls back to a publicly known development signing key and serves full tracebacks. -
ALLOWED_HOSTSlists your real hostnames.*is rejected outright whenDEBUG=False. -
CORS_ALLOWED_ORIGINSlists only the origins that must call the API. -
CSRF_TRUSTED_ORIGINSlists your HTTPS origins. -
SECURE_SSL_REDIRECT=Trueunless TLS is terminated by a proxy that already redirects. HSTS, secure cookies and the proxy SSL header are enabled automatically whenDEBUG=False. - Run
python manage.py check --deployand resolve every warning.
- The API sits behind a gateway that enforces authentication and rate limiting. There is none in this codebase, and every request spends OpenAI credits — an open instance is a direct billing risk.
- A spending limit is configured on the OpenAI account.
-
/admin/is either disabled, IP-restricted, or protected by a strong password and MFA. No app models are registered there, but Django's own auth models are.
- Containers run as the non-root users defined in the Dockerfiles; do not
override with
user: root. - The database is not reachable from the public internet.
- Dependencies are current:
pip list --outdatedandnpm audit.
This application is deliberately stateless:
- It defines no database models and persists no user content.
- Keywords, topics and generated articles exist only for the lifetime of the request and in the user's browser URL.
- Keywords and topic titles are transmitted to OpenAI as prompts. Review OpenAI's data-usage policy before processing anything confidential.
- Application logs record request metadata and error messages. They may contain
the keyword a user submitted; set
LOG_LEVELand your log retention accordingly.
An earlier, non-public version of this project collected contact-form submissions (names, emails, free-text messages) into a database table and a CSV file. That feature, its model, its migration and its stored data were removed before this repository was published.