presidentbeef/brakeman
A static analysis security vulnerability scanner for Ruby on Rails applications
Single-maintainer risk — review before adopting
worst of 4 axesnon-standard license (Other)
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 2w ago
- ✓11 active contributors
- ✓Other licensed
Show 4 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Single-maintainer risk — top contributor 88% of recent commits
- ⚠Non-standard license (Other) — review terms
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/presidentbeef/brakeman)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/presidentbeef/brakeman on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: presidentbeef/brakeman
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/presidentbeef/brakeman shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Single-maintainer risk — review before adopting
- Last commit 2w ago
- 11 active contributors
- Other licensed
- CI configured
- Tests present
- ⚠ Single-maintainer risk — top contributor 88% of recent commits
- ⚠ Non-standard license (Other) — review terms
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live presidentbeef/brakeman
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/presidentbeef/brakeman.
What it runs against: a local clone of presidentbeef/brakeman — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in presidentbeef/brakeman | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 45 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of presidentbeef/brakeman. If you don't
# have one yet, run these first:
#
# git clone https://github.com/presidentbeef/brakeman.git
# cd brakeman
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of presidentbeef/brakeman and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "presidentbeef/brakeman(\\.git)?\\b" \\
&& ok "origin remote is presidentbeef/brakeman" \\
|| miss "origin remote is not presidentbeef/brakeman (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "lib/brakeman.rb" \\
&& ok "lib/brakeman.rb" \\
|| miss "missing critical file: lib/brakeman.rb"
test -f "lib/brakeman/checks/base_check.rb" \\
&& ok "lib/brakeman/checks/base_check.rb" \\
|| miss "missing critical file: lib/brakeman/checks/base_check.rb"
test -f "lib/brakeman/app_tree.rb" \\
&& ok "lib/brakeman/app_tree.rb" \\
|| miss "missing critical file: lib/brakeman/app_tree.rb"
test -f "lib/brakeman/call_index.rb" \\
&& ok "lib/brakeman/call_index.rb" \\
|| miss "missing critical file: lib/brakeman/call_index.rb"
test -f "lib/brakeman/checks.rb" \\
&& ok "lib/brakeman/checks.rb" \\
|| miss "missing critical file: lib/brakeman/checks.rb"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 45 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~15d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/presidentbeef/brakeman"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Brakeman is a static analysis security vulnerability scanner that scans Ruby on Rails applications without running code to detect OWASP Top 10 vulnerabilities like SQL injection, XSS, CSRF, mass assignment, and insecure redirects. It parses Rails controller/model/view code as an AST and applies 100+ configurable security checks, outputting results in JSON, HTML, SARIF, or multiple other formats. Monolithic architecture: bin/brakeman and bin/codeclimate-brakeman are CLI entry points; lib/ (inferred, standard Ruby gem structure) contains the core AST-parsing engine and 100+ check classes; docs/warning_types/ contains human-readable threat documentation for each check type; test suites validate both parsing and check accuracy across Rails versions.
👥Who it's for
Rails developers and security engineers who need to automatically audit Rails 2.3–8.x codebases before deployment. Used by teams adopting CI/CD pipelines (CircleCI, GitHub Actions) and container-based scanning (CodeClimate, Docker) to enforce security gates without manual penetration testing.
🌱Maturity & risk
Highly mature and production-ready. The project is actively maintained with a single long-term maintainer (presidentbeef), has comprehensive CI via CircleCI and GitHub Actions, extensive test coverage tracked via Qlty.sh, and spans multiple stable gemspecs (brakeman.gemspec, brakeman-lib.gemspec, brakeman-min.gemspec). Latest changes confirm ongoing development.
Low risk overall but watch for: single primary maintainer (presidentbeef) creates bus-factor risk; requires Ruby 3.2.0+ to run despite analyzing Rails 2.3+, limiting legacy team adoption; dependency management split across multiple gemspecs may complicate version resolution. No obvious security debt visible in structure.
Active areas of work
Active maintenance with recent commits (evidenced by .github/workflows and .circleci/config.yml setup); Docker Hub publication pipeline active (docker-hub-push.yml); issue templates target common user friction (parsing-errors, false-positives, hanging-scans); CHANGES.md should reflect recent version bumps and check additions.
🚀Get running
git clone https://github.com/presidentbeef/brakeman.git
cd brakeman
bundle install
bundle exec brakeman /path/to/rails/app
Or install as a gem: gem install brakeman && brakeman /path/to/rails/app
Daily commands:
bundle exec brakeman # Scan current Rails app
bundle exec brakeman -q -f json -o out.json /path/to/app # Quiet mode, JSON output
bundle exec brakeman --faster # Speed optimization
bundle exec brakeman -x DefaultRoutes # Skip specific check
bundle exec brakeman -d # Debug output
No dev server needed; static analysis only.
🗺️Map of the codebase
lib/brakeman.rb— Main entry point that orchestrates the entire Brakeman security scanner workflow and exposes the public APIlib/brakeman/checks/base_check.rb— Abstract base class for all security checks; understanding this is essential for adding new vulnerability detectorslib/brakeman/app_tree.rb— Core abstraction for parsing and representing the Rails application's file structure and ASTlib/brakeman/call_index.rb— Critical indexing system that tracks method calls and data flow across the application for vulnerability detectionlib/brakeman/checks.rb— Registry and loader for all vulnerability check modules; controls which checks are executed during scanningbin/brakeman— CLI entry point that handles command-line argument parsing and initiates the scanbrakeman.gemspec— Gem specification defining Brakeman's dependencies, versioning, and distribution metadata
🧩Components & responsibilities
- app_tree.rb (Ruby parser gem, File I/O) — Responsible for parsing the entire Rails application directory, building the AST, and organizing code structures (controllers, models, views, routes)
- Failure mode: Parse errors halt the scan; unsupported Rails patterns may be ignored
- call_index.rb (Hash-based indexing, graph traversal) — Maintains an indexed graph of method calls and variable assignments across the application to enable data flow analysis
- Failure mode: Indexing failures may cause missed vulnerabilities or high memory consumption
- Base & Individual Checks (Pattern matching, confidence scoring) — Each check implements specific vulnerability detection logic (XSS, SQL injection, etc.) by analyzing app_tree and call_index
- Failure mode: Check bugs cause false positives or false negatives for specific vulnerability types
- Output Formatter (JSON/XML/HTML generation) — Transforms warnings and scan results into machine-readable or human-readable formats for reporting and CI integration
- Failure mode: Formatting errors prevent results from being consumed by downstream tools
- CLI & Orchestrator (brakeman.rb) (OptionParser, standard library) — Coordinates the entire scan workflow: parses options, instantiates components, runs checks sequentially, and manages output
- Failure mode: Orchestration bugs prevent scans from starting or completing; option parsing errors confuse users
🔀Data flow
File system→app_— undefined
🛠️How to make changes
Add a New Security Check
- Create a new check class in lib/brakeman/checks/ that inherits from BaseCheck (
lib/brakeman/checks/base_check.rb) - Implement the run_check method to analyze the app_tree for vulnerable patterns (
lib/brakeman/checks/check_basic_auth.rb) - Use warn() to report findings with proper warning type and confidence level (
lib/brakeman/checks/check_cross_site_scripting.rb) - Register the check in lib/brakeman/checks.rb using the checks hash (
lib/brakeman/checks.rb) - Add documentation in docs/warning_types/{check_name}/ explaining the vulnerability (
docs/warning_types/cross_site_scripting/index.markdown)
Integrate New Data Flow Analysis
- Extend call tracking logic to recognize new method patterns or data sources (
lib/brakeman/call_index.rb) - Update app_tree.rb to parse additional Rails patterns if needed (
lib/brakeman/app_tree.rb) - Create a check that uses the enhanced call_index to detect vulnerabilities (
lib/brakeman/checks/base_check.rb)
Add a New Output Format
- Create a formatter class in lib/brakeman/ that inherits from a base formatter (
lib/brakeman.rb) - Implement the output method to format warnings and tracker results (
lib/brakeman.rb) - Register the formatter in the Brakeman options/config handler (
lib/brakeman.rb) - Test via bin/brakeman --format custom_format (
bin/brakeman)
🔧Why these technologies
- Ruby AST (Ruby parser gem) — Enables accurate static analysis of Ruby/Rails code without execution, critical for security scanning
- Gem-based plugin architecture — Allows modular check implementation and easy extension for new vulnerability types
- Docker containerization — Provides isolated, reproducible scanning environments and enables CI/CD integration
- Multiple output formats (JSON, HTML, XML) — Integrates with various tools, CI systems (CircleCI, GitHub Actions), and reporting platforms
⚖️Trade-offs already made
-
Static analysis only (no runtime execution)
- Why: Safer and faster than dynamic analysis; avoids side effects
- Consequence: May miss runtime-specific vulnerabilities or have false positives with complex metaprogramming
-
Call graph indexing across entire codebase
- Why: Enables accurate data flow tracking and cross-file vulnerability detection
- Consequence: Higher memory usage and longer initial scan time for large applications
-
Confidence levels rather than binary detection
- Why: Reflects uncertainty in static analysis and reduces alert fatigue
- Consequence: Developers must understand confidence levels to prioritize findings
-
Rails-specific scanner (not general Ruby)
- Why: Allows deep understanding of Rails conventions and common vulnerable patterns
- Consequence: Limited applicability to non-Rails Ruby projects
🚫Non-goals (don't propose these)
- Runtime vulnerability detection or dynamic program analysis
- Fixed false-positive rate (static analysis inherently has limitations)
- Scanning non-Rails Ruby applications
- Replacing SAST tools for non-security code quality checks
- Network-based or remote vulnerability assessment
🪤Traps & gotchas
- Ruby version constraint: Brakeman requires Ruby 3.2.0+ to run but analyzes Rails 2.3+ codebases; teams on Ruby 2.7 must use older Brakeman versions or upgrade runtime.
- AST parsing fragility: If Rails code uses non-standard Ruby syntax or dynamic metaprogramming, Brakeman may fail to parse or miss vulnerabilities; debugging requires
-dflag and understanding of Ruby parser internals. - False positive tuning: Multiple checks (SQL injection, XSS, mass assignment) rely on heuristics and can trigger on safe code; users must configure exclusions in .brakeman config file (not shown in file list but inferred from README).
- Gemspec fragmentation: Three separate gemspecs (brakeman, brakeman-lib, brakeman-min) mean gem resolution can break if installing wrong variant; users should install
brakemangem, not internal variants.
🏗️Architecture
💡Concepts to learn
- Abstract Syntax Tree (AST) Analysis — Brakeman parses Rails source into ASTs without executing code, then walks the tree applying pattern-matching rules; understanding AST node types (MethodCall, Send, Const, etc.) is essential to writing new checks
- Data Flow / Taint Analysis — Brakeman tracks untrusted user input (params, request.env) flowing through assignments and method calls to detect SQL injection and XSS; new checks must implement taint propagation logic
- Rails Convention over Configuration — Brakeman exploits Rails idioms (controllers in app/controllers/, models in app/models/) to locate and analyze security-critical code; understanding Rails file layout and controller/model/view role separation is prerequisite
- OWASP Top 10 Web Vulnerabilities — Each Brakeman check maps to a specific OWASP category (A1:Injection, A7:XSS, A8:CSRF, etc.); understanding threat models (attack vectors, remediation) helps triage results and avoid false positives
- Security Scanner Output Formats (SARIF, CodeClimate) — Brakeman outputs JSON, SARIF (for GitHub Code Scanning), and CodeClimate format for CI/CD integration; each format has distinct schema and tool expectations, important when integrating into CI gates
- Mass Assignment Vulnerability (Rails attr_accessible/permit) — Brakeman flags unguarded mass assignment in Rails models; understanding the difference between attr_accessible (Rails 3) and strong_parameters/permit (Rails 4+) is critical to writing and validating this check
- Static Analysis False Positive Tuning — Brakeman's checks (SQL, XSS, CSRF) use heuristics and may flag safe code; understanding where to add exclusions (config files, skip annotations, confidence levels) reduces alert fatigue in large codebases
🔗Related repos
ruby-parser/ruby_parser— Core dependency for Brakeman's AST parsing; understanding its node types directly informs writing new checkswhitequark/parser— Modern Ruby parser alternative to ruby_parser; Brakeman likely supports both; used for newer syntax (pattern matching, safe navigation)ankane/easily— Companion tool for Rails security; focuses on unsafe Easily queries, complementary to Brakeman's broader checksrubocop/rubocop— Similar static analysis tool for Ruby style/lint; shares similar AST-walking architecture and extensible check pattern; users often combine with Brakemanpresidentbeef/brakeman-ci-action— Official GitHub Action wrapper for Brakeman; simplifies CI integration and PR commenting on vulnerabilities
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for warning_types documentation
The docs/warning_types directory contains 30+ warning type definitions (CVE checks, XSS, CSRF, command injection, etc.) but there's no automated test suite validating that each warning type has proper documentation structure, examples, and remediation guidance. This would prevent documentation drift and ensure consistency across all warning types.
- [ ] Create test/warning_types_test.rb to validate each docs/warning_types/*/index.markdown file
- [ ] Verify required sections exist: description, remediation, false positives explanation
- [ ] Check for code examples in at least 50% of warning type docs
- [ ] Add CI step in .circleci/config.yml to run documentation validation
- [ ] Document the testing approach in CONTRIBUTING.md
Create GitHub Actions workflow for gem release automation
Brakeman publishes to multiple gems (brakeman.gemspec, brakeman-lib.gemspec, brakeman-min.gemspec) and uses code signing (brakeman-public_cert.pem), but there's no automated release workflow in .github/workflows. Currently maintainers must manually build/release, creating friction and potential for human error.
- [ ] Create .github/workflows/gem-release.yml triggered on version tag push
- [ ] Implement steps to build all 3 gemspec variants and validate code signing
- [ ] Push built gems to RubyGems.org using RUBYGEMS_API_KEY secret
- [ ] Generate CHANGES.md release notes automatically from git history
- [ ] Add documentation in CONTRIBUTING.md on release process for maintainers
Add integration test suite for brakeman output formats
Brakeman supports multiple output formats (JSON, CSV, CodeClimate), but there's no dedicated integration test validating that each format produces correctly structured output. The bin/codeclimate-brakeman binary exists but lacks corresponding tests. This ensures output stability across versions.
- [ ] Create test/integration_test.rb with sample Rails app fixtures
- [ ] Add tests validating JSON output schema matches expected structure
- [ ] Add tests validating CSV output columns and escaping
- [ ] Add tests for CodeClimate format output (test/fixtures used by bin/codeclimate-brakeman)
- [ ] Verify output formats match documented OPTIONS.md specifications
🌿Good first issues
- Add missing warning_types documentation: Several checks referenced in lib/ likely lack corresponding docs/warning_types/check_name/ markdown files; audit lib/ against docs/ and create missing ones with OWASP threat descriptions.
- Improve parsing error reporting: The .github/ISSUE_TEMPLATE/parsing-error.md suggests this is a recurring pain point; add a
--debug-astflag that dumps the parsed tree and AST node positions for failed checks, making user bug reports self-service. - Expand Docker documentation: OPTIONS.md is comprehensive but Docker-specific flag mapping (e.g., how to mount config files, pass environment variables for CI systems like GitLab CI) is absent; add docs/DOCKER.md with real examples.
⭐Top contributors
Click to expand
Top contributors
- @presidentbeef — 88 commits
- @viralpraxis — 3 commits
- @FFederi — 1 commits
- @imran-iq — 1 commits
- @chaadow — 1 commits
📝Recent commits
Click to expand
Recent commits
565e7a7— Merge pull request #2010 from viralpraxis/fix-template-alias-processor-template-name-arity (presidentbeef)169a7d4— Do a better job detecting shell escaping (presidentbeef)2e55d45— Bump to 8.0.4 (presidentbeef)d6c6c9a— Merge pull request #2016 from presidentbeef/fix-ensure-latest-date (presidentbeef)56f9324— Load 'date' for --ensure-latest (presidentbeef)d1699da— Always pass an argument to#template_name(viralpraxis)8b644a6— Bump to 8.0.3 (presidentbeef)08e0a18— Update CHANGES (presidentbeef)a29fe44— Merge pull request #2014 from FFederi/fix-polymorphic-name-false-positive (presidentbeef)61150cf— Fix polymorphic_name false positive (FFederi)
🔒Security observations
Brakeman is a mature security scanning tool with reasonable security practices. The codebase structure is well-organized and follows standard Ruby/Rails conventions. Primary concerns are Docker configuration hardening (non-root user, image pinning, frozen dependencies) and security policy documentation completeness. No critical vulnerabilities detected in the provided context. The tool itself is designed to find security issues in other applications, indicating security-conscious development. Recommendations focus on production deployment hardening and process improvements.
- Low · Insecure Docker Base Image —
Dockerfile, line 1. The Dockerfile uses 'ruby:3.3-alpine' without specifying a full digest/tag. Alpine Linux images can receive updates that may include security patches, but using a floating tag means rebuilds will pull newer versions unpredictably. This could lead to inconsistent builds or missed security updates if images are cached. Fix: Use a specific version tag with digest: 'ruby:3.3.0-alpine@sha256:...' or pin to a specific date-based tag to ensure reproducible builds while maintaining control over security updates. - Low · Missing HEALTHCHECK in Docker —
Dockerfile. The Dockerfile does not include a HEALTHCHECK instruction. This means container orchestration systems cannot automatically detect if the brakeman scanner process is functioning correctly. Fix: Add a HEALTHCHECK instruction to verify the container is operational. For a CLI tool, consider using 'brakeman --version' or similar as a health indicator if running as a service. - Low · Running Container without Explicit Non-Root User —
Dockerfile. The Dockerfile does not specify a non-root user. The application will run as root inside the container, which violates the principle of least privilege and could amplify the impact if the application is compromised. Fix: Create and switch to a non-root user before the ENTRYPOINT: 'RUN addgroup -g 1000 brakeman && adduser -D -u 1000 -G brakeman brakeman' and 'USER brakeman'. - Medium · Overly Permissive Bundle Install —
Dockerfile, line 14. The Dockerfile uses 'bundle install --without "development test"' but does not use '--frozen' or '--check' flags. This allows Gemfile.lock to be updated during Docker builds, potentially introducing unexpected dependency changes or vulnerabilities. Fix: Use 'bundle install --frozen' to ensure the Gemfile.lock is strictly respected and prevent accidental dependency updates in production builds. - Low · Missing APK Cache Cleanup —
Dockerfile, line 9. The Dockerfile installs build dependencies with 'apk --update add' but does not clean up the APK cache afterward. This increases the final image size and could retain unnecessary package metadata. Fix: Add cache cleanup: 'RUN apk --update add build-base && rm -rf /var/cache/apk/*' to reduce image size. - Low · Security Policy Lacks Disclosure Timeline —
SECURITY.md. The SECURITY.md file provides a security contact but lacks information about expected response timelines, CVE disclosure procedures, or embargo periods. Fix: Enhance the security policy with: expected response timeline (e.g., 48 hours), CVE coordination process, embargo period details, and information about security advisories channel.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.