Docs • Installation • Quickstart • GitHub Action • Rules • Contributing • Changelog
flaw reads your Crystal source and holds it up to the light. Each rule looks for a specific security flaw — hardcoded secrets, command injection sinks, SQL built from interpolation, weak randomness used for tokens, untrusted YAML loads. Findings print with file and line, and can be emitted as JSON or SARIF for CI and GitHub Code Scanning.
Features
- 83 built-in rules across security, AI-slop hygiene, design tokens, and accessibility — see
rules/ - Per-rule severity override, path ignore, and tag include/exclude via
.flaw.ymlor CLI flags - Incremental scans with
--since <ref>(only report on files/lines changed since a git ref) - Baselines (
flaw baseline+--baseline .flaw-baseline.json) to gate only on new findings --fixfor safe autofixes (e.g. weak-hash upgrades)--verify-secretsto probe provider APIs (AWS, GitHub) on FLAW002 matches- Recurses any directory of
.crfiles, skipslib/andspec/by default
scan— analyze code and emit findingsbrowse— interactive TUI triage (fzf + bat + optional tmux popup)baseline— snapshot current findings so future scans ignore themaudit— scanshard.lockfor shards with known CVEsrules/lint-rules— list rules, or validate therules/contract in CIinit config/init rule— scaffold a.flaw.ymlor a new rule folderregex/doctor— author rule regexes, diagnose the environment
- Pretty (colored, grouped by file, with snippet)
- JSON for pipelines and agents
- SARIF 2.1.0 for GitHub Code Scanning upload
- Single static binary, zero runtime dependencies
- Reusable GitHub Action (
uses: kdairatchi/flaw@v0.1.0) - Non-zero exit on finding-at-threshold
git clone https://github.com/kdairatchi/flaw.git
cd flaw
shards build --release --no-debug --production
./bin/flaw versionbrew install kdairatchi/tap/flawDownload from the Releases page — linux-amd64, linux-arm64, macos-arm64.
flaw scan . # scan current directory, pretty output
flaw scan src/ --format json # JSON for agents / pipelines
flaw scan . --format sarif > flaw.sarif
flaw scan . --fail-on high # CI: exit 1 if any high+ finding
flaw scan . --since HEAD~1 --since-lines # only findings on lines changed since HEAD~1
flaw scan . --include-tag security # only run rules tagged 'security'
flaw scan . --fix # apply safe autofixes in place
flaw scan . --verify-secrets # live-probe AWS/GitHub keys from FLAW002
flaw browse src/ # interactive TUI triage (fzf + bat)
flaw browse --tmux popup src/ # open picker in a tmux popup
flaw baseline # snapshot current findings to .flaw-baseline.json
flaw scan --baseline .flaw-baseline.json # suppress baselined findings
flaw audit # scan shard.lock for known CVEs
flaw doctor # diagnose Crystal version, AST backend, config
flaw regex test '(?i)secret' input.cr # interactively tune rule regexes
flaw rules # list built-in rules, grouped by tag
flaw rules FLAW001 # show rule detail
flaw lint-rules # validate rules/ directory contract
flaw init config # drop a .flaw.yml config stub
flaw init rule FLAW200 my-new-rule # scaffold a new rule folder + detector# .github/workflows/flaw.yml
name: flaw
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: kdairatchi/flaw@v0.1.0
with:
args: scan . --fail-on high --format sarif > flaw.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: flaw.sarifflaw ships 83 rules split into two ID ranges. Full catalog, severity, tags, CWE, and OWASP mapping live in rules/README.md.
Real vulnerabilities. Default severity is medium+; designed for --fail-on high in CI.
| ID | Severity | Flaw |
|---|---|---|
FLAW001 |
critical | Command built from string interpolation |
FLAW002 |
high | Hardcoded secret literal |
FLAW003 |
high | SQL built via interpolation or concatenation |
FLAW009 |
high | Weak hash (MD5/SHA1) for password or integrity |
FLAW011 |
high | Outbound HTTP to user-controlled URL (SSRF) |
FLAW014 |
high | XML parsed without disabling external entities (XXE) |
FLAW022 |
high | Archive entry extracted without normalization (zip-slip) |
FLAW023 |
critical | JWT with alg:none or verification disabled |
FLAW024 |
high | CORS wildcard / echoed origin with credentials |
| …and 15 more | see rules/README.md |
Novel territory: catches vibe-coded AI paste-through, LLM-app footguns (prompt-role injection, unfenced tool results, user-controlled max_tokens), MCP/agent supply-chain hazards, and design/a11y token drift. Groups include:
| Group | Range | Examples |
|---|---|---|
| AI-slop hygiene | FLAW100–FLAW108 |
narration comments, assistant boilerplate, placeholders, unfinished stubs, silenced rescues, commented-out auth |
| Design / a11y | FLAW106, FLAW109, FLAW111, FLAW118–FLAW121, FLAW127–FLAW131 |
raw color literals, contrast fail, mixed CSS units, missing alt/lang, Tailwind conflicts |
| Security sinks | FLAW112–FLAW117, FLAW122–FLAW126, FLAW132–FLAW148 |
dynamic eval, DOM XSS, SSTI, prototype pollution, Log4Shell, NoSQL injection, PII in logs, debug-in-prod, cloud-metadata, LOLBIN, insecure GitHub Actions, open security groups, source maps shipped |
| LLM / MCP | FLAW149–FLAW157 |
unpinned MCP source, project-local config grants exec, role injection, tool result unfenced, user-controlled max_tokens, non-literal tool-handler URLs, AI-tool config committed |
Every rule lives in its own folder under rules/ with the detector, a vulnerable fixture (bad.cr), a fixed version (good.cr), metadata (rule.yml), and docs. Add one with flaw init rule FLAW200 my-rule.
flaw lint-rules enforces the rule contract — every folder matches FLAWNNN, has all four required files, the rule.yml parses and has the required keys, the detector file exists, and each bad.cr + good.cr behaves as claimed. Run it in CI as the gatekeeper for rule contributions.
.flaw.yml in your repo root:
version: 1
exclude:
- spec/
- lib/
- vendor/
rules:
FLAW002:
ignore:
- "examples/fake-keys.cr"
FLAW004:
severity: critical
FLAW005:
disabled: true- v0.2 — 10 more rules,
--fixautofix for trivial cases, better SARIF provenance - v0.3 — LSP server (real-time flaws in your editor)
- v0.4 — Baseline file (gate only on new findings)
- v0.5 — Custom rule DSL (community rules in YAML)
- v0.6 — Cross-file taint tracking (sources → sinks)
- v1.0 — Plugin system, hosted rule docs at
flaw.prowlrbot.com(landing page lives underdocs/— enable GitHub Pages withmain//docs), Caido integration
flaw is an open-source project built by one person and improved by many. See CONTRIBUTING.md for how to add a rule, report a false positive, or suggest a roadmap item.
In gemology, a flaw is a fracture, inclusion, or imperfection inside a crystal — the thing a trained eye spots by catching the light right. flaw does the same for Crystal code: it holds your program up to the light and shows you the fractures before someone else does.
Report suspected vulnerabilities privately — see SECURITY.md.
MIT © kdairatchi
