|
| 1 | +# Security Checklist |
| 2 | + |
| 3 | +Quick reference for security in flow-code. CLI tool handling local state, no web server. |
| 4 | + |
| 5 | +## Pre-Commit Secret Scan |
| 6 | + |
| 7 | +```bash |
| 8 | +# Check staged files for secrets before committing |
| 9 | +git diff --cached | grep -iE \ |
| 10 | + "password\s*=|secret\s*=|api_key\s*=|token\s*=|private_key|BEGIN RSA|BEGIN EC" |
| 11 | + |
| 12 | +# Patterns to catch |
| 13 | +grep -rn "AKIA[0-9A-Z]{16}" # AWS access keys |
| 14 | +grep -rn "sk-[a-zA-Z0-9]{48}" # OpenAI API keys |
| 15 | +grep -rn "ghp_[a-zA-Z0-9]{36}" # GitHub personal tokens |
| 16 | +grep -rn "xoxb-[0-9]{10,}" # Slack bot tokens |
| 17 | +``` |
| 18 | + |
| 19 | +## Files to Never Commit |
| 20 | + |
| 21 | +| File/Pattern | Reason | Mitigation | |
| 22 | +|---|---|---| |
| 23 | +| `.env` | Contains secrets | Add to `.gitignore` | |
| 24 | +| `*.pem`, `*.key` | Private keys | Add to `.gitignore` | |
| 25 | +| `.flow/` | Runtime state (may contain tokens) | Add to `.gitignore` | |
| 26 | +| `credentials.json` | Service account keys | Add to `.gitignore` | |
| 27 | +| `*.upstream` | Backup files with potential secrets | Add to `.gitignore` | |
| 28 | + |
| 29 | +Commit `.env.example` with placeholder values instead of `.env`. |
| 30 | + |
| 31 | +## Secrets Management |
| 32 | + |
| 33 | +| Do | Don't | |
| 34 | +|---|---| |
| 35 | +| Use environment variables for secrets | Hardcode secrets in source | |
| 36 | +| Commit `.env.example` with placeholders | Commit `.env` with real values | |
| 37 | +| Use `--json` flag for machine parsing | Parse human-readable output with secrets | |
| 38 | +| Rotate secrets after exposure | Ignore leaked credentials | |
| 39 | +| Scope API keys to minimum permissions | Use admin keys for all operations | |
| 40 | + |
| 41 | +## OWASP Top 10 Quick Reference |
| 42 | + |
| 43 | +| # | Vulnerability | Prevention | |
| 44 | +|---|---|---| |
| 45 | +| 1 | Broken Access Control | Auth checks on every endpoint, ownership verification | |
| 46 | +| 2 | Cryptographic Failures | HTTPS, strong hashing, no secrets in code | |
| 47 | +| 3 | Injection | Parameterized queries, input validation | |
| 48 | +| 4 | Insecure Design | Threat modeling, spec-driven development | |
| 49 | +| 5 | Security Misconfiguration | Minimal permissions, audit deps, secure defaults | |
| 50 | +| 6 | Vulnerable Components | `cargo audit`, `cargo deny`, minimal deps | |
| 51 | +| 7 | Auth Failures | Strong passwords, rate limiting, session management | |
| 52 | +| 8 | Data Integrity Failures | Verify updates/dependencies, signed artifacts | |
| 53 | +| 9 | Logging Failures | Log security events, don't log secrets | |
| 54 | +| 10 | SSRF | Validate/allowlist URLs, restrict outbound requests | |
| 55 | + |
| 56 | +## Dependency Audit (Rust) |
| 57 | + |
| 58 | +```bash |
| 59 | +# Audit for known vulnerabilities |
| 60 | +cargo audit |
| 61 | + |
| 62 | +# Deny specific licenses or advisories |
| 63 | +cargo deny check |
| 64 | + |
| 65 | +# Check for outdated dependencies |
| 66 | +cargo outdated |
| 67 | + |
| 68 | +# Minimal dependency tree (fewer deps = smaller attack surface) |
| 69 | +cargo tree | wc -l |
| 70 | +``` |
| 71 | + |
| 72 | +| Tool | Purpose | When to Run | |
| 73 | +|---|---|---| |
| 74 | +| `cargo audit` | CVE database check | Pre-commit, CI | |
| 75 | +| `cargo deny` | License + advisory policy | CI pipeline | |
| 76 | +| `cargo outdated` | Stale dependency check | Weekly/monthly | |
| 77 | +| `cargo tree` | Dependency graph audit | When adding deps | |
| 78 | + |
| 79 | +## Input Validation |
| 80 | + |
| 81 | +| Rule | Example | |
| 82 | +|---|---| |
| 83 | +| Validate at boundaries only | CLI args, JSON input, file reads | |
| 84 | +| Use allowlists, not denylists | Accept known-good, reject everything else | |
| 85 | +| Constrain string lengths | Task titles: 1-500 chars | |
| 86 | +| Validate file paths | No `..` traversal, stay within `.flow/` | |
| 87 | +| Sanitize output for shells | Escape special chars in generated commands | |
| 88 | +| Parse, don't validate | Deserialize into typed structs, not raw strings | |
| 89 | + |
| 90 | +```rust |
| 91 | +// Good: parse into typed struct at boundary |
| 92 | +let task: TaskInput = serde_json::from_str(&input)?; |
| 93 | + |
| 94 | +// Bad: pass raw string around and validate later |
| 95 | +fn process(raw: &str) { /* who validates this? */ } |
| 96 | +``` |
| 97 | + |
| 98 | +## Error Handling |
| 99 | + |
| 100 | +| Context | Approach | |
| 101 | +|---|---| |
| 102 | +| CLI output (user-facing) | Clear error message, no stack traces | |
| 103 | +| JSON output (`--json`) | Structured error: `{"error": "message"}` | |
| 104 | +| Internal logging | Full context, file/line, but no secrets | |
| 105 | +| Panics | Catch at boundaries with `catch_unwind` or `?` | |
| 106 | + |
| 107 | +```rust |
| 108 | +// Good: generic error to user, detail in logs |
| 109 | +eprintln!("Error: failed to open database"); |
| 110 | +tracing::error!("DB open failed: {:?} at {:?}", err, path); |
| 111 | + |
| 112 | +// Bad: expose internals |
| 113 | +eprintln!("Error: {}", err); // May leak path, SQL, etc. |
| 114 | +``` |
| 115 | + |
| 116 | +## SQL Safety (libSQL) |
| 117 | + |
| 118 | +| Do | Don't | |
| 119 | +|---|---| |
| 120 | +| Use parameterized queries | Concatenate user input into SQL | |
| 121 | +| Use `?` placeholders | Use `format!()` for query building | |
| 122 | +| Validate types before query | Trust raw input as safe | |
| 123 | +| Use transactions for multi-step ops | Execute multiple queries without atomicity | |
| 124 | + |
| 125 | +```rust |
| 126 | +// Good: parameterized |
| 127 | +conn.execute("INSERT INTO tasks (title) VALUES (?1)", [&title]).await?; |
| 128 | + |
| 129 | +// Bad: string concatenation |
| 130 | +conn.execute(&format!("INSERT INTO tasks (title) VALUES ('{}')", title), ()).await?; |
| 131 | +``` |
| 132 | + |
| 133 | +## File System Security |
| 134 | + |
| 135 | +| Rule | Rationale | |
| 136 | +|---|---| |
| 137 | +| Validate paths stay within `.flow/` | Prevent directory traversal | |
| 138 | +| Use temp dirs for scratch work | Don't pollute user directories | |
| 139 | +| Set restrictive permissions on state files | Protect `.flow/` data | |
| 140 | +| Clean up temp files on exit | No stale sensitive data | |
| 141 | +| Don't follow symlinks blindly | Potential symlink attacks | |
0 commit comments