Auto-fix security vulnerabilities in your PRs.
Fixpoint is a deterministic security patch bot that enforces compliance at merge time—so security findings become merged fixes, not backlog.
As AI increases PR volume, Fixpoint keeps security debt at zero: every finding gets a fix, every fix gets merged.
Positioning: The fixed point in your workflow where security issues are detected and corrected before merge—no AI, no wait, no backlog.
Try it now! Fork the demo repository to see Fixpoint in action.
Install as GitHub App (free beta): Install Fixpoint — one-click install for your org or repos.
Free beta for early adopters. No billing, no Marketplace signup—just install and go.
We're inviting early users to test Fixpoint before wider release.
| What to expect | Details |
|---|---|
| Stability | Core flows tested; 133 tests pass. Some edge cases may remain. |
| Platforms | GitHub Action & CLI: Linux, Mac. Semgrep: not supported on Windows. |
| Modes | Start with mode: warn — review proposed fixes before enabling enforce. |
| Feedback | Report issues, awkward workflows, or "how do I...?" in Discussions or Issues. |
Quick test: Fork fixpoint-demo, add the workflow from Quick Start, open a PR with vulnerable code. Fixpoint will comment or fix.
Support: support@fixpoint.dev · Privacy: Privacy Policy
See Beta Tester Notes for full release notes and feedback prompts.
| Vulnerability | Detection | Auto-Fix |
|---|---|---|
| SQL Injection | f-strings, concatenation, .format(), % formatting |
✅ Parameterized queries |
| Hardcoded Secrets | Passwords, API keys, tokens, database URIs | ✅ os.environ.get() |
| XSS (Templates) | |safe filter, autoescape off |
✅ Removes unsafe patterns |
| XSS (Python) | mark_safe(), SafeString() |
✅ Replaces with escape() |
| Command Injection | os.system(), subprocess with shell=True |
✅ List-based subprocess |
| Path Traversal | os.path.join with user input |
✅ Path validation |
| SSRF | requests.get(), urlopen with dynamic URL |
|
| JS/TS eval | eval() with user input |
|
| JS/TS secrets | apiKey = "xxx" |
✅ process.env.API_KEY |
| JS/TS DOM XSS | innerHTML = with user input |
✅ textContent = |
- Deterministic-first: Same input → same output. No AI hallucinations.
- No AI/LLM for fixes: All fixes are rule-based and auditable.
- Trust through transparency: Start in warn mode, graduate to enforce when ready.
- Safety over speed: Max-diff limits, optional test run, CWE/OWASP tags in every finding.
Add to .github/workflows/fixpoint.yml:
name: Fixpoint
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: write
pull-requests: write
statuses: write
jobs:
fixpoint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
fetch-depth: 0
- name: Fixpoint
uses: IWEBai/fixpoint@v1
with:
mode: warn # Start with warn, graduate to enforce
base_branch: ${{ github.base_ref }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}That's it. Fixpoint will scan every PR for vulnerabilities.
# Before (vulnerable)
query = f"SELECT * FROM users WHERE email = '{email}'"
cursor.execute(query)
# After (auto-fixed)
query = "SELECT * FROM users WHERE email = %s"
cursor.execute(query, (email,))# Before (vulnerable)
api_key = "sk_live_abc123def456"
# After (auto-fixed)
api_key = os.environ.get("API_KEY")<!-- Before (vulnerable) -->
<p>{{ user_input|safe }}</p>
<!-- After (auto-fixed) -->
<p>{{ user_input }}</p># Before (vulnerable)
return mark_safe(user_input)
# After (auto-fixed)
return escape(user_input)# Before (vulnerable)
os.system(user_input)
# After (auto-fixed)
subprocess.run(shlex.split(user_input), shell=False)# Before (vulnerable)
path = os.path.join(base_dir, user_input)
# After (auto-fixed)
path = os.path.join(base_dir, user_input)
if not os.path.realpath(path).startswith(os.path.realpath(base_dir)):
raise PermissionError("Path traversal denied")// Before (vulnerable)
const apiKey = "sk_live_abc123";
// After (auto-fixed)
const apiKey = process.env.API_KEY || "";// Before (vulnerable)
el.innerHTML = userInput;
// After (auto-fixed)
el.textContent = userInput;mode: warn- Posts PR comments with proposed fixes
- Sets status check to FAIL
- No commits made
- Perfect for building trust
mode: enforce- Applies fixes automatically
- Commits to PR branch
- Sets status check to PASS
- For trusted, production use
Recommended: Start with warn mode, review the fixes, then graduate to enforce.
Fixpoint sets GitHub status checks (fixpoint/compliance):
| Status | Meaning |
|---|---|
| ✅ PASS | No vulnerabilities found |
| ❌ FAIL | Vulnerabilities found (warn mode) |
| ✅ PASS | Vulnerabilities fixed (enforce mode) |
- Go to Settings → Branches → Branch protection rules
- Enable "Require status checks to pass before merging"
- Select:
fixpoint/compliance - Save
Now PRs with security issues can't be merged until fixed.
Create .fixpoint.yml in your repo root to customize safety rails.
New: presets and a CLI generator to make this effortless.
Preset configs
- starter: warn-only, low noise
- balanced: enforce safe fixes, warn on riskier transforms
- strict: enforce more rules, tighter safety rails
- tailored: team-specific defaults (see preset in core/config.py)
Generate a config from a preset:
python main.py config init --preset starterThis writes .fixpoint.yml in the current directory. Use --repo to target another path and --force to overwrite.
Example (balanced preset)
max_diff_lines: 400
max_files_changed: 8
max_runtime_seconds: 90
test_before_commit: false
test_command: "pytest"
allow_dependency_changes: false
sensitive_paths_allowlist: []
rules:
enabled:
- sqli
- secrets
- xss
- command-injection
- path-traversal
- ssrf
- eval
- dom-xss
enforce_per_rule:
sqli: enforce
secrets: enforce
dom-xss: enforce
xss: warn
command-injection: warn
path-traversal: warn
ssrf: warn
eval: warn
severity_threshold: ERROR
# Longest-prefix policies for specific directories
directory_policies:
"src/critical/":
severity_threshold: WARNING
enforce_per_rule:
xss: warn
format_after_patch: true
max_format_expansion: 0.2Or use env vars: FIXPOINT_MAX_DIFF_LINES, FIXPOINT_TEST_BEFORE_COMMIT, FIXPOINT_TEST_COMMAND.
Schema validation
Fixpoint validates .fixpoint.yml at runtime and reports friendly, line-level errors for bad fields or types.
Baseline mode (noise suppression)
Baseline mode filters pre-existing findings so only new issues show up.
# Create a baseline at a commit
python main.py baseline create --sha <commit-sha>Enable in .fixpoint.yml:
baseline_mode: true
baseline_sha: "<commit-sha>"
baseline_max_age_days: 30 # optional rebaseline window (0 = never)GitHub Action — Pass as inputs:
- uses: IWEBai/fixpoint@v1
with:
mode: warn
max_diff_lines: "500"
test_before_commit: "true"
test_command: "pytest"PR comments include CWE/OWASP tags (e.g. CWE-89 | A03:2021) for each finding.
Create .fixpointignore in your repo root:
# .fixpointignore
tests/
test_*.py
migrations/
third_party/
*.test.pyDetects unsafe SQL construction patterns:
| Pattern | Example |
|---|---|
| f-strings | f"SELECT * WHERE id = {id}" |
| Concatenation | "SELECT * WHERE id = " + id |
.format() |
"SELECT {}".format(id) |
% formatting |
"SELECT %s" % id |
Supports variable names: query, sql, stmt, command, etc.
Supports cursor names: cursor, cur, db, conn, c, etc.
Detects secrets in code:
| Type | Examples |
|---|---|
| AWS Keys | AKIA... pattern |
| GitHub Tokens | ghp_..., gho_... |
| Slack Tokens | xoxb-... |
| Stripe Keys | sk_live_... |
| Database URIs | postgres://user:pass@... |
| Generic | password = "...", api_key = "..." |
In Templates (Jinja2/Django):
{{ variable|safe }}- The|safefilter{% autoescape off %}- Disabled escaping
In Python:
mark_safe(variable)- Django mark_safeSafeString(variable)- Django SafeStringMarkup(variable)- Flask/Jinja2 Markup
| Issue | Pattern | Fix |
|---|---|---|
| eval | eval(userInput) |
Detection only; guidance recommends JSON.parse or removal |
| Secrets | apiKey = "sk_live_xxx" |
process.env.API_KEY |
| DOM XSS | el.innerHTML = userInput |
el.textContent = userInput |
# Install
pip install -r requirements.txt
pip install semgrep # Linux/Mac only - required for scanning
# Warn mode (scans .py, .js, .ts, .jsx, .tsx)
python main.py /path/to/repo --warn-mode
# Enforce mode
python main.py /path/to/repo
# PR diff mode
python main.py /path/to/repo --pr-mode --base-ref main --head-ref featureFor on-premise deployments:
# Configure
cp .env.example .env
# Edit .env with your settings
# Run
python webhook_server.pyConfigure GitHub webhook:
- URL:
https://your-domain.com/webhook - Events:
pull_request(opened, synchronize) - Secret: Your
WEBHOOK_SECRET
See API Reference for details.
- ❌ Fix arbitrary bugs
- ❌ Refactor code
- ❌ Auto-merge PRs
- ❌ Generate creative fixes
- ❌ Use AI/LLMs
Only deterministic, verifiable, compliance-safe changes.
- Python 3.12+
- Semgrep (installed automatically in GitHub Action and Docker; install separately for CLI:
pip install semgrep) - GitHub repository
- GitHub Actions (or self-hosted webhook)
- Supported files:
.py,.js,.ts,.jsx,.tsx
- iwebai.space - IWEB website
- r/IWEBai - Community on Reddit
- Demo Repository - Try Fixpoint with vulnerable code examples
- Beta Tester Notes - Release notes and feedback prompts for testers
- Introduction - Why Fixpoint?
- Getting Started - Complete setup guide
- API Reference - Webhook API
- Environment Variables - Configuration
- Roadmap - What's next
MIT License - See LICENSE for details.
Let us know — it helps us improve and plan what to build next.
| We'd love to... | How |
|---|---|
| Know who's using it | Reply in "Who's using Fixpoint?" with your company/repo (optional). |
| Get your feedback | Open an Issue or Discussion — bugs, feature ideas, or "how do I...?" |
| Help us build | Would you pay for a hosted version? What would make it worth it? Reply here — your input shapes our roadmap. |
| Offer you more | Need hosted Fixpoint (SaaS) or enterprise support? Get in touch — we're building paid options. |
- Website: iwebai.space
- Community: r/IWEBai on Reddit
- Contributing: CONTRIBUTING.md
- Security: SECURITY.md (report vulnerabilities)
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Fixpoint by IWEB — Because security shouldn't slow you down.