"I've been staring at your code for a long time."
AI-powered bug hunter that uses your existing LLM subscription. No API keys needed. No extra costs.
βββ ββββββ ββββββββββββββββββββββββββββββ βββββββ ββββββββββββββββ
βββ ββββββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββ ββ ββββββββββββββ βββ ββββββ βββββββββββ βββββββββββββββββ
βββββββββββββββββββββ βββ ββββββ βββββββββββ βββββββββββββββββ
βββββββββββββ ββββββ βββ βββββββββββ ββββββββββββββββββββββββββββ
ββββββββ βββ ββββββ βββ βββββββββββ βββ βββββββ ββββββββββββββββ
- Why whiterose?
- Installation
- Quick Start
- Commands
- Architecture
- Configuration
- Bug Categories
- Output Formats
- Contributing
- Show Your Support
- License
You're already paying for Claude Code Max, Cursor, Codex, or similar AI coding tools. Why pay again for bug detection APIs?
whiterose piggybacks on your existing subscription to find bugs in your code. Zero additional cost.
| Feature | whiterose | Traditional SAST |
|---|---|---|
| Cost | $0 (uses existing subscription) | $100-500/mo |
| Setup | npm install -g |
Complex integrations |
| False positives | Low (LLM understands context) | High (pattern matching) |
| Fix generation | Yes (agentic) | No |
| Provider lock-in | None (works with any LLM CLI) | Vendor-specific |
npm install -g @shakecodeslikecray/whiteroseYou need at least one LLM CLI tool installed:
| Provider | Installation | Status |
|---|---|---|
| Claude Code | npm install -g @anthropic-ai/claude-code |
β Ready |
| Codex | npm install -g @openai/codex |
β Ready |
| Gemini | npm install -g @google/gemini-cli |
β Ready |
| Aider | pip install aider-chat |
β Ready |
| OpenCode | curl -fsSL https://opencode.ai/install | bash |
β Ready |
# Interactive menu (recommended)
whiterose
# Or use commands directly:
whiterose init # Initialize (explores codebase, generates understanding)
whiterose scan # Scan for bugs (19-pass pipeline)
whiterose scan --quick # Quick scan (single pass, for pre-commit)
whiterose fix # Fix bugs interactivelyExample output:
β whiterose - thorough scan
β
β Found 64 files to scan
β Static analysis: 37 signals found
ββββ CORE SCANNER (PIPELINE MODE) ββββ
Provider: claude-code
Passes: 19 (9 unit β 5 integration β 5 E2E)
Findings flow: Unit β Integration β E2E
ββββ PHASE 1: UNIT ANALYSIS ββββ
Looking for: injection, null refs, auth bypass, etc.
[Batch 1/2] injection, auth-bypass, null-safety, type-safety, resource-leaks
β injection: 2 bugs
β auth-bypass: 0 bugs
β null-safety: 1 bugs
...
ββββ PHASE 2: INTEGRATION ANALYSIS ββββ
Building on 5 unit findings
Looking for: auth flows, data flows, trust boundaries
β auth-flow-trace: 1 bugs
...
ββββ PHASE 3: E2E ANALYSIS ββββ
Building on 5 unit + 2 integration findings
Looking for: attack chains, privilege escalation
β attack-chain-analysis: 1 bugs
...
ββββ SCAN COMPLETE ββββ
Duration: 4m 32s
Unit: 5 β Integration: 2 β E2E: 1
Final bugs: 7
First-time setup. Explores your codebase and generates understanding.
whiterose initCreates .whiterose/ directory with:
config.yml- Configurationintent.md- Behavioral contracts (editable)cache/understanding.json- AI-generated codebase understanding
Find bugs using the 19-pass pipeline.
whiterose scan # Incremental scan (changed files only)
whiterose scan --full # Full scan (all files)
whiterose scan --quick # Quick scan (single pass, fast)
whiterose scan --provider codex # Use specific provider
whiterose scan --json # JSON output
whiterose scan --ci # CI mode (exit 1 if bugs found)
whiterose scan src/api/ # Scan specific pathInteractive TUI for reviewing and fixing bugs.
whiterose fix # Interactive dashboard
whiterose fix WR-001 # Fix specific bug by ID
whiterose fix --dry-run # Preview without applying
whiterose fix --provider claude-code # Use specific provider
# External bug sources:
whiterose fix --sarif ./semgrep.sarif # Import from SARIF
whiterose fix --github https://github.com/owner/repo/issues/123
whiterose fix --describe # Manually describe a bugAgentic Fix: whiterose uses an agentic approach - the LLM reads the code, explores context, and applies fixes directly. It can also detect false positives during fix and notify you.
Rebuild codebase understanding from scratch.
Show current status (provider, cache, last scan).
This section explains how whiterose works internally. Critical reading for contributors.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LAYER 0: UNDERSTANDING β
β (whiterose init) β
β β
β Input: Output: β
β - README.md, package.json - .whiterose/intent.md β
β - CONTRIBUTING.md - .whiterose/cache/understanding β
β - Existing documentation - Project type, framework, etc. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LAYER 1: BUG FINDING β
β (whiterose scan) β
β β
β 1. Load understanding from Layer 0 β
β 2. Run static analysis (tsc, eslint) β
β 3. Run 19-pass LLM pipeline (Unit β Integration β E2E) β
β 4. Deduplicate and merge findings β
β 5. Output reports (SARIF, Markdown, JSON) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LAYER 2: BUG FIXING β
β (whiterose fix) β
β β
β 1. Load bugs from scan results (or external sources) β
β 2. Interactive TUI for review β
β 3. Agentic fix (LLM explores and fixes) β
β 4. False positive detection during fix β
β 5. Commit changes β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
whiterose runs 19 specialized passes organized into 3 phases, with findings flowing through:
Static Analysis (tsc/eslint)
β
βΌ
staticResults ββββββββββββββββββββββββββββββββββββββ
β β
βΌ β
ββββ PHASE 1: UNIT ANALYSIS (9 passes) ββββ β
β β
β Each pass focuses on ONE bug category: β
β 1. injection - SQL, XSS, command injection β
β 2. auth-bypass - Missing/broken auth checks β
β 3. null-safety - Null/undefined dereference β
β 4. type-safety - Type coercion bugs β
β 5. resource-leaks - Unclosed handles, listeners β
β 6. async-issues - Missing await, race conditions β
β 7. data-validation - Input validation gaps β
β 8. secrets-exposure - Hardcoded secrets, leaks β
β 9. logic-errors - Off-by-one, wrong operators β
β β
β Runs in batches of 5 (parallel within batch) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
unitFindings ββββββββββββββββββββββββββββββ
β β
βΌ βΌ
ββββ PHASE 2: INTEGRATION ANALYSIS (5 passes) ββββ
β Input: staticResults + unitFindings β
β β
β Prompt includes previous findings: β
β "## PREVIOUS FINDINGS TO BUILD ON β
β - [high] SQL injection at api.ts:42 β
β - [medium] Missing auth at routes.ts:15" β
β β
β Passes: β
β 1. auth-flow-trace - Auth across files β
β 2. data-flow-trace - Data propagation β
β 3. validation-boundary - Trust boundaries β
β 4. error-propagation - Error handling β
β 5. trust-boundary-trace - Security bounds β
ββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
integrationFindings ββββββββββββββββββ
β β
βΌ βΌ
ββββ PHASE 3: E2E ANALYSIS (5 passes) ββββ
β Input: staticResults + unitFindings β
β + integrationFindings β
β β
β Builds attack chains from ALL β
β previous findings. β
β β
β Passes: β
β 1. attack-chain-analysis β
β 2. privilege-escalation-trace β
β 3. session-lifecycle-trace β
β 4. user-journey-simulation β
β 5. api-contract-verification β
ββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββ POST-PROCESSING ββββ
β 1. Combine all findings β
β 2. Deduplicate (file:line:category) β
β 3. Merge similar (within 5 lines) β
ββββββββββββββββββββββββββββββββββββββββ
β
βΌ
Final Bugs
whiterose follows the Liskov Substitution Principle - all providers are interchangeable and get the same 19-pass scanning.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CoreScanner β
β src/core/scanner.ts β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β’ 19-pass pipeline logic β
β β’ Batching (5 parallel, 2s delay) β
β β’ Phase dependencies (Unit β Integration β E2E) β
β β’ Deduplication & merging β
β β’ Progress callbacks β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β executor.runPrompt(prompt)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PromptExecutor (interface) β
β src/core/scanner.ts β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β interface PromptExecutor { β
β name: string; β
β isAvailable(): Promise<boolean>; β
β runPrompt(prompt: string, options: PromptOptions): β
β Promise<PromptResult>; β
β } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β β β
βΌ βΌ βΌ βΌ βΌ
ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ
β claude β β codex β β gemini β β aider β β opencode β
β -code β β β β β β β β β
ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ
executors/ executors/ executors/ executors/ executors/
Adding a new provider is trivial - just implement the PromptExecutor interface (~30 lines).
Static analysis runs first, deterministically, before any LLM passes:
// In scan.ts
staticResults = await runStaticAnalysis(cwd, filesToScan, config);
// Passed to CoreScanner
const bugs = await scanner.scan({
files: filesToScan,
understanding,
staticResults, // β Every pass sees this
});Each LLM pass receives static analysis signals in its prompt:
## STATIC ANALYSIS SIGNALS (from tsc/eslint)
- typescript: src/api.ts:42 - TS2532: Object is possibly 'undefined'
- eslint: src/db.ts:15 - @typescript-eslint/no-explicit-any
NOTE: Static tools already verified control flow. Don't report issues they would catch.
This reduces false positives - the LLM knows what tsc/eslint already flagged.
.whiterose/config.yml:
version: "1"
provider: claude-code # or codex, gemini, aider
include:
- "**/*.ts"
- "**/*.tsx"
- "**/*.js"
- "**/*.jsx"
exclude:
- node_modules
- dist
- "**/*.test.*"
- "**/*.spec.*"
priorities:
src/api/checkout.ts: critical
src/auth/: high
categories:
- injection
- auth-bypass
- null-reference
- logic-error
- async-issue
- resource-leak
- data-validation
- secrets-exposure
minConfidence: low # low, medium, high
staticAnalysis:
typescript: true
eslint: true
output:
sarif: true
markdown: true
sarifPath: .whiterose/reports
markdownPath: BUGS.mdwhiterose looks for bugs in these categories:
| Category | Description | Example |
|---|---|---|
injection |
SQL, XSS, command injection | db.query("SELECT * FROM users WHERE id=" + userId) |
auth-bypass |
Missing/broken authentication | Route handler without auth middleware |
null-reference |
Null/undefined dereference | user.profile.name when profile might be null |
logic-error |
Off-by-one, wrong operators | i <= arr.length instead of i < arr.length |
async-issue |
Missing await, race conditions | const data = fetchData(); use(data); |
resource-leak |
Unclosed handles, listeners | db.connect() without db.close() |
data-validation |
Input validation gaps | Missing sanitization on user input |
secrets-exposure |
Hardcoded secrets | const API_KEY = "sk-..." |
type-coercion |
Loose equality bugs | if (value == null) when 0 is valid |
boundary-error |
Edge case handling | Empty array, zero values |
concurrency |
Thread safety issues | Shared state without locks |
intent-violation |
Violates documented behavior | Code contradicts README/docs |
Standard format for static analysis tools. Works with:
- VS Code (SARIF Viewer extension)
- GitHub Code Scanning
- Azure DevOps
Two formats:
bugs.md- Technical (for developers)bugs-human.md- Tester-friendly (for QA)
Full bug data with code paths, evidence, and confidence scores.
whiterose/
βββ src/
β βββ cli/
β β βββ index.ts # CLI entry point
β β βββ commands/
β β βββ init.ts # whiterose init
β β βββ scan.ts # whiterose scan
β β βββ fix.ts # whiterose fix
β β
β βββ core/
β β βββ scanner.ts # CoreScanner + PromptExecutor interface
β β βββ multipass-scanner.ts # Pass configurations (SCAN_PASSES)
β β βββ flow-analyzer.ts # Flow pass configurations (FLOW_PASSES)
β β βββ fixer.ts # Agentic fix logic
β β βββ config.ts # Config loading
β β βββ utils.ts # Utilities
β β
β βββ providers/
β β βββ executors/ # LSP-compliant provider implementations
β β β βββ index.ts # getExecutor(), getAvailableExecutors()
β β β βββ claude-code.ts # ClaudeCodeExecutor
β β β βββ codex.ts # CodexExecutor
β β β βββ gemini.ts # GeminiExecutor
β β β βββ aider.ts # AiderExecutor
β β β βββ opencode.ts # OpenCodeExecutor
β β β
β β βββ prompts/
β β β βββ multipass-prompts.ts # Unit pass prompts
β β β βββ flow-analysis-prompts.ts # Integration/E2E prompts
β β β βββ adversarial.ts # Validation prompts
β β β
β β βββ detect.ts # Provider detection
β β
β βββ analysis/
β β βββ static.ts # tsc/eslint integration
β β
β βββ tui/
β β βββ App.tsx # Main TUI app
β β βββ screens/ # TUI screens
β β
β βββ output/
β β βββ sarif.ts # SARIF output
β β βββ markdown.ts # Technical markdown
β β βββ human-readable.ts # Tester-friendly markdown
β β
β βββ types.ts # TypeScript types (Zod schemas)
β
βββ tsup.config.ts # Build config
βββ package.json
| File | Purpose |
|---|---|
src/core/scanner.ts |
Start here. CoreScanner orchestrates everything. |
src/core/multipass-scanner.ts |
Pass configurations for unit analysis |
src/core/flow-analyzer.ts |
Pass configurations for integration/E2E |
src/providers/executors/*.ts |
Provider implementations (simple!) |
src/providers/prompts/*.ts |
Prompt templates |
- Create
src/providers/executors/your-provider.ts:
import { PromptExecutor, PromptOptions, PromptResult } from '../../core/scanner.js';
export class YourProviderExecutor implements PromptExecutor {
name = 'your-provider';
async isAvailable(): Promise<boolean> {
// Check if CLI tool is installed
}
async runPrompt(prompt: string, options: PromptOptions): Promise<PromptResult> {
// Run: your-cli -p "prompt"
// Return: { output: stdout, error: stderr }
}
}- Register in
src/providers/executors/index.ts - Add to
ProviderTypeinsrc/types.ts - Add detection in
src/providers/detect.ts
-
Add pass config to
SCAN_PASSESinsrc/core/multipass-scanner.ts(for unit passes) orFLOW_PASSESinsrc/core/flow-analyzer.ts(for integration/E2E) -
Add to pipeline in
src/providers/prompts/flow-analysis-prompts.ts:
export function getFullAnalysisPipeline() {
return [
{ phase: 'Unit Analysis', passes: [..., 'your-new-pass'] },
// ...
];
}npm run build # Build
npm run dev # Watch mode
npm test # Run tests- SRP: whiterose finds bugs. It doesn't write tests, lint code, or format files.
- Leverage, Don't Reinvent: Uses existing AI agents (Claude Code, Codex) rather than building a custom agent loop.
- LSP-Compliant: All providers are interchangeable. Scanning logic lives in ONE place.
- Transparency: Shows exactly what's happening in real-time.
- Grounded: Every bug must have evidence and a code path trace.
- Zero Cost: Uses your existing LLM subscription.
If you're using whiterose, we'd love to know!
- Star this repo - helps others discover the project
- Add the
whiterosetopic to your repo - browse repos using whiterose - Share your experience - open a discussion
PolyForm Noncommercial 1.0.0
This software is free for non-commercial use. See LICENSE for details.
Named after the Mr. Robot character who sees everything and orchestrates from the shadows.
Copyright (c) 2024-2025 shakecodeslikecray (https://github.com/shakecodeslikecray)