Security
This page describes the protections actually in place in Borhan — and states plainly what is not there yet. An overstated security claim is more dangerous than the missing feature itself.
Last updated: 22 July 2026
Passwords and sessions
- Passwords are hashed with argon2id — the winner of the Password Hashing Competition, and the most resistant to GPU cracking.
- Access tokens are short-lived (15 minutes by default).
- Refresh tokens are stored hashed, and are revoked the moment they are used and replaced — so if one leaks and is used once, the second use fails.
- Disabling an account revokes every token on every device immediately.
- Changing a password ends every open session.
- Password reset links are single-use, expire within 30 minutes, and are stored hashed.
Isolation between centres
Each centre is an independent workspace. Isolation is enforced at the level of every database query, not by hiding elements in the interface — the distinction matters: one centre cannot reach another's data even by editing the request by hand.
An attempt to reach a resource belonging to another centre returns "not found" rather than "forbidden" — so that we do not reveal even whether the resource exists.
Content protection
Lesson videos are not available at direct URLs. Every link is:
- Signed with HMAC and tied to the viewer's own account — a link forwarded to another account does not work.
- Expiring within minutes, not hours.
- Issued only after confirming the student is actually enrolled in the course.
What we cannot guarantee: preventing someone filming the screen with another device. Any content shown on a screen can be photographed with a phone. We block screen recording on Android as a deterrent, but that is a deterrent and not a guarantee — and any platform claiming otherwise is misleading you.
Payments
- Card data never passes through our servers — payment happens on the provider's pages.
- Every webhook has its signature verified against the raw bytes before any processing.
- Every processed event is recorded, so a redelivery does not create a duplicate transaction.
- Granting access happens as a side effect of a completed payment, and cannot be triggered from the client.
Application-level protection
- All traffic over HTTPS.
- Standard security headers via Helmet.
- An explicit allowlist of permitted origins (CORS); the production default is same-origin only.
- Rate limiting, with a stricter cap on sign-in and password-reset endpoints.
- Any unexpected field in a request is rejected rather than silently ignored.
- Internal error messages are never shown to the user — they are logged on the server only.
- API documentation (Swagger) is disabled by default in production.
Not implemented yet
We list this plainly because transparency here is more useful than a polished feature list:
- Two-factor authentication (2FA) — not currently available.
- A complete audit trail of staff actions — in development.
- Application-level encryption of secrets stored in centre settings — not implemented; do not put provider keys there.
- Error tracking and operational monitoring — not yet connected.
- External security review or independent penetration test — has not been carried out.
Reporting a vulnerability
If you find a vulnerability, write to security@borhan.app before any public disclosure. We respond within 72 working hours, and we value responsible disclosure.
Please do not run any penetration test against the production environment without prior written permission — it holds real student data.