| description | Basic CodeQL query examples and patterns for Go programs |
|---|
Minimal Go query examples in VS Code; variables, constraints, and results for concrete bug patterns. Demonstrates query structure and common Go programming pattern detection.
import: Include standard Go library (import go)from: Declare typed variables to range over (Method,Variable,Write,Field)where: Constrain relationships among variables with predicatesselect: Emit results; message can concatenate strings and AST entities
import go
from <Type1> var1, <Type2> var2, ...
where <conditions and relationships>
select <results>, "<message with " + var1 + " references>"Methods defined on value receivers that write to a field have no effect (receiver is copied). Should use pointer receiver instead.
import go
from Method m, Variable recv, Write w, Field f
where recv = m.getReceiver() and
w.writesField(recv.getARead(), f, _) and
not recv.getType() instanceof PointerType
select w, "This update to " + f + " has no effect, because " + recv + " is not a pointer."Method.getReceiver(): Receiver variable of a methodWrite.writesField(baseRead, field, idx): Write whose LHS writes field of base expressionVariable.getARead(): Read expression of the variablePointerType: Type test to exclude pointer receivers
Function calls that return errors but the error is ignored.
import go
from CallExpr call, AssignStmt assign
where call.getType().toString().matches("%error%") and
assign.getRhs() = call and
assign.getLhs().(Ident).getName() = "_"
select call, "Error from " + call.getTarget().getName() + " is ignored"Pointer dereference without nil check.
import go
from StarExpr deref, Variable ptr
where deref.getExpr() = ptr.getARead() and
not exists(IfStmt guard, NeqExpr check |
check.getLeftOperand() = ptr.getARead() and
check.getRightOperand().(Ident).getName() = "nil" and
guard.getCondition() = check and
deref.getParent*() = guard.getThen()
)
select deref, "Potential nil pointer dereference of " + ptrGoroutines launched without context cancellation mechanism.
import go
from GoStmt goStmt, FuncLit funcLit
where goStmt.getExpr() = funcLit and
not exists(Parameter ctx |
ctx = funcLit.getParameter(0) and
ctx.getType().toString().matches("%context.Context%")
)
select goStmt, "Goroutine launched without context parameter"Type assertions without the "ok" idiom to check success.
import go
from TypeAssertExpr assert
where not exists(TupleExpr tuple, VariableName ok |
tuple = assert.getParent() and
tuple.getElement(1) = ok.getARead() and
ok.getName() = "ok"
)
select assert, "Type assertion without ok check: " + assert.toString()Files opened without corresponding defer close.
import go
from CallExpr open, VariableName file
where open.getTarget().hasQualifiedName("os", "Open") and
open.getARead() = file.getARead() and
not exists(DeferStmt defer, CallExpr close |
close.getTarget().getName() = "Close" and
close.getReceiver() = file.getARead() and
defer.getExpr() = close
)
select open, "File opened without defer close: " + fileString concatenation used to build SQL queries.
import go
from CallExpr dbCall, AddExpr concat, StringLit sqlPart
where dbCall.getTarget().hasQualifiedName("database/sql", ["Query", "Exec"]) and
dbCall.getArgument(0) = concat and
concat.getAnOperand() = sqlPart and
sqlPart.getValue().matches("%SELECT%")
select concat, "SQL query built by concatenation, potential injection risk"User input used directly in command execution.
import go
from CallExpr execCall, CallExpr inputCall
where execCall.getTarget().hasQualifiedName("os/exec", "Command") and
inputCall.getTarget().hasQualifiedName("os", "Getenv") and
DataFlow::localFlow(DataFlow::exprNode(inputCall), DataFlow::exprNode(execCall.getAnArgument()))
select execCall, "Environment variable flows to command execution"Range over map in goroutine without copying the value (race condition risk).
import go
from GoStmt goStmt, RangeStmt rangeStmt, Variable mapVar
where goStmt.getExpr().(FuncLit).getBody().getAStmt*() = rangeStmt and
rangeStmt.getDomain() = mapVar.getARead() and
mapVar.getType().toString().matches("map[%")
select rangeStmt, "Range over map " + mapVar + " in goroutine may cause race condition"Slice access without bounds checking.
import go
from IndexExpr index, Variable slice
where index.getBase() = slice.getARead() and
slice.getType().toString().matches("[]%") and
not exists(IfStmt guard, CallExpr lenCall, RelationalComparisonExpr compare |
lenCall.getTarget().getName() = "len" and
lenCall.getArgument(0) = slice.getARead() and
compare.getAnOperand() = index.getIndex() and
compare.getAnOperand() = lenCall and
guard.getCondition() = compare
)
select index, "Slice access without bounds check: " + slice// Find all calls to specific function
from CallExpr call
where call.getTarget().hasQualifiedName("fmt", "Printf")
select call
// Find method calls on specific type
from CallExpr call, SelectorExpr sel
where call.getCallee() = sel and
sel.getBase().getType().toString() = "MyType" and
sel.getSelector().getName() = "MyMethod"
select call// Find if statements with specific conditions
from IfStmt ifStmt, EqlExpr eq
where ifStmt.getCondition() = eq and
eq.getRightOperand().(Ident).getName() = "nil"
select ifStmt
// Find loops with range
from RangeStmt rangeStmt
where rangeStmt.getKey().getName() != "_" and
rangeStmt.getValue().getName() != "_"
select rangeStmt// Find specific imports
from ImportSpec spec
where spec.getPath().getValue() = "unsafe"
select spec, "Unsafe package imported"
// Find package-level variables
from Variable v
where v.isPackageLevel() and
v.getName().matches("debug%")
select v- Open VS Code with CodeQL extension
- Paste query after
import go - Click "Run Query" or use Ctrl+Shift+P → "CodeQL: Run Query"
- Click results to jump to code locations
// Add guards to exclude false positives
where not exists(CommentGroup comment |
comment.getText().matches("%TODO%") and
comment.getLocation().getStartLine() < result.getLocation().getStartLine()
)
// Restrict to specific files or packages
where result.getFile().getBaseName().matches("%.go") and
not result.getFile().getAbsolutePath().matches("%test%")- Add guards to exclude writes to temporary copies
- Restrict to exported methods/types
- Focus on specific packages with
hasQualifiedName - Convert to path queries to show data flow
- Add more specific type checking
These examples provide practical starting points for finding real Go programming issues and can be customized for specific codebases and requirements.