Skip to main content

DSL .sca Reference

Level Advanced
Reading time ⏱ 20 min
words 1410
Topics custom-rulesdsl

DSL .sca Reference — StaticCodeAudit by CodeFixture

This document describes the complete syntax of .sca rule files. Each file defines a self-contained detection rule.

1. Rule structure

A .sca file contains a single rule. Minimal structure:

rule mon_id_de_regle
  language  python
  severity  HIGH

  match
    pattern  mon_pattern_regex
  end

  risk
    en: English risk description
    fr: Description du risque en français
  end
  solution
    en: English fix
    fr: Correction en français
  end
end
The rule_id must be lowercase with underscores only: [a-z0-9_]+

↑ Back to top

2. Rule keywords

KeywordValuesRequiredDescription
languagepython, javascript, java, csharp, php, html, yaml, dockerfilerequiredLanguage of the analyzed code
severityCRITICAL, HIGH, MEDIUM, LOW, INFOrequiredFinding severity
categorysecurity, arch, ui, ux, maintenance, cicdoptionalCategory (default: security)
confidence0 to 100optionalConfidence in % (default: 80)

↑ Back to top

3. match block (pattern detection)

The match block defines the patterns to detect in the code. Repeatable (multiple blocks = OR).

3.1 match block keywords

KeywordTypeDescription
patternRegexRegular expression to search for
textPlain textText escaped automatically. * = wildcard (anything)
withRegexThe context must also contain this pattern
with-textPlain textLike with but escaped automatically
pattern-notRegexThe context must not contain this pattern
text-notPlain textLike pattern-not but escaped
scopeValueSearch scope (see below)

3.2 Scopes

Scopepattern behaviorpattern-not behavior
lineChecked line by lineChecked on the same line
context-NChecked over windows of N linesChecked over the entire N-line block
fileChecked over the entire fileChecked over the entire file

3.3 text vs pattern

text — for all developers. The tool automatically escapes special characters. The * means "anything".

match
  text  .execute(
  with-text  f"*"
  scope  context-4
end

pattern — for regex experts. The pattern is used as-is.

match
  pattern  \.execute\s*\(.*f["']
  scope  context-4
end

Both examples above detect the same code.

↑ Back to top

4. requires block (file conditions)

The requires block defines conditions on the file. If used alone (without match), the finding is at file level (line 1). If combined with match, it serves as a pre-filter.

KeywordLogicDescriptionExample
hasALL must matchThe file content must contain this patternhas @app\.route
not_hasNONE may matchThe file content must NOT contain this patternnot_has logging
min_lines≥ NThe file must have at least N linesmin_lines 500
path_containsAT LEAST ONE must matchThe file path must contain this segmentpath_contains vendor/
not_path_has_fileNONE may existThe file's directory must NOT contain this filenot_path_has_file LICENSE
has, not_has, path_contains and not_path_has_file are repeatable (multiple lines = multiple conditions).

Examples

# Flask file without logging
requires
  has      @app\.route
  not_has  import\s+logging
end

# File too long
requires
  min_lines  500
end

# Vendor code without LICENSE
requires
  path_contains  vendor/
  not_path_has_file  LICENSE
  not_path_has_file  LICENSE.md
end

↑ Back to top

5. Taint analysis (source → sink)

Taint analysis traces the flow of data from sources (user inputs) to sinks (dangerous functions), unless a sanitizer intervenes.

KeywordSyntaxDescription
sourcesource <regex> kind=<type>Origin of untrusted data
sinksink <regex>Dangerous function receiving the data
sanitizersanitizer <regex>Function that neutralizes the data

Source types (kind=): http, stdin, cli, env, file, network

rule taint_sqli
  language  python
  severity  HIGH

  source  request\.args\.get\(   kind=http
  source  request\.form\[        kind=http
  source  input\s*\(             kind=stdin

  sink    \.execute\s*\(
  sink    \.executemany\s*\(

  sanitizer  \bint\s*\(
  sanitizer  psycopg2\.sql\.SQL
end

↑ Back to top

6. i18n blocks (risk, solution, message)

The risk, solution, benefit and message blocks support translation in 4 languages:

risk
  en: User input in SQL query allows injection.
  fr: Entrée utilisateur dans la requête SQL permet l'injection.
  es: Entrada de usuario en consulta SQL permite inyección.
  de: Benutzereingabe in SQL-Abfrage ermöglicht Injection.
end
Supported language codes: en, fr, es, de. The report uses the language configured via --lang.

↑ Back to top

7. metadata block (CWE, CVE, OWASP, ISO, WCAG)

metadata
  cwe       CWE-89
  cwe       CWE-90
  cve       CVE-2021-44228
  owasp     A03:2021
  iso27001  A.8.28 A.8.25
  asvs      5.3.4
  wcag      1.1.1
end
KeyFormatDescription
cweCWE-NNN (multi)Common Weakness Enumeration. Multiple values via repeated lines or space-separated tokens.
cveCVE-YYYY-NNNN (multi)Specific CVE the rule was created for. Renders as a clickable link to NVD.
owaspANN:YYYYOWASP Top 10
iso27001A.N.NN (multi)ISO/IEC 27001:2022 Annex A
asvsN.N.N (multi)OWASP ASVS
wcagN.N.N (multi)W3C WCAG 2.1 success criterion (used by accessibility rules instead of CWE).

All multi-valued keys (cwe, cve, iso27001, asvs, wcag) accept either several tokens on a single line (cwe  CWE-89 CWE-90) or repeated lines — both are accumulated.

The metadata classification is propagated to all exports: HTML (clickable links), JSON (finding.compliance object), and SARIF (rule.properties.tags).

↑ Back to top

8. Execution modes

The mode is inferred automatically from the blocks present:

Blocks presentInferred mode
match (pattern/text)regex
requires alone (has/not_has/min_lines)file_contains
match + requiresregex with file pre-filter
source + sinktaint
source + sink + matchregex+taint
hookpython_hook (advanced custom rules)
It is not necessary to specify mode explicitly — automatic inference is recommended.

↑ Back to top

9. Complete examples

9.1 Simple detection (plain text)

rule console_log_residual
  language  javascript
  severity  LOW
  category  ux

  match
    text  console.log(
  end

  risk
    en: console.log() calls left in production code.
    fr: Appels console.log() laissés en production.
  end
  solution
    en: Remove console.log() or use a logging system.
    fr: Supprimer les console.log() ou utiliser un système de logging.
  end
end

9.2 Pattern with exclusion (context)

rule insecure_cookie
  language  python
  severity  MEDIUM

  match
    pattern  \.set_cookie\s*\(
    pattern-not  (?:httponly\s*=\s*True|secure\s*=\s*True)
    scope    context-4
  end

  risk
    en: Cookie without HttpOnly/Secure flags.
    fr: Cookie sans flags HttpOnly/Secure.
  end
  solution
    en: Add httponly=True, secure=True, samesite="Lax".
    fr: Ajouter httponly=True, secure=True, samesite="Lax".
  end
end

9.3 File condition only

rule file_too_long
  language  python
  severity  LOW
  category  arch

  requires
    min_lines  500
  end

  risk
    en: Very long files are difficult to maintain.
    fr: Les fichiers très longs sont difficiles à maintenir.
  end
  solution
    en: Split into smaller, focused modules.
    fr: Découper en modules plus petits et focalisés.
  end
end

9.4 Combo match + requires

rule missing_auth_decorator
  language  python
  severity  MEDIUM

  match
    pattern  @app\.route\s*\(\s*[\"'](?:/admin|/api/delete)
    pattern-not  @login_required
    scope    context-4
  end

  risk
    en: Admin route without authentication decorator.
    fr: Route admin sans décorateur d'authentification.
  end
  solution
    en: Add @login_required on all sensitive routes.
    fr: Ajouter @login_required sur toutes les routes sensibles.
  end
end

9.5 Taint analysis (SQL injection)

rule taint_sqli
  language  python
  severity  HIGH
  confidence  90

  source  request\.args\.get\(  kind=http
  source  request\.form\[      kind=http
  sink    \.execute\s*\(
  sink    \.executemany\s*\(
  sanitizer  psycopg2\.sql\.SQL
  sanitizer  \bint\s*\(

  risk
    en: Tainted data flows into SQL query without parameterization.
    fr: Données non fiables atteignent une requête SQL sans paramétrage.
  end
  solution
    en: Use parameterized queries with placeholders (%s, ?).
    fr: Utilisez des requêtes paramétrées avec placeholders (%s, ?).
  end

  metadata
    cwe    CWE-89
    owasp  A03:2021
  end
end

9.6 Vendor governance check

rule unreviewed_vendor_code
  language  python
  severity  LOW
  category  maintenance

  requires
    path_contains       vendor/
    path_contains       third-party/
    not_path_has_file   LICENSE
    not_path_has_file   NOTICE
  end

  risk
    en: Vendor code without LICENSE file.
    fr: Code tiers sans fichier LICENSE.
  end
  solution
    en: Add LICENSE file to vendor directories.
    fr: Ajouter un fichier LICENSE aux répertoires vendor.
  end
end

↑ Back to top

10. Glossary

TermDefinition
DSLDomain-Specific Language — a language dedicated to defining audit rules
FindingAn issue detected by a rule (vulnerability, architectural flaw, etc.)
PatternRegular expression or plain text searched for in the code
ScopeSearch scope: line, block of N lines, or entire file
SourceUntrusted data input (HTTP request, keyboard input, etc.)
SinkDangerous function where untrusted data must not arrive without validation
SanitizerFunction that neutralizes dangerous data (escaping, validation, conversion)
TaintMarking of data as "tainted" to track its propagation through the code
CWECommon Weakness Enumeration — catalogue of software weaknesses
OWASPOpen Web Application Security Project — Top 10 web security risks
ASVSApplication Security Verification Standard — security verification levels
ISO 27001International standard for information security management
SASTStatic Application Security Testing — security analysis without executing the code

↑ Back to top


StaticCodeAudit — CodeFixture | DSL Documentation v1.0