name: astro-security description: Security patterns for Astro lead generation websites on Cloudflare. Forms, headers, bot protection, GDPR. Use for any production lead gen site.
Astro Security Skill
Security patterns for lead generation sites.
Core Rules (Non-Negotiable)
| Violation | Result |
|---|---|
| Production form without Turnstile + honeypot | FAIL |
| Secret exposed client-side | FAIL |
| User input stored without server validation | FAIL |
| Indexable staging environment | FAIL |
| Missing security headers | FAIL |
| Cookie banner missing before analytics | FAIL |
Form Security (Required)
Every form must have:
| Protection | Implementation |
|---|---|
| Turnstile | Cloudflare captcha (invisible mode) |
| Honeypot | Hidden field, reject if filled |
| Rate limit | Max 5 submissions/IP/hour |
| Validation | Server-side Zod, never trust client |
| Sanitize | Strip HTML, trim whitespace |
See references/forms.md.
Security Headers (Required)
CSP Rules:
- MUST disallow inline scripts unless hashed
- MUST restrict script-src to required domains only
- MUST test in report-only before enforcement
Add to _headers:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: [see references]
Strict-Transport-Security: max-age=31536000; includeSubDomains
Environment Variables
# .env.example (commit this)
TURNSTILE_SITE_KEY=
TURNSTILE_SECRET_KEY=
RESEND_API_KEY=
GOOGLE_SHEETS_ID=
# .env (never commit)
# Add to .gitignore
Rules:
- Never expose secrets client-side
- Use
import.meta.envfor public vars only - Validate all env vars on build
Bot Protection
Cloudflare (free tier):
- Bot Fight Mode: ON
- Security Level: Medium
- Challenge Passage: 30 minutes
Application level:
- Turnstile on all forms
- Honeypot fields
- Rate limiting per IP
- Block empty referrer (optional)
Third-Party Scripts
- Use SRI (integrity hash) for CDN scripts
- Load async/defer
- Minimize scripts
- Review GTM tags regularly
GDPR Compliance
Required:
- Cookie banner (before non-essential cookies)
- Privacy policy page
- Form consent checkbox (if marketing)
- Data retention policy
- Right to deletion process
Cookie categories:
| Type | Consent | Examples |
|---|---|---|
| Necessary | No | Session, CSRF |
| Analytics | Yes | GA4, Hotjar |
| Marketing | Yes | Meta Pixel, Google Ads |
See references/gdpr.md.
Input Validation
Never: Trust client-side alone, store raw input, render unsanitized HTML.
See forms.md for Zod schemas.
File Uploads
If needed: Max 5MB, whitelist types, rename files, store outside webroot.
Staging Protection
Password protect OR Cloudflare Access. Add noindex, block in robots.txt.
Error Handling
- Error messages MUST NOT reveal stack traces or internals
- API errors MUST return generic messages (
Something went wrong) - Detailed errors allowed ONLY in development
- 404/500 pages must not leak tech stack info
Dependencies
- Minimize third-party scripts
- Remove unused dependencies before launch
- Review third-party access quarterly
- Prefer self-hosted over CDN when possible
Definition of Done
Security requirements before launch:
- Turnstile on all forms
- Honeypot fields added
- Rate limiting configured
- Security headers set
- HTTPS enforced
- .env in .gitignore
- No secrets in client code
- Cookie banner working
- Privacy policy linked
- Staging protected
- Error pages don't leak info
References
- forms.md — Form security patterns
- headers.md — CSP and headers
- gdpr.md — GDPR compliance