rules:
- id: roteiro.rust.shell-out-to-sh
languages: [rust]
severity: ERROR
message: >-
Spawning a shell (`sh -c`) turns every argument into shell syntax, so any
interpolated value becomes code. Invoke the program directly and pass
arguments as separate `.arg()` calls.
metadata:
category: security
cwe: "CWE-78: OS Command Injection"
confidence: HIGH
patterns:
- pattern-either:
- pattern: std::process::Command::new("sh")
- pattern: Command::new("sh")
- pattern: std::process::Command::new("bash")
- pattern: Command::new("bash")
- id: roteiro.rust.unwrap-on-env-var
languages: [rust]
severity: WARNING
message: >-
`std::env::var(...).unwrap()` panics when the variable is unset, which
turns a missing configuration value into a crash with no diagnostic.
Handle the `Err` and say what was missing.
metadata:
category: correctness
confidence: MEDIUM
patterns:
- pattern-either:
- pattern: std::env::var($NAME).unwrap()
- pattern: env::var($NAME).unwrap()
- id: roteiro.python.subprocess-shell-true
languages: [python]
severity: ERROR
message: >-
`shell=True` runs the command through a shell, so any interpolated value
becomes shell syntax. Pass a list of arguments and leave `shell` at its
default.
metadata:
category: security
cwe: "CWE-78: OS Command Injection"
confidence: HIGH
patterns:
- pattern-either:
- pattern: subprocess.run(..., shell=True, ...)
- pattern: subprocess.call(..., shell=True, ...)
- pattern: subprocess.Popen(..., shell=True, ...)
- pattern: subprocess.check_output(..., shell=True, ...)
- id: roteiro.python.eval-of-input
languages: [python]
severity: ERROR
message: >-
`eval`/`exec` on a value that came from outside the program executes
whatever the caller supplied. Parse the value instead.
metadata:
category: security
cwe: "CWE-95: Eval Injection"
confidence: HIGH
patterns:
- pattern-either:
- pattern: eval(...)
- pattern: exec(...)
- id: roteiro.java.runtime-exec
languages: [java]
severity: ERROR
message: >-
`Runtime.getRuntime().exec(...)` with a composed string is command
injection when any part of that string came from outside the program. Use
`ProcessBuilder` with a list of arguments.
metadata:
category: security
cwe: "CWE-78: OS Command Injection"
confidence: MEDIUM
patterns:
- pattern: Runtime.getRuntime().exec(...)
- id: roteiro.java.concatenated-sql
languages: [java]
severity: ERROR
message: >-
A SQL string built by concatenation is SQL injection as soon as any part
of it is caller-supplied. Use a `PreparedStatement` with bound parameters.
metadata:
category: security
cwe: "CWE-89: SQL Injection"
confidence: MEDIUM
patterns:
- pattern-either:
- pattern: $STMT.executeQuery("..." + ...)
- pattern: $STMT.executeUpdate("..." + ...)
- pattern: $STMT.execute("..." + ...)
- id: roteiro.js.child-process-exec
languages: [javascript, typescript]
severity: ERROR
message: >-
`child_process.exec` runs its argument through a shell. Use `execFile` or
`spawn` with an argument array so no value can become shell syntax.
metadata:
category: security
cwe: "CWE-78: OS Command Injection"
confidence: HIGH
pattern-either:
- pattern: require("child_process").exec(...)
- pattern: child_process.exec(...)
- patterns:
- pattern: $CP.exec(...)
- pattern-inside: |
$CP = require("child_process")
...
- patterns:
- pattern: $F(...)
- pattern-inside: |
import { exec as $F } from "child_process"
...
- id: roteiro.js.eval-call
languages: [javascript, typescript]
severity: ERROR
message: >-
`eval` executes whatever string it is given. If any part of that string
came from outside the program, so did the code.
metadata:
category: security
cwe: "CWE-95: Eval Injection"
confidence: HIGH
patterns:
- pattern: eval(...)
- id: roteiro.sql.grant-all-privileges
languages: [generic]
paths:
include:
- "*.sql"
severity: WARNING
message: >-
Granting ALL PRIVILEGES hands over every current and future permission on
the object, including ones that did not exist when the grant was written.
Grant the specific rights the role needs.
metadata:
category: security
cwe: "CWE-732: Incorrect Permission Assignment"
confidence: HIGH
engine-note: >-
Matched by semgrep's generic (token) engine, not a SQL parser.
patterns:
- pattern: GRANT ALL PRIVILEGES ON ... TO ...
- id: roteiro.sql.select-star-into-outfile
languages: [generic]
paths:
include:
- "*.sql"
severity: ERROR
message: >-
`INTO OUTFILE` writes query results to a file on the database server's
filesystem. It is almost never what an application migration wants, and it
is a common exfiltration primitive.
metadata:
category: security
cwe: "CWE-552: Files Accessible to External Parties"
confidence: HIGH
engine-note: >-
Matched by semgrep's generic (token) engine, not a SQL parser.
patterns:
- pattern: INTO OUTFILE ...