Skip to main content

Installation & Quick Start

Level Beginner
Reading time ⏱ 15 min
words 4531
Topics installcliconfig

StaticCodeAudit

by CodeFixture

Standalone compliance, security and code quality audit tool for web projects (Python, JavaScript/TypeScript, HTML, Java, C#, PHP, YAML).


Table of Contents

  1. Installation
  2. Quick Start
  3. CLI Options
  4. Project Management
  5. Configuration
  6. Audit Categories
  7. Reports
  8. CI/CD Integration
  9. Internationalization (i18n)
  10. Custom Rules

Installation

  1. Download the binary archive for your platform from your customer area (staticcodeaudit-linux-x64.tar.gz, staticcodeaudit-macos-arm64.tar.gz, staticcodeaudit-macos-x64.tar.gz or staticcodeaudit-windows-x64.zip).
  2. Extract the archive.
  3. Move the resulting directory anywhere on disk. The binary is fully self-contained — there is nothing to install on the target machine.
# Linux / macOS
tar -xzf staticcodeaudit-linux-x64.tar.gz
cd staticcodeaudit-linux-x64

# Windows (PowerShell)
Expand-Archive staticcodeaudit-windows-x64.zip
cd staticcodeaudit-windows-x64

In the rest of this document, the binary is referred to as staticcodeaudit-<platform> (replace <platform> with linux-x64, macos-arm64, macos-x64 or windows-x64).


Quick Start

# First run: automatically generates audit.config.json and registers the project
./staticcodeaudit-<platform> /path/to/my-project --init

# Run the audit
./staticcodeaudit-<platform> /path/to/my-project

The --init flag interactively creates audit.config.json by detecting:

  • Project languages (Python, JavaScript/TypeScript, HTML, Java, C#, PHP)
  • Source code directories (app/, src/, etc.)

Important: At runtime, the script uses only the audit.config.json configuration file — no auto-detection.


CLI Options

Option Description
project_path Path to the project to audit (default: .)
--init Create audit.config.json interactively
--quick, -q Quick mode (security only)
--fail-on-high Exit code 1 if HIGH vulnerabilities found (CI/CD)
--sarif Generate SARIF 2.1.0 export (GitHub Code Scanning, GitLab SAST)
--lang Report and console language (fr, en, es, de, default: en)
--debug Debug logging (stderr + log file)
--create-rule Create or edit a custom rule (unified interactive wizard)
--init-rule Alias for --create-rule (backward compatibility)
--custom-rules-match Check custom rules ↔ custom fixtures coverage
--with-tests Auto-detect and run project unit tests
--with-deps Run dependency vulnerability scan (pip-audit, npm audit)
--rules-match Check that every builtin rule has matching fixtures
--benchmark Run benchmark (precision, recall, F1 on fixtures)

Examples:

# Full audit
./staticcodeaudit-linux-x64 /path/to/project

# Quick mode (security only)
./staticcodeaudit-linux-x64 /path/to/project --quick

# CI/CD mode (SARIF export + exit code 1 on HIGH)
./staticcodeaudit-linux-x64 /path/to/project --sarif --fail-on-high

./staticcodeaudit-linux-x64 /path/to/project --with-tests

# With dependency vulnerability scan
./staticcodeaudit-linux-x64 /path/to/project --with-deps

# French report
./staticcodeaudit-linux-x64 /path/to/project --lang=fr

# Create a custom rule (interactive taint wizard)
./staticcodeaudit-linux-x64 /path/to/project --init-rule

# Verify rules/fixtures coverage
./staticcodeaudit-linux-x64 --rules-match

# Benchmark (precision, recall, F1)
./staticcodeaudit-linux-x64 --benchmark

# Debug mode
./staticcodeaudit-linux-x64 /path/to/project --debug

Debug output goes to stderr and a log file ({output}/SCA-DEBUG-YYYY-MM-DD-HH-MM.log). Each line includes: level, module, source file:line, function, thread and PID. Debug messages are translated according to --script-lang (same as console messages).

# stderr (--script-lang=en, default)
[SCA-DBG] INFO    sca.runner             | runner.py:42 run() [MainThread:12345] | Config loaded: ...

# stderr (--script-lang=fr)
[SCA-DBG] INFO    sca.runner             | runner.py:42 run() [MainThread:12345] | Config chargée : ...

# log file (same format with timestamp)
2026-03-03 14:30:15 INFO    sca.runner             | runner.py:42 run() [MainThread:12345] | Config loaded: ...
# Project management
./staticcodeaudit-linux-x64 --list-projects                        # List all projects
./staticcodeaudit-linux-x64 /path/to/project --project-info        # Project info
./staticcodeaudit-linux-x64 /path/to/project --init-fixtures       # Create fixtures directory
./staticcodeaudit-linux-x64 /path/to/project --unregister          # Unregister project

# List audit categories
./staticcodeaudit-linux-x64 --list-categories
./staticcodeaudit-linux-x64 --list-categories --script-lang=fr

# List all rules by category
./staticcodeaudit-linux-x64 --list-rules
./staticcodeaudit-linux-x64 /path/to/project --list-rules --script-lang=fr  # with project fixtures

# Fixture validation
./staticcodeaudit-linux-x64 /path/to/project --self-test

Output Formats

Each audit run generates HTML + JSON by default. Additional formats are available on demand:

Format Content Audience How to enable
HTML Full visual report with charts, sidebar, glossary Humans (managers, developers) Default
JSON Raw audit data (findings, scores, metadata) Automation, dashboards, CI/CD Default
Demo HTML Anonymized report (paths, code, solutions redacted) Prospects, public demos --demo
SARIF Findings in OASIS standard format IDEs, GitHub Code Scanning, GitLab SAST --sarif
SBOM CycloneDX 1.5 dependency inventory Compliance, supply chain security --sbom
# Generate HTML + JSON + anonymized demo report
./staticcodeaudit-linux-x64 /path/to/project --demo

# Generate HTML + JSON + SARIF
./staticcodeaudit-linux-x64 /path/to/project --sarif

# Generate HTML + JSON + SBOM
./staticcodeaudit-linux-x64 /path/to/project --sbom

# Generate all formats
./staticcodeaudit-linux-x64 /path/to/project --sarif --sbom --demo

Demo mode: The --demo flag generates an additional anonymized report (*-demo.html) alongside the full report. File paths are replaced with path_to/{filename}:##, source code is hidden, and solutions are truncated. Ideal for sharing with prospects or publishing as a sample.


Project Management

Each audited project is identified by a unique UUID generated automatically during the first audit (--init). This system allows you to:

  • Distinguish projects with the same directory name but at different locations
  • Isolate project-specific fixtures
  • Track audit history per project
  • Detect if a project has been moved

First project audit

# The script automatically detects the project and generates a UUID
./staticcodeaudit-linux-x64 /path/to/my-project --init

# Output:
# 🔍 Auto-detecting project "my-project"...
#    Type: Python + JavaScript
#    Paths: app/, src/
# 🔑 Unique identifier generated: a1b2c3d4
# ✅ Configuration generated: /path/to/my-project/audit.config.json
# ✅ Project registered: projects/a1b2c3d4/

List registered projects

./staticcodeaudit-linux-x64 --list-projects

# Output:
# 📁 Registered projects (2):
#
# [a1b2c3d4] MyProject
#   Path: /path/to/my-project
#   Description: Example web application
#   Last audit: 2026-02-25 10:30
#   Audits: 15 | Fixtures: 12 specific
#
# [b5c6d7e8] My-API
#   Path: /Users/dev/my-api
#   Last audit: Never
#   Audits: 0 | Fixtures: generic only

Detailed project information

./staticcodeaudit-linux-x64 /path/to/project --project-info

# Output:
# 📋 Project Information
#
# ID:          a1b2c3d4-e5f6-7890-abcd-ef1234567890
# Name:        MyProject
# Description: Example web application
# Version:     3.0
# Path:        /path/to/my-project
#
# Registered:  2026-01-15 14:30
# Last audit:  2026-02-25 10:30
# Total audits: 15
#
# Fixtures:
#   Specific: 12 (projects/a1b2c3d4/fixtures/)
#   Generic:  42 (include_generic: true)
#   Total:    54

Add project-specific fixtures

# Create the fixtures directory for a project
./staticcodeaudit-linux-x64 /path/to/project --init-fixtures

# Add files to:
# Audit/projects/{uuid}/fixtures/vulnerable/  # Files that should be detected
# Audit/projects/{uuid}/fixtures/clean/       # Files without vulnerabilities

Moved project detection

If a project is moved to a different location, the script automatically detects the change and updates the registered path:

⚠️  Warning: path has changed for this project
    Previous: /Users/dev/old-path/my-project
    New:      /Users/dev/new-path/my-project

    ✅ project.json updated

Unregister a project

./staticcodeaudit-linux-x64 /path/to/project --unregister

# The project.json file is deleted
# Fixtures are preserved (if present)
# The project's audit.config.json is not modified

Configuration

The audit.config.json file is automatically generated at the target project root during the first audit. It is based on the templates/audit.config.template.json template.

brand

Branding configuration. Allows customizing the tool identity per project (e.g., for client-facing reports).

Field Type Description
tool_name string Tool name displayed in the report (default: StaticCodeAudit)
company_name string Company name displayed in the report footer (default: CodeFixture)
prefix string Prefix for report and data files (default: SCA)
logo string|null Path to a client logo (SVG, PNG, JPG). Replaces favicon and header icon in the report. Relative to project root or absolute.
{
  "brand": {
    "tool_name": "Acme Code Audit",
    "company_name": "Acme Corp",
    "prefix": "ACM",
    "logo": "assets/acme-logo.svg"
  }
}

Note: If brand.logo points to a missing file or an unsupported format, the tool falls back to its default icons with a console warning. The logo is embedded as base64 in the HTML report to keep it standalone.

project

Project information displayed in the report.

Field Type Description
id string Unique UUID generated automatically at --init (do not modify)
name string Project name (auto-detected from directory name)
version string Project version (auto-detected from package.json or pyproject.toml)
description string Optional description
{
  "project": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "My Project",
    "version": "1.0.0",
    "description": "FastAPI + Vue.js web application"
  }
}

Important: The UUID (id) is generated automatically and should not be modified manually. It is used to uniquely identify the project and associate project-specific fixtures.

languages

REQUIRED — Declares the project languages. Controls which audit rules are executed.

Value Extensions scanned Rules enabled
python .py SQL Injection, secrets, debug mode, eval, deserialization, crypto, exceptions, etc.
javascript .js, .jsx, .ts, .tsx, .mjs XSS, console.log, insecure RNG, client-side auth, DOM, inline style, etc.
html .html, .htm, .xhtml, .shtml, .vue, .svelte, .ejs, .hbs, .njk, .jinja, .jinja2, .twig, .liquid, .mustache, .phtml, .erb, .jsp, .asp, .aspx, .cshtml Inline SVG, ARIA, buttons without label, etc.
java .java SQL Injection, deserialization, XXE, crypto, CSRF, CORS, command injection, etc.
csharp .cs SQL Injection, deserialization, XXE, crypto, LDAP, command injection, etc.
php .php SQL Injection, command injection, file inclusion, XSS, deserialization, etc.
yaml .yml, .yaml CI/CD security (GitHub Actions, GitLab CI)
{
  "languages": ["python", "javascript", "html", "java", "csharp", "php", "yaml"]
}

Important: If a language is not declared, the corresponding rules will not run. TypeScript (.ts, .tsx) and JSX (.jsx, .mjs) files are treated as JavaScript — the same rules apply. No separate "typescript" language is needed.

paths

Scan path configuration.

Field Type Description
include array REQUIRED - Directories to scan (relative to project root)
exclude array Patterns to ignore — supports 3 formats: glob (**/node_modules/**), directory name (alembic/), extension (*.min.js)

Note: paths.include is used for all declared languages. File type filtering is done by extension. During --init, the configuration is auto-generated with detected paths.

{
  "paths": {
    "include": [
      "app/",
      "src/",
      "UI-FRONT/js/",
      "UI-ADMIN/js/"
    ],
    "exclude": [
      "**/node_modules/**",
      "**/vendor/**",
      "**/__pycache__/**",
      "*.min.js",
      "*.bundle.js"
    ]
  }
}

reports

Report generation configuration.

Field Type Description
output_dir string HTML report output directory
history_dir string JSON data storage directory (history)
max_history integer Maximum number of reports kept
language string HTML report language (fr, en, es, de, default: fr)
{
  "reports": {
    "output_dir": "docs/audit-reports",
    "history_dir": "docs/audit-reports/audit-datas",
    "max_history": 10,
    "language": "en"
  }
}

categories

Audit category activation and weights.

Field Type Description
enabled boolean Enable/disable the category
weight integer Category weight (1-5) — used for finding prioritization
{
  "categories": {
    "security": { "enabled": true, "weight": 3 },
    "architecture": { "enabled": true, "weight": 2 },
    "ui": { "enabled": true, "weight": 1 },
    "ux": { "enabled": true, "weight": 1 },
    "maintenance": { "enabled": true, "weight": 1 }
  }
}

Recommended weights:

  • security: 3 (critical)
  • architecture: 2 (important)
  • ui, ux, maintenance: 1 (standard)

rules

Detection rules configuration.

Field Type Description
disabled array List of rules to ignore
custom_patterns object Custom paths for specific rules
{
  "rules": {
    "disabled": [
      "TODO/FIXME",
      "console.log"
    ],
    "custom_patterns": {
      "admin_routes": "app/features/admin",
      "services": "app/features",
      "templates": "src/templates"
    }
  }
}

Available rules (324 rules):

Security:

  • SQL Injection: Non-parameterized SQL queries (f-string, concatenation)
  • XSS: innerHTML without sanitization
  • Hardcoded Secrets: Hardcoded passwords and API keys
  • Debug mode: debug=True in production
  • HTTP without TLS: Insecure HTTP URLs
  • Eval/Exec: Dangerous use of eval()/exec()
  • Secret logged: Secrets exposed in logs
  • Deserialization: Insecure pickle.loads(), yaml.load()
  • Weak crypto: hashlib.md5, hashlib.sha1
  • OS Injection: subprocess with shell=True
  • Verbose exception: Exposed stack traces
  • Catch-all: except: without specific type
  • Insecure RNG: Math.random() for sensitive values
  • Client-side auth: Access control via localStorage
  • Homebrew auth: Custom password comparison instead of proper hashing
  • Predictable session: Weak RNG for tokens/sessions
  • Dynamic import: Unrestricted dynamic module loading
  • Race condition: TOCTOU file access patterns
  • JNDI Injection: JNDI lookup with user input (Log4Shell, Java)
  • XPath Injection: XPath queries with string concatenation (Java, C#, PHP, Python)
  • SSTI: Server-Side Template Injection (Jinja2, Pug, EJS, Nunjucks)
  • CSV Injection: CSV output without formula character sanitization
  • SMTP Injection: Email headers with unsanitized user input (Python, PHP)
  • ReDoS: Regular expressions with nested quantifiers
  • Format String: User input in format strings (.format(), String.format())
  • Missing HSTS: HTTP framework without Strict-Transport-Security
  • Missing X-Content-Type-Options: Response without nosniff header
  • Missing Referrer-Policy: Framework without Referrer-Policy header
  • Missing Frame Protection: Without frame-ancestors CSP or X-Frame-Options
  • PostMessage No Origin Check: addEventListener("message") without origin validation
  • Missing SRI: External scripts without Subresource Integrity
  • SVG Scriptable Content: SVG elements with embedded scripts or event handlers
  • GraphQL Introspection: Introspection enabled in production
  • GraphQL No Depth Limit: GraphQL without query depth/cost limiter
  • WebSocket No TLS: ws:// connections instead of wss://
  • File Upload No Validation: Upload without MIME type or extension check
  • Weak Password Policy: Minimum password length under 8 characters
  • Default Credentials: Hardcoded admin/root/test passwords
  • Security Questions: Knowledge-based authentication patterns
  • JWT None Algorithm: JWT accepting "none" algorithm
  • JWT Hardcoded Secret: JWT signing key hardcoded in source
  • Insufficient Key Size: RSA key under 2048 bits
  • Log Injection: Unsanitized user input in log messages (CRLF)

Architecture:

  • File too long: Files exceeding the line threshold
  • N+1 Query: Database queries inside a loop

UI:

  • Inline style: Direct .style manipulation
  • createElement: Manual DOM element creation
  • Inline SVG: SVG directly in HTML
  • Event listeners: Listeners without cleanup
  • DOM in loop: DOM manipulation inside a loop

UX:

  • Untranslated toast: Hardcoded text in toasts
  • Ephemeral toast: Error toast without persistence
  • console.log: Residual debug logs
  • ARIA: Buttons without aria-label

Maintenance:

  • TODO/FIXME: TODO, FIXME, HACK, XXX comments
  • Deprecated API: Usage of deprecated stdlib functions

GDPR:

  • PII logged: Personal data in log statements (5 languages)
  • Missing data retention: No data lifecycle management

Dockerfile:

  • Root user: Container running as root
  • Unpinned base: FROM without version tag
  • COPY all: COPY . . exposing sensitive files

Java (18 rules):

  • SQL Injection, deserialization, XXE, command injection, Spring CSRF/CORS, weak crypto/RNG, SSL bypass, open redirect, SpEL injection, verbose exception, secret logged

C# (17 rules):

  • SQL Injection, deserialization, XXE, command injection, weak crypto/RNG, SSL bypass, XSS raw HTML, CORS, open redirect, verbose exception, secret logged, LDAP injection, request validation disabled

PHP (22 rules):

  • SQL Injection, command injection, eval, deserialization, file inclusion, XXE, XSS echo/Blade, weak crypto/RNG, open redirect, extract, type juggling, mass assignment, verbose exception, secret logged

CI/CD (18 rules):

  • pull_request_target_checkout, GHA expression injection, excessive/missing permissions, unguarded comment trigger, unpinned action version, GitLab unsafe variables, workflow not in CODEOWNERS
  • gha_secret_in_log, gha_deprecated_commands, gha_artifact_poisoning, gha_self_hosted_runner
  • ci_curl_pipe_bash, ci_insecure_download, hardcoded_secret_cicd, docker_latest_tag
  • gitlab_allow_failure_security, gitlab_script_secrets_echo

Frontend XSS (4 rules):

  • React dangerous innerHTML setter, Angular DomSanitizer bypass, Vue v-html, Svelte @html

ORM/SQL Injection (12 rules):

  • Django raw, SQLAlchemy text, JPA native, MyBatis, Dapper, PHP whereRaw/wpdb/Doctrine, Sequelize, Mongoose NoSQL, Prisma, TypeORM

MFA Detection (5 rules):

  • Missing MFA in Python, Java, C#, JavaScript, PHP

SSRF (5 rules):

  • Server-Side Request Forgery in Python (requests/urllib/httpx), Java (URL), C# (HttpClient), PHP (file_get_contents/curl), JavaScript (fetch/axios)

Path Traversal (4 rules):

  • Path traversal in Python (open/Path), Java (File/Paths), C# (File.ReadAllText/Path.Combine), JavaScript (fs.readFile)

Framework Security (7 rules):

  • Django: @csrf_exempt, DEBUG=True, hardcoded SECRET_KEY
  • Flask: debug=True, hardcoded secret_key
  • Express: missing Helmet, permissive CORS

Cookie & LDAP (3 rules):

  • Insecure cookie (missing HttpOnly/Secure) in Python, Java, C#, JavaScript, PHP
  • LDAP injection in Python, Java

ISO 27001 A.8 Coverage (6 rules):

  • Insecure local storage (tokens/secrets in localStorage)
  • Missing CSP header (Flask, Django, Express without Content-Security-Policy)
  • Hardcoded internal IP (RFC 1918 private addresses)
  • Exposed test endpoint (unprotected /test, /debug routes)
  • Destructive without backup (DROP/TRUNCATE outside migrations)
  • Local time usage (datetime.now() without timezone)

tests

Unit test configuration (optional).

Field Type Description
enabled boolean Enable test execution
tests_dir string Tests directory
command string Execution command ({tests_dir} will be replaced)
{
  "tests": {
    "enabled": true,
    "tests_dir": "tests/",
  }
}

fixtures

Fixture configuration for rule validation (--self-test mode).

Field Type Description
include_generic boolean If true, also includes generic fixtures as fallback
parallel boolean Enable parallel fixture execution
parallel_workers integer Number of parallel workers
fixture_timeout integer Timeout per fixture (seconds)
{
  "fixtures": {
    "include_generic": true,
    "parallel": true,
    "parallel_workers": 4,
    "fixture_timeout": 30
  }
}

Fixture organization:

Fixtures are organized by project UUID:

Audit/
├── projects/
│   └── {uuid}/                     # Project directory (first 8 characters)
│       └── fixtures/               # Project-specific fixtures
│           ├── vulnerable/         # Files that should be detected
│           └── clean/              # Files without vulnerabilities
│
    └── generic/                    # Generic fixtures (fallback)
        ├── vulnerable/
        └── clean/

Loading priority: 1. Project-specific fixtures (projects/{uuid}/fixtures/)

Create fixture directories for a project:

./staticcodeaudit-linux-x64 /path/to/project --init-fixtures

thresholds

Thresholds for health score and CI/CD integration.

Field Type Description
max_high integer Maximum tolerated HIGH vulnerabilities (0 = none)
max_medium integer Maximum tolerated MEDIUM vulnerabilities
min_health integer Minimum required health score (0-100)
health_good integer Threshold for a "good" score (green)
health_warning integer Threshold for a "warning" score (orange)
{
  "thresholds": {
    "max_high": 0,
    "max_medium": 10,
    "min_health": 80,
    "health_good": 90,
    "health_warning": 70
  }
}

Exit codes:

  • 0: Audit passed, thresholds met
  • 1: Thresholds exceeded (HIGH vulnerabilities or insufficient score)
  • 2: Fixture validation error (--self-test mode)

sla

SLA configuration by severity (optional).

Field Type Description
enabled boolean Enable SLA section in report (default: false)
rules object SLA rules per severity level
{
  "sla": {
    "enabled": true,
    "rules": {
      "CRITICAL": { "delay": "4h", "escalation": "CTO" },
      "HIGH": { "delay": "24h", "escalation": "Tech Lead" },
      "MEDIUM": { "delay": "1 sprint", "escalation": "Team Lead" },
      "LOW": { "delay": "Backlog", "escalation": "Developer" }
    }
  }
}

retention

Report retention configuration (optional). Controls automatic cleanup of old reports.

Field Type Description
mode string|null Cleanup mode: "count", "days", "both", or null (default: null = no cleanup)
max_count integer Maximum number of reports to keep (default: 10, used in count or both mode)
max_days integer Maximum age in days (default: 90, used in days or both mode)
{
  "retention": {
    "mode": "both",
    "max_count": 10,
    "max_days": 90
  }
}

Modes:

  • "count": Keep only the N most recent reports (max_count)
  • "days": Delete reports older than N days (max_days)
  • "both": Apply both rules (report must satisfy both to be kept)
  • null: No automatic cleanup (default)

Safety: At least one report is always preserved. Reports are deleted in HTML+JSON pairs. Use --retention-dry-run to preview which files would be deleted without actually removing them.

Note: The existing reports.max_history setting controls chart display limits only — it does not delete files. Use retention for actual file cleanup.


Audit Categories

Category Description Example Rules
SECURITY Security vulnerabilities XSS, SQL Injection, secrets, deserialization, weak crypto, RNG, client-side auth
ARCHITECTURE Architecture violations Files too long, N+1 queries
UI Interface issues Accessibility (ARIA), inline SVG, inline styles
UX User experience Untranslated toasts, non-persistent errors
MAINTENANCE Code maintainability TODO/FIXME, console.log, dead code, deprecated APIs
CICD CI/CD pipeline security 18 rules: GHA injection, unpinned actions, secrets in logs, curl|bash, hardcoded credentials, docker :latest, GitLab allow_failure on SAST
DEPENDENCIES Dependency vulnerabilities CVE scanning, unpinned versions, non-compliant licenses

Reports

Reports are generated in <project>/docs/audit-reports/:

docs/audit-reports/
  SCA-REPORT-2026-02-22-15-30.html    # Interactive HTML report
  audit-datas/
    SCA-DATA-2026-02-22-15-30.json    # JSON data (history)

Each report is a standalone HTML file — all CSS, JavaScript, charts, and favicons are embedded inline (no external dependencies). Open it in any browser, share it, or archive it.

The HTML report includes:

  • Project information (name, version, description, UUID, path)
  • Audit parameters: languages, scanned extensions per language, include/exclude paths, categories
  • Global health score (logarithmic, security-weighted, LOC-normalized) with visual indicator
  • Breakdown by severity (CRITICAL, HIGH, MEDIUM, LOW, INFO)
  • Breakdown by category
  • Detailed findings list with source code
  • Git committer attribution per finding (when --git-blame is enabled)
  • Comparison with previous audit (new/resolved)
  • Heatmap of most problematic files
  • Fixture validation with detailed results

CI/CD Integration

# GitHub Actions
- name: Run Audit
  run: |
# GitLab CI
audit:
  script:
  allow_failure: false

The script returns a non-zero exit code if:

  • HIGH vulnerabilities are detected (--fail-on-high or max_high: 0)
  • The health score is below the threshold (min_health)

Internationalization (i18n)

The audit tool supports four languages: French (fr), English (en), Spanish (es) and German (de).

Two independent configurations:

Configuration Description Default
Script language Console messages (Security Scan..., Report generated...) en
Report language HTML content (titles, labels, captions) en

Script language (CLI)

The language of console messages and debug logs is configured via the --script-lang option:

# Messages in English (default)
./staticcodeaudit-linux-x64 /path/to/project

# Messages in French
./staticcodeaudit-linux-x64 /path/to/project --script-lang=fr

# Messages in Spanish
./staticcodeaudit-linux-x64 /path/to/project --script-lang=es

# Messages in German
./staticcodeaudit-linux-x64 /path/to/project --script-lang=de

Report language (audit.config.json)

The language of the generated HTML report is configured in the project's audit.config.json file:

{
  "reports": {
    "output_dir": "docs/audit-reports",
    "history_dir": "docs/audit-reports/audit-datas",
    "max_history": 10,
    "language": "es"
  }
}

Supported values: fr (French), en (English), es (Spanish), de (German)

The report displays a language badge in the header (e.g., 🇫🇷 Francais, 🇬🇧 English, 🇪🇸 Espanol, 🇩🇪 Deutsch).

Translation files

Translation files are stored in the locales/ directory of the audit tool:

Audit/
  locales/
    script/
      fr.json    # Console messages in French
      en.json    # Console messages in English
      es.json    # Console messages in Spanish
      de.json    # Console messages in German
    report/
      fr.json    # HTML report in French
      en.json    # HTML report in English
      es.json    # HTML report in Spanish
      de.json    # HTML report in German

Fallback: If an unsupported language is specified, the script automatically falls back to English (en).

Combination examples

# Script EN + Report EN (default)
./staticcodeaudit-linux-x64 /path/to/project

# Script FR + Report EN
./staticcodeaudit-linux-x64 /path/to/project --script-lang=fr

# Script EN + Report FR (set "language": "fr" in audit.config.json)
./staticcodeaudit-linux-x64 /path/to/project

# Script FR + Report FR
./staticcodeaudit-linux-x64 /path/to/project --script-lang=fr
# (with audit.config.json containing "language": "fr")

Custom Rules

Two types of custom rules: builtin (contributed to SCA) and client (specific to a project).

The fastest way to create a rule for your project:

./staticcodeaudit-linux-x64 . --create-rule        # Create or edit a custom rule
./staticcodeaudit-linux-x64 . --custom-rules-match # Check coverage (rules ↔ fixtures)

The interactive wizard guides you through 7 steps: 1. Name, language, category, severity — with duplicate check (name + pattern) 2. Pattern to detect (text or regex) + what neutralizes it (optional) 3. Risk description — EN required, FR/ES/DE optional 4. Solution — EN required, FR/ES/DE optional 5. Benefit — optional 6. Code example before/after (fix_before + fix_after) — optional 7. Preview → validation → write to custom-rules/{lang}/{cat}/{rule_id}.sca

If a rule with the same name already exists, the wizard proposes to edit it (pre-filled with current values).

Builtin Rules — Manual

Adding a new builtin rule requires changes in 6 locations. Follow this guide step by step.

Overview

Step File(s) Action
1 sca/rules/builtin/{lang}/{cat}/ Create .sca rule file
2 locales/report/{fr,en,es,de}.json Add rule translations (all 4 languages)

Step 1: Detection Logic

Complete pattern:

# In _audit_security() (or other _audit_*() method)
py_files = self._find_files(self._py_exts, self._py_paths)  # or self._js_exts, self._html_exts

for filepath in py_files:
    for line_num, line in self._read_file(filepath):
        if re.search(r'your_detection_pattern', line):
            r = self._rule("your_rule_key")
            self._add_finding(
                "SECURITY",           # category: SECURITY, ARCH, UI, UX, MAINTENANCE
                r["name"],            # localized rule name
                filepath,             # file path
                line_num,             # line number
                line,                 # code snippet
                "HIGH",               # severity: CRITICAL, HIGH, MEDIUM, LOW, INFO
                r["risk"],            # localized risk description
                r["solution"],        # localized solution
                r["benefit"],         # localized benefit
                confidence=90,        # 0-100, how likely this is a real issue
                rule_key="your_rule_key"
            )

Note: When --git-blame is enabled, each Finding object is enriched with a committer field (string) containing the name of the last person who modified the line, resolved via git blame. This field is None by default.

File path helpers:

  • self._find_files(self._py_exts, self._py_paths) — Python files (.py)
  • self._find_files(self._js_exts, self._js_paths) — JavaScript/TypeScript files (.js, .jsx, .ts, .tsx, .mjs)
  • self._find_files(self._html_exts, self._html_paths) — HTML/template files (.html, .htm, .xhtml, .vue, .svelte, .ejs, .hbs, .njk, .jinja2, .twig, .liquid, etc.)
  • self._find_files(self._java_exts, self._java_paths) — Java files (.java)
  • self._find_files(self._csharp_exts, self._csharp_paths) — C# files (.cs)
  • self._find_files(self._php_exts, self._php_paths) — PHP files (.php)
  • self._find_files(self._yaml_exts, self._yaml_paths) — YAML files (.yml, .yaml)

Note: _find_files() automatically excludes files matching paths.exclude patterns (glob, directory name, extension). No manual filtering needed.

Step 2: Translations (4 languages)

Add the rule key in all 4 files under "rules":

locales/report/fr.json:

"your_rule_key": {
  "name": "Nom de la règle",
  "risk": "Description du risque en français.",
  "solution": "Comment corriger le problème.",
  "benefit": "Bénéfice après correction (ex: CWE-XXX)."
}

locales/report/en.json:

"your_rule_key": {
  "name": "Rule Name",
  "risk": "Risk description in English.",
  "solution": "How to fix the issue.",
  "benefit": "Benefit after fix (e.g., CWE-XXX)."
}

Repeat for es.json (Spanish) and de.json (German) with the same structure.

Step 3: Fixtures

# VULNERABLE: Description of the vulnerability
# Expected: Should trigger your_rule_key detection (HIGH severity)

def vulnerable_function():
    # Minimal code that triggers the detection
    dangerous_call(user_input)
# CLEAN: Description of the safe pattern
# Expected: Should NOT trigger your_rule_key detection

def safe_function():
    # Correct implementation
    safe_call(sanitized_input)

Naming conventions:

  • Vulnerable: use the rule key as filename (e.g., sql_injection_fstring.py)
  • Clean: use a descriptive safe name (e.g., sql_parameterized.py)
  • Extension matches the language (.py, .js, .html)

Step 4: Register Fixtures

VULNERABLE_FIXTURES = {
    # ...existing entries...
    "your_rule_key": ("your_rule_key.py", "app/target_path.py", "Rule Name"),
}

CLEAN_FIXTURES = {
    # ...existing entries...
    "safe_alternative": ("safe_alternative.py", "app/target_path.py", "Rule Name"),
}

Tuple format: (fixture_filename, target_path_in_temp_project, rule_name_for_docs)

The target_path must match a directory in paths.include config (e.g., app/, UI-FRONT/).

Step 5: Tests

class TestYourRule:
    """Tests for your_rule_key detection."""

    def test_detects_vulnerability(self, temp_project, audit_runner):
        """Must detect the vulnerable pattern."""
        fixture = VULNERABLE_FIXTURES["your_rule_key"]
        use_vulnerable_fixture(temp_project, fixture[0], fixture[1])

        audit_runner._audit_security()  # or _audit_architecture(), etc.

        findings = get_findings_by_rule_key(audit_runner, "your_rule_key")
        assert len(findings) >= 1

    def test_ignores_safe_code(self, temp_project, audit_runner):
        """Must NOT detect the safe pattern."""
        fixture = CLEAN_FIXTURES["safe_alternative"]
        use_clean_fixture(temp_project, fixture[0], fixture[1])

        audit_runner._audit_security()

        findings = get_findings_by_rule_key(audit_runner, "your_rule_key")
        assert len(findings) == 0

Run your tests: ```bash

Run only your new tests

Run all tests (check for regressions)

Checklist

Before submitting, verify:

  • [ ] Rule defined in all 4 locale files (fr.json, en.json, es.json, de.json)
  • [ ] Vulnerable fixture created and triggers detection
  • [ ] Clean fixture created and does NOT trigger detection
  • [ ] Test class with at least 2 tests (detect + ignore)

License

MIT