Security and privacy
I built The Lesson Stand to hold teachers' work and teachers' money, so keeping both safe was part of the plan from the very first line of code. This page explains what protects you. A few details I keep to myself on purpose, because they would only help someone trying to break in.
This page describes the security controls behind The Lesson Stand. It names the kinds of protection and the standards we follow, but not our configuration values, because publishing exact settings would help an attacker far more than it would help you.
Everything here is in place in the code today unless it is marked At launch, which means it is on our launch checklist and will be working before the site opens. The protections are layered, so no single one is the only thing between an attacker and your data, and activity that looks wrong is recorded.
Paying and getting paid
When you pay, you type your card details into Stripe's own checkout page, not ours. Card numbers never reach our servers, so there are none here for anyone to steal. Sellers' bank details and tax forms are held by Stripe, too.
Checkout runs on Stripe's hosted checkout, so card details are entered on Stripe's pages and are never sent to, processed by or stored on our systems. Seller identity checks, bank details and tax forms are handled by Stripe Connect, and we never see bank account numbers.
Payment events reach us as webhooks, and each one's signature is verified before anything else happens, so a forged or unsigned event is thrown away. Every cent that moves is written to a read-only ledger, and each month that ledger is checked against Stripe's own totals.
Signing in and your account
Every seller and every member of our staff has to enter a code from an authenticator app when they sign in, on top of their password, so a stolen password alone won't open a store or our admin. Passwords are stored in a form that can't be turned back into the password, and anyone who keeps guessing wrong is made to wait. You'll also get an email if your account signs in from a new device.
Two-step sign-in with time-based one-time passwords (TOTP) is required for every seller and staff account, with single-use backup codes for recovery. Seller tools and the admin refuse any session that hasn't finished the second step, and that stays true when someone signs in with Google or Microsoft.
Passwords are stored with a salted, deliberately slow one-way hash (PBKDF2 with SHA-256) and have to pass strength rules when they're set. Repeated wrong passwords lock that account for a while. Separate limits per connection cover sign-in, sign-up, password resets, confirmation emails and two-step codes, so guessing at scale doesn't pay off.
The forgot-password page gives the same answer whether or not an account exists, so it can't be used to find out who has one. Reset and confirmation links work once and then expire. Session cookies are sent only over encrypted connections and can't be read by page scripts, and a sign-in from a new device sends the owner an email.
The files you buy
The files you buy are kept in private storage, not at a public web address. When you download, the site makes you a link that only works for a short time, and it stops working right away if the purchase is refunded. PDFs get a small "licensed to" line with the buyer's name, which helps sellers' work stay where it belongs.
Paid product files live in private object storage with no public access. Downloads are handed out as signed URLs that expire quickly. Before a file is released, the server checks that the link is genuine and still fresh, and that the buyer still owns the purchase. A shared or old link simply stops working, and a refund takes away access at once.
Cover and preview images are kept in a separate public store that never holds anything a buyer pays for. PDF downloads are stamped with the buyer's name and email plus the order number, only where a page's margin is empty, and ZIP downloads include a license file. Sellers can turn stamping off for a product.
What sellers upload
Every file a seller uploads is checked for viruses before anyone can buy it. If the check can't finish for any reason, the file waits for a person on our team instead of going live. We also make sure each file really is the kind of file it says it is, and that it isn't too large.
Product files are scanned for malware before they can be published, and the scan fails closed. An infected file is refused. If a scan times out or fails, the listing is held for staff review rather than let through, and the live site won't even start without its scanner set up.
File type is confirmed from the file's actual contents, not its name. Size limits apply to product files and to images, and images are checked to be real images. A file that matches one already sold by a different store is also held for a person to review.
How the site itself is protected
Every page is sent over an encrypted connection, and your browser is told never to connect to us any other way. Each change is tried out first on a separate copy of the site that has its own data, before it reaches the real one. The keys and passwords the site uses live only in the server's settings, never in our code. At launch a security network will sit in front of the site and filter traffic before it reaches us.
All traffic is encrypted with TLS. Plain HTTP is redirected, and HSTS, including subdomains, tells browsers never to fall back to an unencrypted connection. A strict Content Security Policy lets scripts and styles load only from our own site, and the pages are written without inline scripts so that policy can stay strict. Pages refuse to be shown inside other sites, and the standard browser hardening is turned on.
Every form is protected against cross-site request forgery, and everything shown on a page is escaped by default. The database is reached only through a query layer, never through raw queries built from what people type. Rich text that staff edit is cleaned with an allowlist when it's saved and cleaned again each time it's shown. When the site calls out to a seller's webhook, it only calls public HTTPS addresses, checked both when the webhook is added and on every send. Seller API keys are stored hashed.
Staging and production are separate apps with separate databases, and staging uses test-mode payment keys. Secrets come only from server configuration, and production refuses to start if a required one is missing. At launch a proxy network sits in front of our servers, with strict TLS all the way through.
Watching and testing
Every change to the site's code goes through automatic checks for known security holes before it can go live. Failed sign-in attempts are recorded, and so is every action our staff take, and the staff record can't be edited or deleted afterward. At launch server errors will alert us right away so we can fix problems quickly.
Every code change runs through automated checks, and nothing is deployed unless all of them pass. They include scanning our dependencies for known vulnerabilities, static security analysis of our own code, the framework's production deployment checklist and a test suite with a required coverage level.
Failed sign-in attempts are recorded, the framework's security events are logged, and new-device sign-ins are emailed to the account owner. Every staff moderation action, refund and fee change goes into an audit log that can be read but never edited or deleted. Some patterns, such as a sudden wave of activity aimed at one store, or a brand-new account posting contact details, are held for a person to look at.
At launch server errors are reported to us by email and by an error-monitoring service, with personal details left out, and outside scans of the running site join the code scans we already run.
Backups, and if something goes wrong
At launch the database will be backed up every night, and we'll have practiced restoring it before the site opens, so we know the backups actually work. If something ever does go wrong, we have a written plan for it, and part of that plan is telling the people affected, in plain words, what happened and what to do. I won't hide a problem from you.
At launch the database is backed up automatically every night, and a full practice restore into a separate, throwaway copy is done before opening and again after big changes. Product files sit in durable object storage that is separate from the database.
We keep a written incident response plan. It sorts problems by how serious they are, sets out how to contain them (for example rolling back a release, rotating keys in a way that signs everyone out, or pausing payouts), and lists where to look to find out what happened. When personal details may have been exposed, the plan has us notify the people affected promptly and specifically, under the breach notification rules that apply. Every incident ends with a written review and a new test that would have caught it.
Your privacy
We don't sell your data, and sellers never get buyers' email addresses. You can hide any seller privately, and they're never told. You can download a copy of everything we hold about you, or delete your account, from your account settings.
We don't sell personal data. Buyer email addresses are never shown to sellers and are left out of every seller export. When a seller writes to their followers, our site sends the email, so the addresses stay with us, and every marketing email has a one-click unsubscribe. Account email addresses are never shown publicly.
A buyer can privately hide a seller, which takes that seller's products out of the buyer's browsing and search, and the seller isn't notified. Any member can export everything we hold about them as one file, and can delete their account. Deletion erases personal details, keeps reviews under the name Former member and keeps money records with the person's name removed. Sellers and staff contact us first, so payouts can be settled. Payout, identity and tax details are held by Stripe, and error reports are sent without personal details.
Buying fairly, refunds and copyright
If you already own something, the site won't let you buy it again by accident, and an accidental double purchase is refunded right away. You can ask for a refund from your purchases page, under clear rules. If someone's work is copied, there's a copyright notice form linked at the bottom of every page.
The duplicate-purchase check runs on the server at the cart and at checkout, so an item you already own can't be bought twice by editing the page. Buying extra licenses for colleagues is still allowed on purpose, and an obvious accidental duplicate is refunded at once.
Refund requests follow a set process, with a deadline for the seller to answer and staff review for buyer-protection cases. A refund takes away download access immediately, and chargebacks are recorded and handled the same way every time.
Copyright complaints come in through a DMCA notice form that asks for everything the law requires. A takedown locks the listing and records a strike, counter-notices are forwarded to the person who complained, and repeat infringement pauses a store. At launch Our DMCA agent registration with the U.S. Copyright Office is underway.
Found a security problem? Tell us
If you think you've found a security problem, please tell us at security@lessonstand.com. That address is coming soon, and until it's working, please use our contact form.
Please report suspected vulnerabilities to security@lessonstand.com. This address is coming soon, and until it's live, please use our contact form. Tell us how to reproduce the problem and what you saw.
For notices by mail: The Lesson Stand, PO Box 310204, Enterprise, AL 36331.