A high-performance, open-source static code security scanner
Project description
๐ Secara
Static Code Security Scanner
Fast. Accurate. Developer-Trusted.
Detect real, exploitable vulnerabilities โ not style warnings.
What is Secara?
Secara is an open-source, CLI-based static code security scanner designed for accuracy and developer usability. It uses a hybrid of AST-based analysis, regex pattern matching, and basic taint tracking to detect real security vulnerabilities in your codebase โ without false alarms.
It runs fully offline, requires no cloud APIs, and is built to scale across large monorepos.
โจ Features
| Feature | Details |
|---|---|
| ๐ Secrets Detection | AWS keys, GitHub tokens, Stripe keys, private keys, high-entropy strings |
| ๐ SQL Injection | AST-based detection of string concat / f-string SQL in Python and JS |
| ๐ฅ๏ธ Command Injection | os.system, subprocess with shell=True, exec(), eval() |
| ๐ Python (Tier 1) | Full AST analysis + Interprocedural Taint Tracking |
| ๐ JavaScript / TypeScript (Tier 1) | Regex-AST hybrid, no compiled dependencies |
| โ Java / Kotlin (Tier 2) | Detects SQLi, XXE, Insecure Deserialization, SSRF |
| ๐ PHP (Tier 2) | Detects SQLi, LFI/RFI, XSS, Path Traversal |
| ๐ Ruby (Tier 2) | Detects ActiveRecord SQLi, Mass Assignment, CMDi |
| ๐น Go (Tier 2) | Basic regex-based AST parsing (SQLi, CMDi, SSRF) |
| ๐ฆ SCA Scanning | Dependency vulnerability scanning via OSV.dev API |
| ๐ Bash / Shell (Tier 2) | Eval injection, unsafe substitution patterns |
| โ๏ธ JSON / YAML / .env (Tier 2) | Config file plaintext credential detection |
| ๐ง Inline Suppression | Fine-grained suppression with secara: ignore[RULE_ID] |
| ๐จ Beautiful Output | Rich terminal UI, JSON mode, SARIF export |
๐ Quick Start
Linux / macOS โ One-line install (recommended)
git clone https://github.com/ilyshoaib/secara.git
cd secara
bash install.sh
The installer will:
- Install secara from source
- Create a global symlink in
/usr/local/bin(may prompt forsudopassword) - Verify the
secaracommand works
You can now use secara from anywhere immediately:
secara scan .
Manual install (all platforms)
git clone https://github.com/ilyshoaib/secara.git
cd secara
pip install -e .
If secara command is not found after install (common on Linux):
# Check where pip installed the script
python3 -c "import site; print(site.getusersitepackages())"
# Add ~/.local/bin to your PATH permanently
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Windows (PowerShell):
git clone https://github.com/ilyshoaib/secara.git
cd secara
pip install -e .
# The secara command is available immediately โ no PATH fix needed
secara scan .
Install from PyPI (recommended)
pip install secara
Upgrade to the latest release:
pip install --upgrade secara
Uninstall:
pip uninstall secara
Scan a directory
secara scan ./src
Scan a single file
secara scan app.py
JSON output (for CI/CD pipelines)
secara scan . --json > results.json
๐ Usage
Usage: secara scan [OPTIONS] PATH
Scan a file or directory for security vulnerabilities.
Options:
--json Output results as JSON (machine-readable)
--sarif Output results as SARIF v2.1.0 for GitHub CI/CD integration
-o, --output Write output to file (useful with --sarif or --json)
-v, --verbose Show full descriptions and fix details
-s, --severity Minimum severity: HIGH | MEDIUM | LOW [default: LOW]
--min-confidence Minimum confidence: HIGH | MEDIUM | LOW [default: LOW]
--policy Policy preset: balanced | strict
--ci-profile CI profile preset: pr | main | release
--changed-only Scan only changed/untracked git files
--baseline Filter findings already present in baseline fingerprint file
--write-baseline Write current findings to a baseline fingerprint file
--enforce-suppression-metadata Require reason= and until= for suppressions
--no-cache Disable file cache (re-scan everything)
-w, --workers Number of parallel worker threads [default: 8]
-V, --version Show version and exit
--help Show this message and exit
Examples
# Scan everything, show all findings
secara scan .
# Only show HIGH severity findings
secara scan . --severity HIGH
# Full details with fix suggestions
secara scan ./src --verbose
# Machine-readable JSON for CI integration
secara scan . --json | jq '.[] | select(.severity == "HIGH")'
# Generate SARIF for GitHub Code Scanning
secara scan . --sarif --output secara-results.sarif
# Force re-scan (ignore cache)
secara scan . --no-cache
# Scan with more parallel workers
secara scan /large/repo --workers 16
# Only scan changed files (fast PR checks)
secara scan . --changed-only
# Strict policy + confidence filtering
secara scan . --policy strict --min-confidence MEDIUM
# CI environment preset
secara scan . --ci-profile pr
# Baseline workflow (new findings only)
secara scan . --write-baseline .secara/baseline.json
secara scan . --baseline .secara/baseline.json
# View historical scan trends
secara metrics --limit 20
# Show per-rule benchmark quality metrics
secara metrics --rules
# Generate benchmark quality report artifacts (JSON + markdown)
secara quality-report --json-output artifacts/quality_report.json --md-output artifacts/quality_report.md
# Show standardized CI presets
secara policy
secara policy --profile main --json
Advanced workflows
# Enforce suppression governance (must include reason= and until=YYYY-MM-DD)
secara scan . --enforce-suppression-metadata
# Focus only on high-confidence actionable findings
secara scan . --min-confidence HIGH
# Baseline + changed-only fast PR signal
secara scan . --baseline .secara/baseline.json --changed-only --policy strict
# Use built-in CI profiles (PR/main/release)
secara scan . --ci-profile pr
secara scan . --ci-profile main
secara scan . --ci-profile release
# Impacted graph mode (changed + dependent files)
secara scan . --impacted-only
# Deterministic sharded scan for CI parallel jobs
secara scan . --shard-index 0 --shard-count 4
# Merge shard JSON outputs into one deterministic artifact
secara merge-shards --input-glob "artifacts/shards/*.json" --output artifacts/merged_findings.json
# Audit suppression governance (active/expired/invalid)
secara suppressions . --json
# Persist lifecycle metadata in workspace-local file
secara scan . --lifecycle-file .secara/lifecycle.json --json
# Mark a finding as accepted risk or fixed
secara lifecycle-status <fingerprint> accepted_risk --lifecycle-file .secara/lifecycle.json
secara lifecycle-status <fingerprint> accepted_risk --expires-at 2026-12-31 --lifecycle-file .secara/lifecycle.json
# Exclude accepted/fixed findings from output and CI exit code
secara scan . --exclude-status accepted_risk,fixed --lifecycle-file .secara/lifecycle.json
# Fail CI only on open findings (default) or customize blocking statuses
secara scan . --fail-on-status open --lifecycle-file .secara/lifecycle.json
secara scan . --fail-on-status open,accepted_risk --lifecycle-file .secara/lifecycle.json
# Triage lifecycle state (list + bulk updates)
secara lifecycle-list --status open --json --lifecycle-file .secara/lifecycle.json
secara lifecycle-bulk-status accepted_risk --rule-id SQL001 --expires-at 2026-12-31 --lifecycle-file .secara/lifecycle.json
๐ก๏ธ Vulnerability Coverage (v0.6.1)
๐ Hardcoded Secrets (35+ patterns)
| Rule ID | Vulnerability | Severity |
|---|---|---|
| SEC001 | AWS Access Key ID (AKIA...) |
HIGH |
| SEC001B | AWS Secret Access Key | HIGH |
| SEC002 | GitHub PAT (ghp_...) |
HIGH |
| SEC004B | GitHub Fine-Grained Token (github_pat_...) |
HIGH |
| SEC004C | GitLab Token (glpat-...) |
HIGH |
| SEC005 | Stripe Live Key (sk_live_...) |
HIGH |
| SEC007B | Slack Webhook URL | HIGH |
| SEC008 | RSA/EC/OPENSSH Private Key Header | HIGH |
| SEC009 | SendGrid API Key (SG....) |
HIGH |
| SEC010 | Google API Key (AIza...) |
HIGH |
| SEC010B | Google OAuth Secret (GOCSPX-...) |
HIGH |
| SEC010C | GCP Service Account Key | HIGH |
| SEC012 | Hardcoded JWT Token | HIGH |
| SEC015 | OpenAI API Key (sk-...) |
HIGH |
| SEC016 | Anthropic API Key (sk-ant-...) |
HIGH |
| SEC017 | Azure Storage Connection String | HIGH |
| SEC018 | npm Auth Token (npm_...) |
HIGH |
| SEC020 | Telegram Bot Token | HIGH |
| SEC021 | Discord Bot Token | HIGH |
| SEC024 | PyPI Token (pypi-...) |
HIGH |
| SEC025 | HuggingFace Token (hf_...) |
HIGH |
| SEC026 | Databricks Token (dapi...) |
HIGH |
| SEC028 | HashiCorp Vault Token (hvs....) |
HIGH |
| SEC029 | Shopify Token (shpat_...) |
HIGH |
| SEC031 | Database Connection String (Postgres/MySQL/MongoDB) | HIGH |
| SEC013 | Generic Hardcoded Credential (password/secret/api_key) | HIGH |
| SEC014 | High-Entropy String (Possible Secret) | MEDIUM |
๐ SQL Injection
| Rule ID | Vulnerability | Languages | Severity |
|---|---|---|---|
| SQL001 | SQLi via String Concat / f-string | Python AST | HIGH |
| SQL201 | SQLi via Dynamic Statement | Java | HIGH |
| SQL301 | SQLi via mysql_query |
PHP | HIGH |
| SQL401 | SQLi via String Interpolation in ActiveRecord | Ruby | HIGH |
| SQL005 | SQLi via string construction in db.Query |
Go | HIGH |
๐ฅ๏ธ Command Injection
| Rule ID | Vulnerability | Languages | Severity |
|---|---|---|---|
| CMD001 | os.system() with dynamic args |
Python | HIGH |
| CMD201 | Runtime.getRuntime().exec() |
Java | HIGH |
| CMD301 | exec() / shell_exec() |
PHP | HIGH |
| CMD401 | `backticks` and system() |
Ruby | HIGH |
| SH001 | eval with variable in shell script |
Bash | HIGH |
| SH002 | Unsafe backtick substitution | Bash | HIGH |
| SH004 | Dangerous command with unquoted variable | Bash | HIGH |
๐ Cryptographic Failures [OWASP A02]
| Rule ID | Vulnerability | Languages | Severity |
|---|---|---|---|
| CRY001 | Weak hash: hashlib.md5() / hashlib.sha1() |
Python | HIGH |
| CRY002 | SSL cert verification disabled: verify=False |
Python | HIGH |
| CRY003 | Insecure PRNG: random.random() for secrets |
Python | MEDIUM |
| CRY004 | Weak hash: crypto.createHash('md5'/'sha1') |
JavaScript | HIGH |
| CRY005 | Insecure random: Math.random() for tokens/secrets |
JavaScript | HIGH |
๐ Server-Side Request Forgery [OWASP A10]
| Rule ID | Vulnerability | Languages | Severity |
|---|---|---|---|
| SSRF001 | requests.get/post(user_url) โ tainted URL |
Python | HIGH |
| SSRF002 | fetch/axios.get(user_url) โ tainted URL |
JavaScript | HIGH |
| SSRF003 | http.Get with dynamic strings |
Go | HIGH |
๐ฃ Insecure Deserialization [OWASP A08]
| Rule ID | Vulnerability | Languages | Severity |
|---|---|---|---|
| DSER001 | pickle.loads(data) โ arbitrary code execution |
Python | HIGH |
| DSER002 | marshal.loads(data) |
Python | HIGH |
| DSER003 | shelve.open(user_path) โ pickle-based |
Python | MEDIUM |
| DSER004 | yaml.load() without SafeLoader |
Python | HIGH |
| DSER005 | node-serialize.deserialize(req.body) |
JavaScript | HIGH |
| DSER006 | yaml.load() without safe schema |
JavaScript | HIGH |
๐ Path Traversal [OWASP A01]
| Rule ID | Vulnerability | Languages | Severity |
|---|---|---|---|
| PATH001 | open(user_input) โ directory traversal |
Python | HIGH |
| PATH201 | new File(user_input) |
Java | HIGH |
| PATH301 | file_get_contents($user_input) |
PHP | HIGH |
| PATH401 | File.read(user_input) |
Ruby | HIGH |
| PATH004 | os.Open with dynamic path |
Go | MEDIUM |
๐ฏ Injection โ Extended [OWASP A03]
| Rule ID | Vulnerability | Languages | Severity |
|---|---|---|---|
| SSTI001 | SSTI via render_template_string(user_data) |
Python | HIGH |
| XSS001 | XSS via innerHTML = req.params.x |
JavaScript | HIGH |
| XSS002 | Potential XSS via element.innerHTML = var |
JavaScript | MEDIUM |
| XSS003 | XSS via document.write(user_data) |
JavaScript | HIGH |
๐ Security Logging Failures [OWASP A09]
| Rule ID | Vulnerability | Languages | Severity |
|---|---|---|---|
| LOG001 | Sensitive variable (password/token) passed to logger | Python | MEDIUM |
| TEMP001 | Insecure Temporary File via tempfile.mktemp() |
Python | HIGH |
| RACE001 | TOCTOU check via os.path.exists() before open() |
Python | MEDIUM |
| MASS001 | Mass Assignment via __dict__.update(user_data) |
Python | HIGH |
| MASS002 | Mass Assignment via **kwargs in ORM creation |
Python | MEDIUM |
โ๏ธ Security Misconfiguration [OWASP A05]
| Rule ID | Vulnerability | Languages | Severity |
|---|---|---|---|
| CFG001 | Plaintext secret value in .env/.ini file |
Config | HIGH |
| CFG201 | Spring Boot CSRF Disabled | Java | MEDIUM |
| CFG301 | display_errors enabled in code |
PHP | MEDIUM |
| CFG010 | CORS wildcard * origin |
JavaScript | MEDIUM |
๐ฆ Software Composition Analysis (SCA)
| File | Scanner | Severity Mapping |
|---|---|---|
requirements.txt |
Python Dependency Scan | OSV.dev (CVE/GHSA) |
package.json |
JS Dependency Scan | OSV.dev (CVE/GHSA) |
go.mod |
Go Dependency Scan | OSV.dev (CVE/GHSA) |
Gemfile.lock |
Ruby Dependency Scan | OSV.dev (CVE/GHSA) |
๐๏ธ Architecture
secara/
โโโ cli.py # CLI entry point (deps/scan commands)
โโโ scanner/
โ โโโ file_scanner.py # Recursive traversal + parallel execution
โ โโโ language_engine.py # Maps files to analysis tier (Tier 1/2)
โ โโโ cache.py # SHA-256 file cache
โโโ detectors/
โ โโโ python_analyzer.py # Python AST + Taint analysis
โ โโโ js_analyzer.py # JavaScript/TypeScript hybrid
โ โโโ java_analyzer.py # Java/Kotlin Tier 2
โ โโโ php_analyzer.py # PHP Tier 2
โ โโโ ruby_analyzer.py # Ruby Tier 2
โ โโโ secrets_detector.py # Global secrets detection
โ โโโ generic_analyzer.py # Base class for YAML-based regex detectors
โโโ sca/
โ โโโ osv_client.py # OSV.dev API integration
โ โโโ parsers.py # Manifest parsers (requirements, package.json...)
โโโ taint/
โ โโโ interproc_taint.py # Interprocedural Call Graph logic
โ โโโ python_taint.py # Intraprocedural taint (AST)
โโโ output/
โโโ sarif_formatter.py # SARIF v2.1.0 output
โโโ rich_formatter.py # Pretty-print CLI output
Language Tiers:
- Tier 1 (AST-based): Python, JavaScript, TypeScript
- Tier 2 (Regex-hybrid): Java, Kotlin, PHP, Ruby, Go, Bash
- SCA: requirements.txt, package.json, go.mod, Gemfile.lock
โก Performance
| Scenario | Performance |
|---|---|
| 1,000 Python files | ~2-3 seconds |
| 10,000 mixed files | ~15-25 seconds |
| Re-scan (cached) | ~0.5 seconds |
| Files > 512KB | Automatically skipped |
| Binary files | Automatically skipped |
Performance scales linearly with --workers. Cached results make repeat scans near-instant.
๐ง Suppressing False Positives
Add # secara: ignore to any line to suppress findings on that specific line:
SIGNING_NONCE = "Xk9mP2wQzR4nV7tY1aL8cF0jH6" # secara: ignore
result = eval(compile(safe_tree, "<string>", "eval")) # secara: ignore
๐งช Running Tests
# Install with dev dependencies
pip install -e ".[dev]"
# Run all tests
pytest tests/ -v
# With coverage
pytest tests/ --cov=secara --cov-report=html
๐ค Contributing
Contributions are welcome! See CONTRIBUTING.md for guidelines.
Areas where you can help:
- Adding new vulnerability rules
- Improving taint tracking accuracy
- Adding support for new languages (Go, Ruby, Java, PHPโฆ)
- Improving false positive rate
- VS Code extension / GitHub Action support
๐บ๏ธ Roadmap
- Go language support (Tier 2/Regex)
- Java / Kotlin / Ruby / PHP support (Tier 2)
- Software Composition Analysis (SCA) - Dependency scanning
- SARIF output format (GitHub Code Scanning compatible)
- GitHub Actions workflow
- VS Code extension
- Interprocedural taint analysis
- Custom rule authoring (YAML)
- Path traversal detection
- SSRF detection
- Insecure deserialization detection
- CWE Mapping for all rules
๐ License
GNU GPLv3 โ see LICENSE for details.
Built with โค๏ธ for the security community ยท Star โญ if you find it useful
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file secara-0.10.1.tar.gz.
File metadata
- Download URL: secara-0.10.1.tar.gz
- Upload date:
- Size: 109.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
91c200a392c9e3035aad9c3fd9e8f504e874f9a6d5f804eba260fe6c9d484f46
|
|
| MD5 |
365bb178ec76da4b2a99fdeb20b1fc39
|
|
| BLAKE2b-256 |
654b18112f3a085c55d7b3e1a586290ada6c6cef6f459721180448f5d17f03fe
|
File details
Details for the file secara-0.10.1-py3-none-any.whl.
File metadata
- Download URL: secara-0.10.1-py3-none-any.whl
- Upload date:
- Size: 108.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
394c3e9fe5d1958b7d522534a944180c851c2e83608b3c64e5948865dca8c5d3
|
|
| MD5 |
eea9155ffc28d0cbe38ea961c6ff73f6
|
|
| BLAKE2b-256 |
e8659a0fc1d337f64fe7767d063f7923a40e6c090e351e3d9e447427de6632cd
|