Security
Effective from 7 August 2026. Version 1.0.
LifeCraft holds records about children. That sets the bar for everything below. This page describes what we actually do, not what we aspire to, and it ends with how to tell us if you find something wrong.
In transit
Every connection to LifeCraft is encrypted with TLS. We send HTTP Strict Transport Security so browsers refuse to connect any other way. Traffic passes through an edge layer that filters known attack patterns before it reaches our servers, and an invisible challenge protects sign-up, sign-in and payment from automated abuse.
We send a strict Content Security Policy built on a per-request nonce, along with X-Frame-Options set to DENY, a restrictive Referrer-Policy and a Permissions-Policy, so the app cannot be framed, and injected scripts have nowhere to run.
Passwords and sessions
- Passwords are hashed with argon2id, a memory-hard algorithm chosen because it is expensive to attack with specialised hardware. We never store a password in a form we can read, so we can never send you your old password, only let you set a new one.
- New passwords are checked against known breached password lists before we accept them.
- Sessions are carried in a signed token, and the session is rotated whenever your privileges change.
- Sensitive actions, meaning billing changes, data export and account deletion, require you to confirm your password again even if you are already signed in.
- Every action that changes data is protected against cross-site request forgery.
- Sign-in errors are deliberately generic. We never reveal whether an email address has an account.
Rate limiting
Sign-in attempts are limited to 5 per 15 minutes per address and per account, with a delay that grows on each further attempt. One-time codes are limited to 3 per hour, are stored hashed, are single use, and expire in 10 minutes. Authenticated interfaces carry per-user quotas. The counters live in the database, so a limit cannot be sidestepped by hitting a different server.
Separation between households and institutions
Every read and write goes through a data access layer that requires the caller’s session and enforces ownership and role. There is no route or component in the product that queries the database directly, and there is no unscoped function that returns every record outside the administrative area.
Beneath that, the schema itself carries the boundary. Related rows are joined by composite foreign keys that include the owning household or institution, so the database will reject a row that tries to attach a learner to the wrong tenant. An application bug alone cannot produce a cross-tenant read, because the key would not resolve. One institution can never see another institution’s learners.
Audit logs
Significant actions are written to an append-only audit log: who acted, what they did, which resource, a one-way hash of the IP address and the browser user agent. Entries cannot be edited or deleted by the application, and the table is partitioned by month. Consent is recorded the same way, as a ledger, so withdrawing consent adds a record rather than erasing the history of what was agreed. Audit entries contain no mission content and no observations.
Data at rest
- The database runs in India and is bound to the local machine only. It is not reachable from the internet.
- The application connects with a least-privilege role that cannot alter the schema. Migrations are applied deliberately, not by the running app.
- Backups are taken nightly, encrypted, shipped off the server, held in India, and kept for 30 days.
- A restore is performed and verified every month. A backup nobody has restored is not a backup.
- We minimise what exists to lose: year of birth rather than full date of birth, no child email addresses, no profiling of minors.
Files you upload
Evidence files are private by default. They are never served from a public address. When you or a report needs one, we issue a signed link that expires in 15 minutes. File type and size are validated on upload, and location and camera metadata are stripped from evidence attached to a child before the file is stored.
Payments
We never see or store card numbers. Razorpay handles payments in India and Stripe handles payments elsewhere, and card details go to them directly. Incoming payment notifications are verified by HMAC signature against the raw request body using a constant-time comparison, and each event identifier is recorded once so a replayed or duplicated notification cannot charge or credit you twice.
The servers
Administrative access is by SSH key only, on a non-standard port, with root login disabled. The firewall allows only web traffic. Repeated failed attempts trigger an automatic ban. Security updates are applied automatically. Application containers run as non-root users with read-only file systems, no elevated privileges and explicit resource limits.
How we ship code
Every change must pass type checking, linting, unit tests, integration tests and end-to-end tests before it can merge. Static analysis and a dependency vulnerability audit run in the same pipeline, and a high-severity finding fails the build rather than raising a ticket. Releases soak on a separate staging environment before production. Deploys are zero-downtime with an immediate rollback to the previous image. Before launch we run our own penetration test and a load test and fix what they find.
Errors are reported to our monitoring service and uptime is watched externally. Logs are written so they never contain personal data, tokens or anything about a child.
What we ask of you
Use a password you have not used anywhere else. Keep the device your child uses for missions locked. Sign out on shared computers. Tell us immediately if you think someone has your credentials, and we will end every active session on your account.
Responsible disclosure
If you find a vulnerability, please tell us before you tell anyone else. Email security@lifecraft.in with enough detail to reproduce it: the address involved, the steps you took, what you observed and why it matters. Screenshots or a short recording help.
In scope
- The LifeCraft web application and its progressive web app.
- Our public interfaces, including authentication, payments and file handling.
- lifecraft.in and its subdomains that we operate.
Out of scope
- Denial of service, traffic flooding and resource exhaustion testing.
- Social engineering of our people, our customers or our suppliers.
- Physical attacks on offices or hardware.
- Reports produced only by an automated scanner, with no working proof that the issue can be exploited.
- Missing headers, version disclosure or configuration preferences with no demonstrated impact.
- Services operated by third parties, which should be reported to them directly.
Rules we ask you to follow
- Use your own test accounts. Do not access, modify, download or retain data belonging to anyone else, and stop the moment you realise you can reach it.
- Never test against an account containing a real child’s records.
- Do not degrade the service or destroy data while testing.
- Give us reasonable time to fix the issue before you publish anything about it.
What we commit to
- We acknowledge your report within 3 working days.
- We tell you our assessment and an expected fix timeline, and we keep you updated.
- We credit you publicly when the fix ships, if you want to be credited.
- We will not pursue, support or encourage legal action against anyone who researches in good faith and follows the rules above, and we will say so plainly if anyone asks us to.
We do not run a paid bounty programme at present. We would rather be honest about that than imply a reward we cannot pay.
If something goes wrong
If a breach affects your personal data, we will notify you and the regulator within the time the law requires, tell you what happened, what data was involved and what we are doing about it, and we will not minimise it. Incident handling follows a written runbook rather than improvisation.