Please do not open a public issue for security problems.
Report privately through GitHub's private vulnerability reporting: open the repository's Security tab and choose Report a vulnerability. Only the maintainers can see the report.
Please include:
- what the issue is and roughly how severe you think it is,
- the steps or a proof of concept needed to reproduce it,
- affected version or commit,
- any suggested fix.
What to expect: acknowledgement within 7 days, an assessment within 30 days, and credit in the fix notes unless you would rather stay anonymous. Please give us a reasonable window to ship a fix before disclosing publicly.
- Vulnerabilities in the Hugging Face, Mistral or Google reCAPTCHA services themselves — report those to those vendors.
- Findings that require a deliberately misconfigured deployment, such as running
with
DEBUG=Truein production. - Missing rate limiting and missing authentication. Both are known and documented gaps; see README Limitations.
Work through this before exposing an instance publicly.
-
DJANGO_SECRET_KEYset to a freshly generated random value, unique per environment. Generate with:python -c "from django.core.management.utils import get_random_secret_key as k; print(k())" -
DEBUG=False. With debug on, Django serves tracebacks containing settings and environment data to anyone who triggers an error. -
DJANGO_ALLOWED_HOSTSlists your real hostnames. Never*. -
CORS_ALLOWED_ORIGINSlists only origins you control. Never*. -
CSRF_TRUSTED_ORIGINSset when serving behind a proxy or on a subdomain. - No
.envfile committed.git statusis clean before every push. - Compose defaults replaced —
docker-compose.ymlships a placeholder secret for local use only.
The application refuses to start when DEBUG=False and either
DJANGO_SECRET_KEY or DJANGO_ALLOWED_HOSTS is missing. That is deliberate:
failing loudly beats running on a predictable key.
- HTTPS terminated in front of the app.
-
SECURE_SSL_REDIRECT=True(default), orFalseonly when a proxy already redirects. - HSTS enabled via
SECURE_HSTS_SECONDS(default one year). Confirm every subdomain is HTTPS-ready before enabling preload. - Run
python manage.py check --deployand resolve every warning.
- Rate limiting in front of
/recognition/— a gateway, WAF or reverse proxy. No limiting exists in the application, and every request costs money at Hugging Face and Mistral. - Authentication in front of the API if it is not meant to be public.
-
/admin/restricted by IP or removed fromurls.pyif unused. - A strong password on any Django superuser you create.
-
HUGGINGFACE_API_KEYandMISTRAL_API_KEYsupplied via environment or a secrets manager, never committed. - Keys scoped to the minimum permission each provider offers.
- Spending limits or billing alerts configured at both providers.
- Keys rotated on any suspicion of exposure — including any key that was ever committed to a repository that was pushed anywhere.
This project collects personal data through the contact form. See README Privacy.
-
CSV_DIRpoints outside any web-served directory. - Filesystem permissions restrict that directory to the service account.
- Backups of it are encrypted.
- A retention and deletion policy exists and is actually applied.
- Your privacy notice discloses the contact-form collection, the CSV export, Google reCAPTCHA (visitor IP addresses), and the transmission of uploaded images to Hugging Face and Mistral.
- Images rebuilt from the current base images so OS patches are picked up.
- Containers run as the non-root user the Dockerfiles define — do not
override with
user: root. - The
backend-datavolume, which holds the SQLite database and the CSV export, is backed up and access-controlled.
-
pip-audit -r backend/requirements.txtreports no known vulnerabilities. -
npm auditinfrontend/reports no known vulnerabilities. - Both re-run on a schedule, not only at release.
This project has not yet cut a tagged release. Until it does, security fixes
land on main only.