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.
Source: EresusSecurity/appsec-skills — distributed by TomeVault.
1---2name: eresussecurity-appsec-skills-eresus-codeql-heuristics3description: CodeQL-Informed Audit Heuristics4---56# CodeQL-Informed Audit Heuristics78## Purpose910Provide a language-specific reference of dangerous sinks, sources, and patterns that11security auditors should prioritize during manual code review. These heuristics are derived12from the CodeQL Community Packs — the same query suites used by GitHub Advanced Security13to find real vulnerabilities at scale.1415Use 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`.1718---1920## Java / Kotlin2122### Command Injection23- `Runtime.exec()`, `ProcessBuilder.command()`24- `Runtime.getRuntime().exec(userInput)`2526### JNDI Injection27- `InitialContext.lookup(userInput)`28- `Context.lookup()` with attacker-controlled LDAP/RMI URLs2930### Expression Language Injection31- `SpELExpressionParser.parseExpression(userInput)`32- `OGNL.getValue(userInput)`33- `MVEL.eval(userInput)`3435### SQL Injection36- `Statement.execute(query)` with string concatenation37- `Statement.executeQuery("SELECT ... " + userInput)`38- JPA `createNativeQuery()` with interpolated strings39- MyBatis `${}` (raw) vs `#{}` (parameterized)4041### Deserialization42- `ObjectInputStream.readObject()`43- `XStream.fromXML()`44- `Kryo.readObject()`45- Jackson `@JsonTypeInfo` with `MINIMAL_CLASS` / `CLASS`4647### XXE48- `DocumentBuilderFactory` without `setFeature(XMLConstants.FEATURE_SECURE_PROCESSING)`49- `SAXParserFactory` without disabling external entities50- `XMLInputFactory` without disabling DTDs5152### Unsafe Reflection53- `Class.forName(userInput).newInstance()`54- `Method.invoke()` with user-controlled method names5556### Path Traversal57- `new File(basePath + userInput)` without canonicalization58- `Paths.get(userInput)` without restricting to base directory5960---6162## Python6364### Command Injection65- `os.system(userInput)`66- `subprocess.Popen(userInput, shell=True)`67- `subprocess.call(userInput, shell=True)`68- `os.popen(userInput)`6970### Code Injection71- `eval(userInput)`72- `exec(userInput)`73- `compile(userInput, ...)`7475### Deserialization76- `pickle.loads(userInput)`77- `pickle.load(untrustedFile)`78- `yaml.load(userInput)` — safe: `yaml.safe_load()`79- `shelve.open(userInput)`80- `marshal.loads(userInput)`8182### Template Injection (SSTI)83- `jinja2.Template(userInput).render()`84- `jinja2.Environment(autoescape=False)`85- `mako.template.Template(userInput)`8687### SQL Injection88- `cursor.execute("SELECT ... " + userInput)`89- Django `extra()`, `raw()`, `RawSQL()` with user input90- SQLAlchemy `text(userInput)`9192### Path Traversal93- `open(basePath + userInput)`94- Flask `send_file(userInput)`95- FastAPI `FileResponse(userInput)`96- `os.path.join(base, userInput)` without `os.path.realpath()` check9798### SSRF99- `requests.get(userInput)`100- `urllib.request.urlopen(userInput)`101102---103104## JavaScript / TypeScript105106### Code Injection107- `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)`113114### Command Injection115- `child_process.exec(userInput)`116- `child_process.execSync(userInput)`117- `` child_process.exec(`cmd ${userInput}`) ``118119### XSS / DOM Injection120- `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)`127128### Prototype Pollution129- `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` keys133134### NoSQL Injection135- MongoDB `$where: userInput`136- `collection.find({ field: userInput })` when userInput is `{ $gt: "" }`137- `collection.find(JSON.parse(userInput))`138139### Path Traversal140- `path.join(base, userInput)` without `path.resolve()` + prefix check141- `fs.readFile(userInput)`142- Express `res.sendFile(userInput)`143144### postMessage145- `window.addEventListener('message', handler)` without `event.origin` check146147### SSRF148- `fetch(userInput)`, `axios.get(userInput)`, `got(userInput)`149- URL construction: `fetch(\`/api/${userInput}\`)`150151---152153## Go154155### Command Injection156- `exec.Command(userInput)`157- `exec.CommandContext(ctx, userInput)`158- `os.StartProcess(userInput, ...)`159160### SQL Injection161- `db.Query("SELECT ... " + userInput)`162- `db.Exec("INSERT INTO ... " + userInput)`163- `fmt.Sprintf("SELECT ... %s", userInput)` passed to `db.Query()`164165### Template Injection166- `text/template` (NO auto-escaping) vs `html/template` (auto-escapes)167- `template.HTML(userInput)` explicitly marking user input as safe168169### Path Traversal170- `filepath.Join(base, userInput)` — does NOT prevent `../`171- `os.Open(userInput)` without validation172- Need: `filepath.Rel()` or prefix check after `filepath.Clean()`173174### TLS Misconfiguration175- `InsecureSkipVerify: true`176- `MinVersion: tls.VersionTLS10`177178### SSRF179- `http.Get(userInput)`180- `http.NewRequest("GET", userInput, nil)`181182---183184## Ruby185186### Command Injection187- `system(userInput)`188- `` `#{userInput}` `` (backticks)189- `IO.popen(userInput)`190- `Open3.capture3(userInput)`191- `Kernel.exec(userInput)`192193### Deserialization194- `Marshal.load(userInput)` — RCE via universal gadget chain195- `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`198199### SQL Injection200- `ActiveRecord: .where("column = '#{userInput}'")`201- `ActiveRecord: .order(userInput)`202- `ActiveRecord: .pluck(userInput)`203- `ActiveRecord: .select(userInput)`204205### Dynamic Dispatch206- `object.send(userInput)` — calls any method207- `object.public_send(userInput)` — calls any public method208209### Template Injection210- `ERB.new(userInput).result(binding)`211- `Slim::Template.new { userInput }`212213### Path Traversal214- `File.read(params[:file])`215- `send_file(params[:path])`216217---218219## C# / .NET220221### Deserialization222- `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]` types228229### Command Injection230- `Process.Start(userInput)`231- `Process.Start("cmd.exe", "/c " + userInput)`232233### SQL Injection234- `new SqlCommand("SELECT ... " + userInput)`235- `cmd.CommandText = "SELECT ... " + userInput`236- EF Core `FromSqlRaw("SELECT ... " + userInput)`237238### XSS239- `HtmlString(userInput)` — bypasses Razor encoding240- `Html.Raw(userInput)`241242### Unsafe Reflection243- `Type.GetType(userInput)`244- `Activator.CreateInstance(Type.GetType(userInput))`245246### Path Traversal247- `Path.Combine(basePath, userInput)` without canonicalization248- `File.ReadAllText(userInput)`249250---251252## C / C++253254### Buffer Overflow255- `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 C11259260### Format String261- `printf(userInput)` — safe: `printf("%s", userInput)`262- `fprintf(fp, userInput)`263- `syslog(priority, userInput)`264265### Integer Overflow266- `malloc(count * size)` without overflow check267- `size_t` arithmetic wrapping to zero268- Signed/unsigned comparison mismatches269270### Memory Safety271- Use-after-free: accessing memory after `free()`272- Double-free: calling `free()` twice on same pointer273- Null dereference: missing NULL checks after `malloc()`274275### Command Injection276- `system(userInput)`277- `popen(userInput, "r")`278- `execvp(userInput, args)`279280---281282## Audit Priority Rules283284When performing depth-first manual review, prioritize:2852861. **Security-sensitive sinks** over style issues2872. **Exploitable paths** over theoretical vulnerabilities2883. **Business logic flaws** over pattern-match findings2894. **Trust boundary violations** over defense-in-depth gaps290291---292293## Tooling Constraints294295Use ONLY these tools for code inspection:296- `view_file` — read source code297- `grep_search` — find pattern matches298299Do NOT use terminal commands like `grep`, `rg`, `cat`, `sed`, or any shell-based tools.300301---302> Source: [EresusSecurity/appsec-skills](https://github.com/EresusSecurity/appsec-skills) — distributed by [TomeVault](https://tomevault.io).303<!-- tomevault:4.0:skill_md:2026-05-22 -->