SentinelAI ships with three built-in scanners and supports user-defined custom rules. This document covers every scanner, its rule catalog, and how to extend the system.
| Scanner | ID | Description |
|---|---|---|
| Code Scanner | code |
Static analysis for injection, XSS, and unsafe APIs |
| Secrets Scanner | secrets |
Detects hardcoded credentials, keys, and tokens |
| Dependency Scanner | dependencies |
Finds known vulnerabilities in project dependencies |
The code scanner performs pattern-based and AST-based static analysis to find common security vulnerabilities.
| Rule ID | Severity | Description | CWE |
|---|---|---|---|
SAI-SQL-001 |
High | SQL query with string concatenation | CWE-89 |
SAI-SQL-002 |
High | SQL query with f-string interpolation | CWE-89 |
SAI-SQL-003 |
High | SQL query with %-format string | CWE-89 |
SAI-SQL-004 |
High | SQL query with .format() call |
CWE-89 |
SAI-SQL-005 |
Critical | executescript() with user-controlled input |
CWE-89 |
SAI-SQL-006 |
High | Dynamic table or column names from user input | CWE-89 |
SAI-SQL-007 |
Medium | ORDER BY clause with user-controlled input | CWE-89 |
| Rule ID | Severity | Description | CWE |
|---|---|---|---|
SAI-XSS-001 |
Medium | Reflected XSS via string interpolation in HTML | CWE-79 |
SAI-XSS-002 |
Medium | Stored XSS via raw template rendering | CWE-79 |
SAI-XSS-003 |
High | DOM-based XSS via innerHTML pattern | CWE-79 |
SAI-XSS-004 |
Medium | Unescaped user input in HTML attributes | CWE-79 |
SAI-XSS-005 |
High | javascript: protocol in href attribute |
CWE-79 |
SAI-XSS-006 |
Low | User input in CSS style attribute | CWE-79 |
SAI-XSS-007 |
High | User input in event handler attribute | CWE-79 |
SAI-XSS-008 |
Critical | Server-side template injection (user-controlled template) | CWE-1336 |
| Rule ID | Severity | Description | CWE |
|---|---|---|---|
SAI-CMD-001 |
Critical | os.system() with user-controlled input |
CWE-78 |
SAI-CMD-002 |
Critical | subprocess with shell=True and user input |
CWE-78 |
SAI-CMD-003 |
High | os.popen() with user-controlled input |
CWE-78 |
SAI-CMD-004 |
Critical | subprocess.Popen with shell=True and user input |
CWE-78 |
SAI-CMD-005 |
Critical | eval() with user-controlled input |
CWE-95 |
SAI-CMD-006 |
Critical | exec() with user-controlled input |
CWE-95 |
SAI-CMD-007 |
High | __import__() with user-controlled input |
CWE-502 |
SAI-CMD-008 |
Critical | subprocess.call() with shell=True and user input |
CWE-78 |
SAI-CMD-009 |
Critical | os.system() with string concatenation |
CWE-78 |
The secrets scanner uses pattern matching, entropy analysis, and known-format detection to find hardcoded credentials.
| Rule ID | Severity | Description | CWE |
|---|---|---|---|
SAI-SEC-001 |
Critical | Hardcoded API key | CWE-798 |
SAI-SEC-002 |
Critical | Hardcoded database password | CWE-798 |
SAI-SEC-003 |
Critical | Hardcoded AWS credentials | CWE-798 |
SAI-SEC-004 |
High | Hardcoded JWT signing secret | CWE-798 |
SAI-SEC-005 |
Critical | Hardcoded OAuth / service token | CWE-798 |
SAI-SEC-006 |
Critical | Connection string with embedded password | CWE-798 |
SAI-SEC-007 |
Critical | Private key material in source code | CWE-321 |
SAI-SEC-008 |
High | Hardcoded encryption key | CWE-321 |
SAI-SEC-009 |
Medium | Secret in function default parameter | CWE-798 |
SAI-SEC-010 |
Medium | Hardcoded password in environment variable fallback | CWE-798 |
The dependency scanner reads lock files and manifest files to check for known vulnerabilities using the OSV and NVD databases.
| Ecosystem | Files |
|---|---|
| Python | requirements.txt, Pipfile.lock, poetry.lock, uv.lock |
| Node.js | package-lock.json, yarn.lock, pnpm-lock.yaml |
| Go | go.sum |
| Rust | Cargo.lock |
| Java | pom.xml, build.gradle.kts |
| Rule ID | Severity | Description |
|---|---|---|
SAI-DEP-001 |
Varies | Known vulnerability in direct dependency |
SAI-DEP-002 |
Varies | Known vulnerability in transitive dependency |
SAI-DEP-003 |
Info | Dependency has been deprecated or abandoned |
SAI-DEP-004 |
Low | Dependency version is outdated (major version gap) |
You can define custom scanning rules using YAML files placed in the custom_rules_dir directory (default: .sentinelai/rules/).
# .sentinelai/rules/no-print-statements.yaml
rules:
- id: "CUSTOM-001"
name: "No print statements"
description: "print() should not be used in production code; use logging instead."
severity: low
confidence: high
category: code_quality
languages:
- python
pattern:
type: regex
value: '^\s*print\s*\('
exclude_paths:
- "tests/**"
- "scripts/**"
message: "Replace print() with a proper logging call."
remediation: |
Use the `logging` module instead:
import logging
logger = logging.getLogger(__name__)
logger.info("your message here")For more precise detection, you can write AST-based rules:
rules:
- id: "CUSTOM-002"
name: "No requests without timeout"
description: "HTTP requests must always specify a timeout."
severity: medium
confidence: high
category: reliability
languages:
- python
pattern:
type: ast
node: Call
function: ["requests.get", "requests.post", "requests.put", "requests.delete"]
missing_keyword: "timeout"
message: "HTTP request without timeout can hang indefinitely."You can also define rules directly in sentinelai.yaml:
custom_rules:
- id: "CUSTOM-003"
pattern: "FIXME|HACK|XXX"
severity: info
message: "Code annotation found that may need attention."Disable specific rules globally:
code_scanner:
rules:
disable:
- SAI-SQL-007
- CUSTOM-003Or inline with a comment:
query = f"SELECT * FROM users ORDER BY {column}" # sentinelai: ignore SAI-SQL-007