Skip to main content

Finds the door you left open by default: fail-open logic and insecure config defaults in your code.

Project description

ajar — find the door you left open by default

A defensive scanner for fail-open logic, insecure defaults, and web vulnerabilities — that understands your code and explains every fix.

CI license python rules languages local only stance

ajar scanning a project and explaining each finding


Most secret scanners look for the credential you put in (API_KEY = "sk-123").

ajar looks for the door you left open by default — code that silently runs insecure when a config is missing, an environment name differs, or an error gets swallowed. No exploit required: the default is the vulnerability.

if os.getenv("APP_ENV") != "production":
    require_auth = False        # 🚪 unset/typo'd env → auth is OFF in prod

requests.get(url, verify=False) # 🚪 every request open to a man-in-the-middle

try:
    return check_permission(user)
except Exception:
    return True                 # 🚪 an error becomes a free pass

Nobody flags these well. That's the gap ajar fills.

What it scans

Point ajar at a web app or SaaS backend and it flags five families of risk:

Category Examples
🚪 fail-open (flagship) auth disabled by a missing env var, verify=False defaults, errors that grant access
⚙️ insecure-defaults DEBUG=True, wildcard CORS, 0.0.0.0 binds, weak hashes, insecure cookies
💉 injection (web) SQL injection, command injection, XSS, SSRF, path traversal, unsafe deserialization, SSTI, open redirect
🌊 denial-of-service missing timeouts, catastrophic-backtracking regex (ReDoS), decompression bombs, user-controlled regex
🔑 secrets hardcoded AWS/GitHub/Google/Stripe/OpenAI keys, private keys, tokens, credentials in URLs, plus entropy-based detection for random secrets that match no known pattern

Works on Python, JavaScript, TypeScript, and TSX (React/Next.js). Every rule is defensive — it explains the attack and the safe fix, and never produces an exploit.

It actually understands your code

With the optional parser engine (pip install ajar[full]), ajar uses tree-sitter — the same parser GitHub uses — to understand the real structure of your code. That means:

  • A keyword mentioned in a comment or a string never triggers a false alarm — in Python and in your TypeScript/Next.js files.
  • Secrets are still caught inside strings (that's where they hide), while code checks are only applied to real code.
  • Data-flow (taint) tracking follows user input across variables into a dangerous sink — catching exploitable injections that single-line patterns miss (e.g. q = build(request.args['id']); cursor.execute(q)).

No parsers installed? ajar falls back to fast pattern scanning and still works — so it's "pro by default" without ever being fragile.

🤖 Use it with your AI assistant (or any AI assistant)

ajar is built to pair with an AI coding assistant so you don't just find vulnerabilities — you fix them. A scanner tells you what's wrong; your AI applies the fix; ajar confirms it's closed. Together they close the loop.

ajar ships as a AI-assistant skill (in skills/ajar/). Install it and just say:

"Use the ajar skill on my project."

Your AI assistant will then:

  1. Scan your code with ajar (ajar scan . --format json).
  2. Explain every finding — what it is, how it's attacked, how to fix it.
  3. Fix each issue with you, worst-first, making minimal correct changes.
  4. Re-scan until the project is clean.

Every finding already carries a machine-readable why and fix (see --format json), so any assistant can act on the results — no special mode needed. It stays defensive throughout: it fixes and protects, never attacks.

A clean scan is a strong result, not a guarantee — ajar catches common, detectable issues, not business-logic or design flaws. Keep a human in the loop for anything security-critical.

Why ajar is different

  • 🎯 Fail-open first. The flagship category is fail-open logic, not just secrets — the misconfigurations behind real breaches (open buckets, auth-less admin panels, debug in prod).
  • 🎓 It teaches. Every finding explains how an attacker exploits it and exactly how to fix it, with references. You learn while you scan.
  • 🧠 Understands code, not just text. An optional tree-sitter engine parses Python/JS/TS/TSX so comments and strings never cause false positives — the difference between a serious tool and a noisy one.
  • 🔒 Trust by design. 100% local. Zero telemetry. Your code never leaves your machine. Rules are plain, readable YAML you can audit in ajar/rules/.
  • Light and robust. Tiny core (one dependency); the parser engine is an optional extra, and ajar degrades gracefully to pattern scanning without it. Terminal, JSON, and SARIF output for CI.

How it compares

ajar isn't trying to replace the big scanners — it fills a gap next to them.

ajar secret scanners big SAST platforms
Fail-open / insecure-default logic ✅ focus ⚠️ partial ⚠️ partial
Comment/string-aware (few false positives) ✅ tree-sitter ⚠️
Explains attack and fix per finding ⚠️
Runs 100% locally, zero telemetry ⚠️ ❌ (often cloud)
Transparent rules you can read/edit ✅ YAML ⚠️ ⚠️
Setup time seconds seconds hours

Install

pip install "ajar-scanner[full]"   # recommended: includes the tree-sitter engine
pip install ajar-scanner           # lightweight: pattern scanning only
# the command is `ajar` either way. Or from source:
git clone https://github.com/ignaciovalderrama999-dotcom/ajar && cd ajar && pip install ".[full]"

Usage

ajar scan .                       # scan the current project
ajar scan path/to/file.py         # scan one file
ajar scan examples/vulnerable_webapp.py  # demo: SQLi, XSS, SSRF, RCE, path traversal
ajar scan . --min-severity high   # only show high+ findings
ajar scan . --exclude tests --exclude '*.min.js'  # skip paths (repeatable)
ajar scan . --format json         # machine-readable output
ajar scan . --format sarif        # GitHub code scanning
ajar scan . --format report       # a graded Markdown audit report (A–F)
ajar scan . --write-baseline      # record current findings as accepted
ajar scan . --baseline            # then only show NEW findings
ajar rules                        # list every rule ajar checks
ajar rules --format md            # the full rule catalog (see RULES.md)

The full catalog of all rules, with the attack and the fix for each, lives in RULES.md (generated by ajar rules --format md).

Example

$ ajar scan examples/vulnerable_config.py

 CRITICAL  examples/vulnerable_config.py:16:5
   Auth disabled outside production  [FAILOPEN_AUTH_ENV_BYPASS]
   Authentication is switched off based on an environment name.
   code: require_auth = False
   why: If the env var that flips this is missing or misspelled in production,
        the app boots wide open with no authentication. The default IS the bug.
   fix: Fail closed — default auth to ON and require an explicit, logged opt-out.
   ref: https://owasp.org/Top10/A05_2021-Security_Misconfiguration/

Found 9 open doors: 2 critical · 6 high · 1 medium

Configure it once

Drop a .ajar.yml in your project root and stop repeating flags (CLI flags still override it). See .ajar.yml.example:

min_severity: low
fail_on: high
exclude:
  - tests
  - "*.min.js"
disable:
  - DEFAULT_BIND_ALL_INTERFACES

Adopt it gradually with a baseline

Got an existing codebase with findings you can't fix today? Record them once and let ajar flag only what's new from then on:

ajar scan . --write-baseline   # accept today's findings (.ajar-baseline.json)
ajar scan . --baseline         # from now on, only NEW issues fail the build

Use it in CI

ajar returns a non-zero exit code when it finds an issue at or above --fail-on (default: medium), so it drops straight into any pipeline. Add a step to your GitHub Actions workflow:

- run: pip install "ajar-scanner[full]"
- run: ajar scan . --fail-on high

pre-commit

ajar ships a pre-commit hook — add it to .pre-commit-config.yaml:

repos:
  - repo: https://github.com/ignaciovalderrama999-dotcom/ajar
    rev: v0.1.0
    hooks:
      - id: ajar

Docker

No local install needed:

docker run --rm -v "$PWD:/src" ghcr.io/ignaciovalderrama999-dotcom/ajar scan /src

Suppressing a finding

When something is a deliberate, reviewed exception, silence it inline:

DEBUG = True  # ajar:ignore                    # silence every rule on this line
DEBUG = True  # ajar:ignore DEFAULT_DEBUG_ON    # silence one specific rule

Writing your own rules

Rules are transparent YAML — no hidden logic. Drop a file in ajar/rules/ (or point --rules at your own directory):

rules:
  - id: MY_RULE
    name: Short human name
    severity: high          # info | low | medium | high | critical
    category: fail-open
    message: One-line description of the issue.
    pattern: '(?i)dangerous_setting\s*=\s*True'   # a Python regex
    why: How an attacker abuses this.
    fix: How to close the door.
    references:
      - https://owasp.org/...
    extensions: [".py"]    # optional: only these file types
    context: code          # optional: code (default) | string | any

context controls where a match counts once the tree-sitter engine knows code from comments and strings: code ignores comments and strings (most rules), string allows matches inside string literals (e.g. a dangerous regex), any never suppresses (secrets — a leaked key counts anywhere).

Ethics: analyze and protect, never attack 🛡️

ajar is a defensive tool, on purpose. It points at risk and explains the fix — it never generates exploits, payloads, or offensive tooling, and it never connects to or probes any remote system. Its whole job is to help you close doors before someone else finds them open. That principle is not up for negotiation, and it guides every rule we add.

Legal & responsible use ⚖️

  • Use it only on code you own or are authorized to review. See the full Acceptable Use Policy.
  • It is an aid, not a guarantee. A clean scan does not mean your app is secure. See the Disclaimer & Limitation of Liability.
  • Provided "AS IS", no warranty, no liability — standard Apache 2.0 terms. You are responsible for how you use it.
  • Found a bug in ajar itself? See SECURITY.md.
  • Forks & modified copies are the modifier's responsibility, not the author's. Only the official repository is endorsed; the name "ajar" may not be used to promote modified versions. Details in the DISCLAIMER.

By using ajar you accept the DISCLAIMER and Acceptable Use Policy. If you do not agree, do not use it.

FAQ

Isn't this just another secret scanner? No. Secret scanners find the credential you committed. ajar's flagship category is fail-open logic — code that runs insecure when a config is missing or wrong. That's a different, largely uncovered class of bug.

Will it catch every vulnerability? No tool does, and ajar is honest about it: it's a fast, heuristic first line of defense, not a replacement for a real audit. See the DISCLAIMER.

Does my code leave my machine? Never. ajar runs 100% locally, reads files only, and sends nothing anywhere. No telemetry, no account, no network calls.

How do I silence a false positive? Inline # ajar:ignore, a disable: list in .ajar.yml, or a --baseline.

Can I use it to attack a site? No. ajar analyzes local source and never touches remote systems or generates exploits. It is defensive by design — see ACCEPTABLE_USE.md.

Roadmap

  • --baseline to accept existing findings and only flag new ones
  • pre-commit hook and Docker image
  • Denial-of-service rule category
  • Structural (tree-sitter) engine so comments/strings never false-positive
  • Deeper structural rules (track a value across lines, e.g. template-literal SQLi through a variable)
  • More languages (Go, Java, PHP, Ruby — tree-sitter already supports 100+)
  • Publish to PyPI

Contributing

New rules are the best contribution — especially fail-open patterns you've seen in the wild. Keep every rule defensive, explainable, and referenced. PRs and issues welcome.

License

Apache License 2.0 © 2026 Ignacio Valderrama. See LICENSE and NOTICE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ajar_scanner-0.1.5.tar.gz (49.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ajar_scanner-0.1.5-py3-none-any.whl (47.8 kB view details)

Uploaded Python 3

File details

Details for the file ajar_scanner-0.1.5.tar.gz.

File metadata

  • Download URL: ajar_scanner-0.1.5.tar.gz
  • Upload date:
  • Size: 49.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ajar_scanner-0.1.5.tar.gz
Algorithm Hash digest
SHA256 c4aefafe4a5da1c198bf85def1eacc547c66c8e307cb0c19b0ed6c2ec9b68665
MD5 afdbdb75638aa4954379bb0c16709330
BLAKE2b-256 dd3610d24ce6d1002dc80db6d112fd8f605b8234ba3e9d76e25bb1724165c14a

See more details on using hashes here.

Provenance

The following attestation bundles were made for ajar_scanner-0.1.5.tar.gz:

Publisher: publish.yml on ignaciovalderrama999-dotcom/ajar

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ajar_scanner-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: ajar_scanner-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 47.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ajar_scanner-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 8edba0d38f3c016e6d836b1e47fe5b850c048bfbaebb86c7a9c166c7aa672cd4
MD5 89fd7af8212c4dab0c697c4c58ce5b7a
BLAKE2b-256 9363dfe9e3275bb132759026cc20a9616e1a6933543d11a99eef9f56a7589087

See more details on using hashes here.

Provenance

The following attestation bundles were made for ajar_scanner-0.1.5-py3-none-any.whl:

Publisher: publish.yml on ignaciovalderrama999-dotcom/ajar

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page