Last updated: March 30, 2026
We believe you have the right to know how your data is protected. This page details the specific security measures, encryption standards, and architectural decisions we use to safeguard your account, personal information, and purchased content.
| Layer | Standard | Details |
|---|---|---|
| Data in Transit | TLS 1.3 / AES-256-GCM | All traffic between your browser and our servers is encrypted using TLS 1.3, the latest Transport Layer Security protocol. The cipher suite uses AES-256-GCM for symmetric encryption, providing 256-bit encryption strength. Enforced at the edge by Cloudflare with HSTS (HTTP Strict Transport Security) headers to prevent protocol downgrade attacks. |
| Password Storage | bcrypt / 12 rounds | Passwords are hashed using the bcrypt adaptive hashing algorithm with a cost factor of 12 (4,096 iterations). bcrypt is a one-way function — passwords cannot be reversed or decrypted, even by us. Each password is salted with a unique, cryptographically random salt to prevent rainbow table attacks. |
| Session Tokens | HMAC-SHA256 | Authentication tokens (JWT) are signed using HMAC-SHA256 with a 512-bit secret key. Tokens are valid for 7 days and cannot be forged without the signing key. The signing key is stored server-side only and is never transmitted. |
| Payment Data | PCI DSS Level 1 | Payment card data is handled exclusively by Stripe, a PCI DSS Level 1 certified payment processor. Card numbers, CVVs, and bank details never touch our servers. We receive only transaction confirmations and metadata. |
| Measure | Implementation |
|---|---|
| Brute Force Protection | Accounts are locked for 15 minutes after 5 consecutive failed login attempts. Additionally, authentication endpoints are rate-limited to 10 requests per 15-minute window per IP address. |
| Global Rate Limiting | All API endpoints are subject to a global rate limit of 100 requests per 15-minute window per IP address to prevent abuse and denial-of-service attacks. |
| Password Requirements | Minimum 8 characters. Email format validation. Display names capped at 100 characters to prevent overflow attacks. |
| Token Expiration | JWT tokens expire after 7 days, requiring re-authentication. Tokens are stored in browser local storage and cleared on logout. |
| Asset | Protection Method |
|---|---|
| Video Content | Videos are never served via direct URLs. All video content is streamed through an authenticated API proxy that verifies the user's identity and purchase record on every request. Cache-Control headers prevent browser caching of video data. |
| Downloadable Files | Files (datasets, PDFs, guides) are stored in a server-side directory that is not publicly accessible. Downloads are served through an authenticated endpoint that verifies purchase ownership. All downloads are logged with user ID, product, IP address, and timestamp. |
| Course Content | Lesson content (text, HTML) is only returned by the API for users who have purchased the course or for lessons explicitly marked as preview content. Locked lessons return null content. |
| Path Traversal | All file paths are resolved and validated to ensure they remain within the designated uploads directory. Requests attempting to access files outside the uploads boundary are blocked and logged. |
| Threat | Mitigation |
|---|---|
| SQL Injection | All database queries use parameterized statements (prepared statements) through the pg library. User input is never concatenated into SQL strings. |
| Cross-Site Scripting (XSS) | All data from API responses is sanitized using an HTML escape function before DOM insertion. Content Security Policy (CSP) headers restrict script execution sources. |
| Cross-Site Request Forgery (CSRF) | Authentication uses Bearer tokens in the Authorization header, which are not automatically sent by the browser like cookies, providing inherent CSRF protection. |
| Security Headers | The application uses Helmet.js to set comprehensive HTTP security headers including: Content-Security-Policy, X-Content-Type-Options (nosniff), X-Frame-Options (deny), Strict-Transport-Security (HSTS), X-DNS-Prefetch-Control, and X-XSS-Protection. |
| Input Validation | All user inputs are validated server-side: email format, password length, UUID format for identifiers, comment body length (5,000 character cap), display name length (100 character cap), and video position bounds (0-86,400 seconds). |
In the event of a security incident that results in unauthorized access to personal data, we will:
If you discover a security vulnerability in the Service, we genuinely want to hear about it. This is a one-person operation and I take security seriously — if something is broken, I want to know so I can fix it.
Report vulnerabilities to:
We ask that you:
We publish a transparent record of every security audit performed against this platform. If a finding is discovered, we document it, fix it, and list it here.
| Date | Type | Findings | Status |
|---|---|---|---|
| 2026-04-12 | Internal audit (against external pentest pattern) | 1 — hardcoded database credential found in helper scripts and documentation. The credential controlled a database bound only to localhost on the application server (not externally reachable), but was rotated regardless under our "leak = rotate" policy. | Fixed + rotated same day |
The audit checked for: insecure direct object reference (IDOR) on user endpoints, password hash exposure, IP address leaks, file upload path traversal, source code exposure via misconfigured web roots, version control directory exposure, hardcoded API keys in the frontend, and real credentials in environment template files. All checks passed except the one finding above, which has been remediated.
Let's be real — there is no bug bounty program. I'm too broke to pay you. But if you find something and report it responsibly, you will get:
If you're a researcher looking for paid bounties, I totally understand if you move on. No hard feelings. But if you're the type who reports things because it's the right thing to do — I see you, and I appreciate you.