SECURITY
Security
This statement describes the security controls presently implemented in the Service — where your data is stored, how your Account and payments are protected, and who on our side can access data. It is also our coordinated-disclosure channel: Section 8 states how to report a Vulnerability and what we commit to in return.
1. Scope and definitions
This statement covers the security of flightway.ai and its server endpoints. It is a technical and operational description, not an inventory of the data itself; the categories of data collected, the purposes, the recipients, and the retention periods are set out in the Privacy Policy. In this statement:
- "FlightWay," "we," "us," or "our" means FlightWay, Inc.
- "Service" means flightway.ai and every application and feature offered through it.
- "you" or "User" means the individual who accesses the Service.
- "Personal Data" has the meaning given in the Privacy Policy.
- "AI Provider" means Google LLC, operating the Gemini API — the sole AI provider used by the Service.
- "Vulnerability" means a security weakness in the Service capable of affecting the confidentiality, integrity, or availability of data or of the Service.
2. Data storage and transport
The entire Service operates on Cloudflare's network. There is no on-premises server, no second cloud account, and no data warehouse. Four locations hold data concerning you:
| Location | Contents |
|---|---|
| Cloudflare Pages | The site itself and every server endpoint. Code, not data. |
| Cloudflare D1 (SQLite) | The durable record: your email and password hash, your sessions, your profile, roadmap, career analyses, resumes, saved artifacts, mock-interview scores, and your plan state. |
| Cloudflare Workers KV | Working state and caches: Marco's memory of your conversations, cached AI results, rate-limit counters, and admin elevation leases. Most keys carry an expiry. |
| Your browser | A working copy of your profile, roadmap, quiz results, resume drafts, and theme, in local storage on the device you used. See Section 9 (User responsibilities). |
2.1 In transit. The Service is HTTPS only, so all traffic between your browser and the
Service is encrypted with TLS. Our outbound calls to Google, Stripe, and Resend are likewise HTTPS. The
session cookie is marked Secure, so the browser will not transmit it over a plain HTTP
connection.
2.2 At rest. Cloudflare encrypts D1 and Workers KV at rest as the platform provider; that is Cloudflare's control, not ours. Beyond it, we do not operate our own application-level encryption on individual database rows. The two items we never store in usable form — passwords and session tokens — are addressed in Section 3.
2.3 Refusal to run half-configured. Both of our Cloudflare projects can publish preview builds, and a preview build inherits the production database while receiving none of the production secrets. Every request therefore first verifies that a specific server-side secret is present; if it is not, the deployment returns a 503 and serves nothing. A deployment that was never properly configured does not answer requests against real user data.
2.4 Response headers. Static responses carry
X-Content-Type-Options: nosniff, X-Frame-Options: DENY (so that the Service
cannot be placed in a concealed iframe to induce clicks), Referrer-Policy:
strict-origin-when-cross-origin, and a Permissions-Policy that denies camera,
microphone, and geolocation outright, none of which the Service uses.
3. Account and session security
3.1 Passwords
We never store your password. When you set one, we generate a fresh 16-byte random salt and derive a 256-bit key using PBKDF2 with HMAC-SHA-256 at 100,000 iterations. The database holds the algorithm, the iteration count, the salt, and the derived hash — nothing that can be reversed into your password. Verification recomputes the derivation and compares the result in constant time, so that the comparison itself reveals nothing about the proximity of a guess.
An attempt to sign in with an email address that has no Account still runs a full PBKDF2 verification against a dummy hash. This is deliberate: without it, the difference in response time would disclose which email addresses are registered.
The only rule we enforce on passwords is a minimum of eight characters. We do not check your password against lists of previously breached passwords, which is why uniqueness matters more than complexity — see Section 9 (User responsibilities).
3.2 Sessions
When you sign in, we generate a session token from 32 bytes of cryptographically secure randomness. The token is delivered to your browser in a cookie. The database never stores the token. It stores only a SHA-256 hash of the token combined with a server-side secret (a "pepper") held in Cloudflare's secret store — not in this repository, not in the database, and not in any backup of the database. Consequently, a party who obtained a copy of our database could not reconstruct a working session from any row in the sessions table.
The cookie is set with exactly these attributes:
HttpOnly— page JavaScript cannot read it, so a script injection cannot lift your session.Secure— transmitted over HTTPS only.SameSite=Lax— not sent with cross-site requests initiated by another site.Path=/andMax-Age=2592000— a 30-day lifetime.
The 30-day expiry is also enforced on the server against the stored expiry time, not merely by trusting the cookie: when an expired token is presented, the session row is deleted and the request is treated as signed out. Signing out deletes the row and clears the cookie. Resetting your password destroys every session on every device. Deleting your Account does the same.
3.3 Password resets
A reset link carries 32 bytes of random token, emailed to the address on the Account. We store only a SHA-256 hash of it. It is valid for one hour, may be used once, and requesting a new one immediately invalidates the previous one. We also rate-limit reset requests — see Section 5 (Abuse prevention and rate limiting).
3.4 Account deletion
You may delete your Account yourself from your home page, with no email to us and no waiting period. It removes your Account and the records attached to it across our database and our key-value store, and destroys every session. It is a best-effort purge, store by store, and a small number of records are not reached today; the Privacy Policy enumerates exactly what is and is not covered.
4. Payment security
Payments are processed through Stripe, using Stripe's own hosted checkout page. When you purchase a plan, your browser is handed to Stripe, and your card number, expiry, and CVC are entered on Stripe's page, not ours.
- Card details never reach our servers. We do not receive them, we do not log them, and no column anywhere in our database can hold a card number.
- What we transmit to Stripe is your email address and the plan you selected.
- What we store in return is a Stripe customer identifier and your plan state — which plan, when it expires, and whether it resulted from a purchase or was granted by us.
- Changing or cancelling a plan directs you to Stripe's own customer portal, using that stored customer identifier.
Stripe notifies us of payments by calling a webhook endpoint on our side. Because Stripe calls it, that
endpoint has no session to check, and the signature is therefore the authentication. Every request must
carry Stripe's Stripe-Signature header; we recompute the HMAC-SHA-256 over the timestamp and
the raw request body using the endpoint's signing secret, compare it in constant time, and reject anything
older than five minutes so that a captured request cannot be replayed. No byte of the body is trusted
before that check passes, and an unverified request can never move your plan. Each event's identifier is
also claimed in a table before it is handled, so that a retried delivery is processed exactly once.
5. Abuse prevention and rate limiting
Every limit below is enforced on the server, within the endpoint itself. None resides in the browser, so a modified client cannot bypass it. Counters are held in Workers KV on a one-hour rolling window. The sign-in family is keyed by IP address and by email address simultaneously, so that neither one address attacking many Accounts nor many addresses attacking one Account passes through; the remaining endpoints are keyed on whichever of the two identifies the caller.
- Sign in, register, reset password: 10 attempts per hour per IP address and 10 per hour per email address. This control renders credential stuffing and password guessing impractical.
- Endpoints that incur cost. Every AI feature carries its own ceiling — for example, 30 mock-interview requests per hour, 20 per hour for the resume tools, and 60 per hour for a coach conversation. In addition to the hourly limits, metered features carry per-Account daily caps enforced with an atomic daily counter.
- Endpoints that send email. The quiz-results email and the password-reset email are limited by IP address and by recipient address, so that the Service cannot be used to direct mail at a third party.
- The contact form permits five messages per hour from the same sender. That is one limit, not two: a contact message is delivered only to our own inbox, so there is no recipient to protect. The counter is keyed on a peppered hash of your IP address rather than the address itself, because a rate-limit key becomes part of a key name we store, and hashing it first keeps a raw IP out of that store. On deployments where a site key is configured, the form additionally requires a Cloudflare Turnstile challenge.
- Administrative actions carry their own separate, tighter limits in addition to all of the foregoing.
Two further points. Where a request fails because of a fault on our side, we return the attempt rather than charge you for a failure you did not cause. And these are abuse controls, not a web application firewall: volumetric attacks and network-level filtering are handled by Cloudflare as our host, which is Cloudflare's control, not ours.
6. Personnel and administrative access
FlightWay is a small team, and production access is narrower than the team: a few people who operate the Service can reach the live database. We connect no third-party support desk, session-replay tool, or customer-data platform to production; there is no vendor seat that reads your profile.
There is an internal admin console, built to present a small target:
- A single root address, held outside the database. The root admin is an email address set as an environment variable in Cloudflare. It is not a row that anyone can write. No database write — including one made through a compromised admin account — can make a person root, and the root address cannot be demoted, revoked, or targeted by any admin action.
- 404 to everyone else. Every admin endpoint returns a plain "not found" to anyone who is not an admin, including signed-in Users. A 401 or 403 would confirm that the console exists; a 404 discloses nothing.
- A stolen cookie is insufficient. Before any change can be made, the admin must re-enter their own password to obtain a 15-minute elevation lease. A session cookie alone can read but cannot act, and failed elevation attempts are recorded — a run of them is precisely the signal that a session has been taken.
- All actions are audited. Every admin action writes an append-only log row: who acted, what they did, to whom, and when.
- The surface is minimal. The console can grant and revoke complimentary plans, add and remove admins, and read the audit log. That is the entire set of functions. No screen within it browses your profile, your resume, or your coach history.
Cloudflare, as the host, necessarily receives request metadata including your IP address. Our own code uses your IP address only as a rate-limit key or stores it as a salted hash; we do not write raw IP addresses into the database.
7. Artificial intelligence and your data
The Service's AI features operate on the AI Provider's Gemini API, which is the only AI provider used.
7.1 Data transmitted. Each feature transmits the context it requires. The identity block assembled for advice prompts is your name, year, GPA, subjects or major interests, career leaning, and school. In addition, depending on the feature: your messages to Marco and the durable notes Marco keeps about your goals; your quiz answers; your resume text — and, where you upload a resume file, the contents of that file, which include whatever contact details you placed on it; a job posting you paste into the tailoring tool; and your answers during a mock interview. Where the Opportunity Finder is enabled on your Account, the research question that feature constructs from your request is transmitted to the Gemini API with web search enabled, so that Google runs a search with it, and that query may contain names you mentioned, such as a school or a firm.
7.2 Data not transmitted. Your password, in any form. Your session token. Your card details, which we do not have. Your email address is not part of the identity block we build for prompts, though it will travel with your resume where your resume contains it.
7.3 Training. FlightWay does not train models on student data. We do not train models at all; we call an API. What Google may or may not do with data submitted to that API is governed by Google's terms for the Gemini API. We do not paraphrase another company's terms as our own commitment: we can state what we transmit and why, and we cannot make commitments on Google's behalf.
7.4 Marco's memory. Marco retains a short dossier of durable facts about you, together with recent conversation state, so that it does not repeat the same question. That data resides in Workers KV and persists until you delete your Account.
7.5 Do not submit secrets. Anything you enter into Marco is stored and transmitted to Google. Do not enter passwords, API keys, card or bank numbers, or government identification numbers; none of it improves the advice. Likewise, do not enter another person's Personal Data — a contact's details, a recommender's draft letter, a classmate's grades. That data is not yours to submit to a third party, and Marco does not require it to assist you.
8. Vulnerability disclosure
If you have identified a Vulnerability, report it to us.
Email [email protected] with SECURITY in the subject line. That is the fastest route and reaches a person. If you prefer a form, /contact reaches the same destination; include SECURITY in the message so that it is prioritized.
8.1 What to include
- The URL or endpoint involved, and the browser or tool you used.
- Steps to reproduce it, in sufficient detail to follow.
- What an attacker could actually do with it — the factor that sets our priority.
- A proof of concept, if you have one. A screenshot or a single request is sufficient.
- Whether you intend to publish, and approximately when, so that we are not surprised.
- How you wish to be credited, or that you prefer not to be.
8.2 What we commit to
- We acknowledge your report within three business days.
- We inform you of our conclusion, including if we determine that it is not a Vulnerability, and why.
- We inform you when it is fixed.
- We credit you by name or handle if you wish, and remain silent about you if you do not.
- We do not share your identity or your report with any other party unless you ask us to.
- We will not pursue legal action against good-faith research that remains within the scope below, and we will not ask your school or employer to act against you for it. If a third party brings a claim regarding research that followed these rules, we will make clear that your testing was authorized.
- We do not pay bounties today. We state this in advance so that no one undertakes the work expecting payment.
8.3 In scope
flightway.aiand its API endpoints.- The sign-in, registration, session, and password-reset flows.
- Account and profile data access — for example, any means of reading or writing another Account's data.
- Our integration with Stripe, Google, and Resend: our endpoints, our webhook handling, our keys.
- The admin console gating, if you can locate it.
8.4 Out of scope
- Anything that touches another real User's Account or data. If you need two Accounts to demonstrate an issue, register two of your own.
- Destroying, altering, or exfiltrating data. Confirm the issue and stop; one record is proof, a database dump is not research.
- Denial of service, load testing, stress testing, or brute-forcing our rate limits to locate their thresholds.
- Social engineering of our team, our Users, our schools, or our vendors. Phishing, pretexting, and anything involving a physical location are out of scope.
- Spamming Users, including through the contact form or the results email.
- Automated scanner output with no demonstrated impact, and reports that a hardening header is missing without an exploit.
- Self-XSS, or issues that require an already-compromised device or browser extension.
- Vulnerabilities in Cloudflare, Google, Stripe, or Resend themselves. Those belong in the respective provider's disclosure program, not ours; if, however, our use of one of them is incorrect, that is within scope.
To the extent this Section has legal effect, it is governed by the laws of the state in which FlightWay, Inc. is incorporated, without regard to its conflict-of-law rules. As noted at the top of this statement, that state and the venue for any dispute remain with counsel.
9. User responsibilities
Most compromised accounts are not breached; they are accessed with a password that leaked elsewhere. Three measures on your side do most of the work:
9.1 Use a strong, unique password
Uniqueness matters more than complexity. We hash your password properly, so a copy of our database does not disclose your password; but if you reuse a password that leaked from another site, that is a door we cannot close from here. A password manager, or three or four random words you have not used elsewhere, is sufficient. We have no second factor yet, so this password is the whole of the lock.
9.2 Sign out on shared machines
On a library computer, a school laptop, or another person's browser, sign out when you are finished. Your session lasts 30 days, and closing the tab does not end it. Signing out deletes the session on our side, not only in that browser. If you believe another person has your password, change it; that signs out every device.
9.3 A substantial portion of your data resides on your device
The Service keeps a working copy of your profile, roadmap, quiz results, and drafts in your browser's local storage, on the device you used, which is what makes the Service responsive. It also means that anyone with your unlocked phone or laptop can open the page and read it without a password, so lock your device. Clearing your browser data erases that local copy; the copy on our server is unaffected, and signing in again restores it.
9.4 Verify the address bar
We request your password only on flightway.ai. Our emails are sent from
[email protected]. We will never email you to request your password, and we will never
request it over chat, over the telephone, or through the contact form. A message claiming to be from us
that does any of these is not from us; forward it to
[email protected] and we will investigate.
10. Further information
For the categories of data we collect, the purposes, the recipients, and the retention periods, see the Privacy Policy, which contains the full inventory; this statement deliberately does not duplicate it.
For any other matter — a question about this statement, a school or district review, or a request not addressed here — use /contact or email [email protected]. A member of our team reads it.