CodeQL-Informed Audit Heuristics
Purpose
Provide a language-specific reference of dangerous sinks, sources, and patterns that
security auditors should prioritize during manual code review. These heuristics are derived
from the CodeQL Community Packs — the same query suites used by GitHub Advanced Security
to find real vulnerabilities at scale.
Use this skill as a checklist companion during manual audit. It tells you what to look for
in each language. The actual manual reasoning is done by eresus-manual-security-audit.
Java / Kotlin
Command Injection
Runtime.exec(), ProcessBuilder.command()
Runtime.getRuntime().exec(userInput)
JNDI Injection
InitialContext.lookup(userInput)
Context.lookup() with attacker-controlled LDAP/RMI URLs
Expression Language Injection
SpELExpressionParser.parseExpression(userInput)
OGNL.getValue(userInput)
MVEL.eval(userInput)
SQL Injection
Statement.execute(query) with string concatenation
Statement.executeQuery("SELECT ... " + userInput)
- JPA
createNativeQuery() with interpolated strings
- MyBatis
${} (raw) vs #{} (parameterized)
Deserialization
ObjectInputStream.readObject()
XStream.fromXML()
Kryo.readObject()
- Jackson
@JsonTypeInfo with MINIMAL_CLASS / CLASS
XXE
DocumentBuilderFactory without setFeature(XMLConstants.FEATURE_SECURE_PROCESSING)
SAXParserFactory without disabling external entities
XMLInputFactory without disabling DTDs
Unsafe Reflection
Class.forName(userInput).newInstance()
Method.invoke() with user-controlled method names
Path Traversal
new File(basePath + userInput) without canonicalization
Paths.get(userInput) without restricting to base directory
Python
Command Injection
os.system(userInput)
subprocess.Popen(userInput, shell=True)
subprocess.call(userInput, shell=True)
os.popen(userInput)
Code Injection
eval(userInput)
exec(userInput)
compile(userInput, ...)
Deserialization
pickle.loads(userInput)
pickle.load(untrustedFile)
yaml.load(userInput) — safe: yaml.safe_load()
shelve.open(userInput)
marshal.loads(userInput)
Template Injection (SSTI)
jinja2.Template(userInput).render()
jinja2.Environment(autoescape=False)
mako.template.Template(userInput)
SQL Injection
cursor.execute("SELECT ... " + userInput)
- Django
extra(), raw(), RawSQL() with user input
- SQLAlchemy
text(userInput)
Path Traversal
open(basePath + userInput)
- Flask
send_file(userInput)
- FastAPI
FileResponse(userInput)
os.path.join(base, userInput) without os.path.realpath() check
SSRF
requests.get(userInput)
urllib.request.urlopen(userInput)
JavaScript / TypeScript
Code Injection
eval(userInput)
Function(userInput)()
setTimeout(userInput, ms) (string form)
setInterval(userInput, ms) (string form)
vm.runInNewContext(userInput)
vm.runInThisContext(userInput)
Command Injection
child_process.exec(userInput)
child_process.execSync(userInput)
child_process.exec(`cmd ${userInput}`)
XSS / DOM Injection
element.innerHTML = userInput
element.outerHTML = userInput
document.write(userInput)
insertAdjacentHTML('beforeend', userInput)
- React:
dangerouslySetInnerHTML={{ __html: userInput }}
- Vue:
v-html="userInput"
- Angular:
bypassSecurityTrustHtml(userInput)
Prototype Pollution
lodash.merge({}, userInput)
lodash.set(obj, userInput.key, userInput.value)
Object.assign(target, JSON.parse(userInput))
- Deep clone/merge with
__proto__, constructor.prototype keys
NoSQL Injection
- MongoDB
$where: userInput
collection.find({ field: userInput }) when userInput is { $gt: "" }
collection.find(JSON.parse(userInput))
Path Traversal
path.join(base, userInput) without path.resolve() + prefix check
fs.readFile(userInput)
- Express
res.sendFile(userInput)
postMessage
window.addEventListener('message', handler) without event.origin check
SSRF
fetch(userInput), axios.get(userInput), got(userInput)
- URL construction:
fetch(\/api/${userInput}`)`
Go
Command Injection
exec.Command(userInput)
exec.CommandContext(ctx, userInput)
os.StartProcess(userInput, ...)
SQL Injection
db.Query("SELECT ... " + userInput)
db.Exec("INSERT INTO ... " + userInput)
fmt.Sprintf("SELECT ... %s", userInput) passed to db.Query()
Template Injection
text/template (NO auto-escaping) vs html/template (auto-escapes)
template.HTML(userInput) explicitly marking user input as safe
Path Traversal
filepath.Join(base, userInput) — does NOT prevent ../
os.Open(userInput) without validation
- Need:
filepath.Rel() or prefix check after filepath.Clean()
TLS Misconfiguration
InsecureSkipVerify: true
MinVersion: tls.VersionTLS10
SSRF
http.Get(userInput)
http.NewRequest("GET", userInput, nil)
Ruby
Command Injection
system(userInput)
`#{userInput}` (backticks)
IO.popen(userInput)
Open3.capture3(userInput)
Kernel.exec(userInput)
Deserialization
Marshal.load(userInput) — RCE via universal gadget chain
YAML.load(userInput) — RCE via Psych → safe: YAML.safe_load()
Oj.load(userInput, mode: :object) — safe: mode: :strict
Ox.load(userInput, mode: :object) — safe: mode: :generic
SQL Injection
ActiveRecord: .where("column = '#{userInput}'")
ActiveRecord: .order(userInput)
ActiveRecord: .pluck(userInput)
ActiveRecord: .select(userInput)
Dynamic Dispatch
object.send(userInput) — calls any method
object.public_send(userInput) — calls any public method
Template Injection
ERB.new(userInput).result(binding)
Slim::Template.new { userInput }
Path Traversal
File.read(params[:file])
send_file(params[:path])
C# / .NET
Deserialization
BinaryFormatter.Deserialize(stream) — banned in .NET 9+
SoapFormatter.Deserialize(stream)
NetDataContractSerializer.ReadObject(reader)
ObjectStateFormatter.Deserialize(input)
LosFormatter.Deserialize(input)
XmlSerializer with polymorphic [XmlInclude] types
Command Injection
Process.Start(userInput)
Process.Start("cmd.exe", "/c " + userInput)
SQL Injection
new SqlCommand("SELECT ... " + userInput)
cmd.CommandText = "SELECT ... " + userInput
- EF Core
FromSqlRaw("SELECT ... " + userInput)
XSS
HtmlString(userInput) — bypasses Razor encoding
Html.Raw(userInput)
Unsafe Reflection
Type.GetType(userInput)
Activator.CreateInstance(Type.GetType(userInput))
Path Traversal
Path.Combine(basePath, userInput) without canonicalization
File.ReadAllText(userInput)
C / C++
Buffer Overflow
strcpy(dst, src) — safe: strncpy(), strlcpy()
strcat(dst, src) — safe: strncat()
sprintf(buf, fmt, ...) — safe: snprintf()
gets(buf) — never safe, removed in C11
Format String
printf(userInput) — safe: printf("%s", userInput)
fprintf(fp, userInput)
syslog(priority, userInput)
Integer Overflow
malloc(count * size) without overflow check
size_t arithmetic wrapping to zero
- Signed/unsigned comparison mismatches
Memory Safety
- Use-after-free: accessing memory after
free()
- Double-free: calling
free() twice on same pointer
- Null dereference: missing NULL checks after
malloc()
Command Injection
system(userInput)
popen(userInput, "r")
execvp(userInput, args)
Audit Priority Rules
When performing depth-first manual review, prioritize:
- Security-sensitive sinks over style issues
- Exploitable paths over theoretical vulnerabilities
- Business logic flaws over pattern-match findings
- Trust boundary violations over defense-in-depth gaps
Tooling Constraints
Use ONLY these tools for code inspection:
view_file — read source code
grep_search — find pattern matches
Do NOT use terminal commands like grep, rg, cat, sed, or any shell-based tools.
1---2name: eresus-codeql-heuristics3description: Language-specific vulnerability hotspot reference for manual code audit. Trigger when the user asks to: "what sinks should I look for in Java?", "Python security hotspots", "dangerous functions in Go", "JavaScript injection patterns", or when starting a manual audit of a specific language and needing a sink/source checklist.4---5
6# CodeQL-Informed Audit Heuristics
7
8## Purpose
9
10Provide a language-specific reference of dangerous sinks, sources, and patterns that
11security auditors should prioritize during manual code review. These heuristics are derived
12from the CodeQL Community Packs — the same query suites used by GitHub Advanced Security
13to find real vulnerabilities at scale.
14
15Use this skill as a **checklist companion** during manual audit. It tells you **what to look for**
16in each language. The actual manual reasoning is done by `eresus-manual-security-audit`.
17
18---
19
20## Java / Kotlin
21
22### Command Injection
23- `Runtime.exec()`, `ProcessBuilder.command()`
24- `Runtime.getRuntime().exec(userInput)`
25
26### JNDI Injection
27- `InitialContext.lookup(userInput)`
28- `Context.lookup()` with attacker-controlled LDAP/RMI URLs
29
30### Expression Language Injection
31- `SpELExpressionParser.parseExpression(userInput)`
32- `OGNL.getValue(userInput)`
33- `MVEL.eval(userInput)`
34
35### SQL Injection
36- `Statement.execute(query)` with string concatenation
37- `Statement.executeQuery("SELECT ... " + userInput)`
38- JPA `createNativeQuery()` with interpolated strings
39- MyBatis `${}` (raw) vs `#{}` (parameterized)
40
41### Deserialization
42- `ObjectInputStream.readObject()`
43- `XStream.fromXML()`
44- `Kryo.readObject()`
45- Jackson `@JsonTypeInfo` with `MINIMAL_CLASS` / `CLASS`
46
47### XXE
48- `DocumentBuilderFactory` without `setFeature(XMLConstants.FEATURE_SECURE_PROCESSING)`
49- `SAXParserFactory` without disabling external entities
50- `XMLInputFactory` without disabling DTDs
51
52### Unsafe Reflection
53- `Class.forName(userInput).newInstance()`
54- `Method.invoke()` with user-controlled method names
55
56### Path Traversal
57- `new File(basePath + userInput)` without canonicalization
58- `Paths.get(userInput)` without restricting to base directory
59
60---
61
62## Python
63
64### Command Injection
65- `os.system(userInput)`
66- `subprocess.Popen(userInput, shell=True)`
67- `subprocess.call(userInput, shell=True)`
68- `os.popen(userInput)`
69
70### Code Injection
71- `eval(userInput)`
72- `exec(userInput)`
73- `compile(userInput, ...)`
74
75### Deserialization
76- `pickle.loads(userInput)`
77- `pickle.load(untrustedFile)`
78- `yaml.load(userInput)` — safe: `yaml.safe_load()`
79- `shelve.open(userInput)`
80- `marshal.loads(userInput)`
81
82### Template Injection (SSTI)
83- `jinja2.Template(userInput).render()`
84- `jinja2.Environment(autoescape=False)`
85- `mako.template.Template(userInput)`
86
87### SQL Injection
88- `cursor.execute("SELECT ... " + userInput)`
89- Django `extra()`, `raw()`, `RawSQL()` with user input
90- SQLAlchemy `text(userInput)`
91
92### Path Traversal
93- `open(basePath + userInput)`
94- Flask `send_file(userInput)`
95- FastAPI `FileResponse(userInput)`
96- `os.path.join(base, userInput)` without `os.path.realpath()` check
97
98### SSRF
99- `requests.get(userInput)`
100- `urllib.request.urlopen(userInput)`
101
102---
103
104## JavaScript / TypeScript
105
106### Code Injection
107- `eval(userInput)`
108- `Function(userInput)()`
109- `setTimeout(userInput, ms)` (string form)
110- `setInterval(userInput, ms)` (string form)
111- `vm.runInNewContext(userInput)`
112- `vm.runInThisContext(userInput)`
113
114### Command Injection
115- `child_process.exec(userInput)`
116- `child_process.execSync(userInput)`
117- `` child_process.exec(`cmd ${userInput}`) ``
118
119### XSS / DOM Injection
120- `element.innerHTML = userInput`
121- `element.outerHTML = userInput`
122- `document.write(userInput)`
123- `insertAdjacentHTML('beforeend', userInput)`
124- React: `dangerouslySetInnerHTML={{ __html: userInput }}`
125- Vue: `v-html="userInput"`
126- Angular: `bypassSecurityTrustHtml(userInput)`
127
128### Prototype Pollution
129- `lodash.merge({}, userInput)`
130- `lodash.set(obj, userInput.key, userInput.value)`
131- `Object.assign(target, JSON.parse(userInput))`
132- Deep clone/merge with `__proto__`, `constructor.prototype` keys
133
134### NoSQL Injection
135- MongoDB `$where: userInput`
136- `collection.find({ field: userInput })` when userInput is `{ $gt: "" }`
137- `collection.find(JSON.parse(userInput))`
138
139### Path Traversal
140- `path.join(base, userInput)` without `path.resolve()` + prefix check
141- `fs.readFile(userInput)`
142- Express `res.sendFile(userInput)`
143
144### postMessage
145- `window.addEventListener('message', handler)` without `event.origin` check
146
147### SSRF
148- `fetch(userInput)`, `axios.get(userInput)`, `got(userInput)`
149- URL construction: `fetch(\`/api/${userInput}\`)`
150
151---
152
153## Go
154
155### Command Injection
156- `exec.Command(userInput)`
157- `exec.CommandContext(ctx, userInput)`
158- `os.StartProcess(userInput, ...)`
159
160### SQL Injection
161- `db.Query("SELECT ... " + userInput)`
162- `db.Exec("INSERT INTO ... " + userInput)`
163- `fmt.Sprintf("SELECT ... %s", userInput)` passed to `db.Query()`
164
165### Template Injection
166- `text/template` (NO auto-escaping) vs `html/template` (auto-escapes)
167- `template.HTML(userInput)` explicitly marking user input as safe
168
169### Path Traversal
170- `filepath.Join(base, userInput)` — does NOT prevent `../`
171- `os.Open(userInput)` without validation
172- Need: `filepath.Rel()` or prefix check after `filepath.Clean()`
173
174### TLS Misconfiguration
175- `InsecureSkipVerify: true`
176- `MinVersion: tls.VersionTLS10`
177
178### SSRF
179- `http.Get(userInput)`
180- `http.NewRequest("GET", userInput, nil)`
181
182---
183
184## Ruby
185
186### Command Injection
187- `system(userInput)`
188- `` `#{userInput}` `` (backticks)
189- `IO.popen(userInput)`
190- `Open3.capture3(userInput)`
191- `Kernel.exec(userInput)`
192
193### Deserialization
194- `Marshal.load(userInput)` — RCE via universal gadget chain
195- `YAML.load(userInput)` — RCE via Psych → safe: `YAML.safe_load()`
196- `Oj.load(userInput, mode: :object)` — safe: `mode: :strict`
197- `Ox.load(userInput, mode: :object)` — safe: `mode: :generic`
198
199### SQL Injection
200- `ActiveRecord: .where("column = '#{userInput}'")`
201- `ActiveRecord: .order(userInput)`
202- `ActiveRecord: .pluck(userInput)`
203- `ActiveRecord: .select(userInput)`
204
205### Dynamic Dispatch
206- `object.send(userInput)` — calls any method
207- `object.public_send(userInput)` — calls any public method
208
209### Template Injection
210- `ERB.new(userInput).result(binding)`
211- `Slim::Template.new { userInput }`
212
213### Path Traversal
214- `File.read(params[:file])`
215- `send_file(params[:path])`
216
217---
218
219## C# / .NET
220
221### Deserialization
222- `BinaryFormatter.Deserialize(stream)` — **banned in .NET 9+**
223- `SoapFormatter.Deserialize(stream)`
224- `NetDataContractSerializer.ReadObject(reader)`
225- `ObjectStateFormatter.Deserialize(input)`
226- `LosFormatter.Deserialize(input)`
227- `XmlSerializer` with polymorphic `[XmlInclude]` types
228
229### Command Injection
230- `Process.Start(userInput)`
231- `Process.Start("cmd.exe", "/c " + userInput)`
232
233### SQL Injection
234- `new SqlCommand("SELECT ... " + userInput)`
235- `cmd.CommandText = "SELECT ... " + userInput`
236- EF Core `FromSqlRaw("SELECT ... " + userInput)`
237
238### XSS
239- `HtmlString(userInput)` — bypasses Razor encoding
240- `Html.Raw(userInput)`
241
242### Unsafe Reflection
243- `Type.GetType(userInput)`
244- `Activator.CreateInstance(Type.GetType(userInput))`
245
246### Path Traversal
247- `Path.Combine(basePath, userInput)` without canonicalization
248- `File.ReadAllText(userInput)`
249
250---
251
252## C / C++
253
254### Buffer Overflow
255- `strcpy(dst, src)` — safe: `strncpy()`, `strlcpy()`
256- `strcat(dst, src)` — safe: `strncat()`
257- `sprintf(buf, fmt, ...)` — safe: `snprintf()`
258- `gets(buf)` — **never safe**, removed in C11
259
260### Format String
261- `printf(userInput)` — safe: `printf("%s", userInput)`
262- `fprintf(fp, userInput)`
263- `syslog(priority, userInput)`
264
265### Integer Overflow
266- `malloc(count * size)` without overflow check
267- `size_t` arithmetic wrapping to zero
268- Signed/unsigned comparison mismatches
269
270### Memory Safety
271- Use-after-free: accessing memory after `free()`
272- Double-free: calling `free()` twice on same pointer
273- Null dereference: missing NULL checks after `malloc()`
274
275### Command Injection
276- `system(userInput)`
277- `popen(userInput, "r")`
278- `execvp(userInput, args)`
279
280---
281
282## Audit Priority Rules
283
284When performing depth-first manual review, prioritize:
285
2861. **Security-sensitive sinks** over style issues
2872. **Exploitable paths** over theoretical vulnerabilities
2883. **Business logic flaws** over pattern-match findings
2894. **Trust boundary violations** over defense-in-depth gaps
290
291---
292
293## Tooling Constraints
294
295Use ONLY these tools for code inspection:
296- `view_file` — read source code
297- `grep_search` — find pattern matches
298
299Do NOT use terminal commands like `grep`, `rg`, `cat`, `sed`, or any shell-based tools.