Compare commits

..

12 Commits

Author SHA1 Message Date
yoff
709566ecb1 Python: visit function parameter and return annotations in new CFG
The new (shared-CFG-based) Python control flow graph in
`semmle.python.controlflow.internal.Cfg` previously did not emit CFG
nodes for parameter type annotations (`def f(x: T): ...`) or for the
return type annotation (`-> T`). The legacy CFG emitted both, and a
small number of framework models rely on this: `LocalSources.qll`'s
`annotatedInstance` walks the parameter annotation expression by way
of its CFG node to track that a parameter receives an instance of the
annotated class.

After the dataflow flip to the new CFG/SSA this regression manifested
as lost flows in any test exercising annotation-based parameter
tracking: FastAPI `Depends()` receivers, Pydantic request bodies,
Starlette `WebSocket`, the call-graph type-annotation test, and so on.
Extend `FunctionDefExpr` to visit each annotation as a child of the
function-def expression, in CPython evaluation order: positional
parameter annotations, `*args` annotation, keyword-only parameter
annotations, `**kwargs` annotation, then the return annotation. (Lambda
expressions have no annotations in Python syntax, so `LambdaExpr` is
unchanged.) PEP 695 type parameters remain out of scope; they belong
to the inner annotation scope, not the enclosing CFG.

Restored test results across `framework/aiohttp`, `framework/fastapi`,
`framework/lxml`, the `CallGraph-type-annotations` test, and
`CWE-022-PathInjection`. Two FastAPI list-comprehension MISSING markers
become positive (`taint_test.py:41,55`). CPython CFG consistency
remains clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 08:10:14 +00:00
yoff
b783ed69c5 Python: model exception edges for raise-prone expressions inside try/with
The new CFG previously only emitted exception edges for explicit `raise`
and `assert` statements. As a result, code that became reachable only
via the exception path of an arbitrary expression (e.g., the body of an
`except` handler following a try-body whose `call()` could raise) was
classified as dead, breaking analyses like StackTraceExposure,
FileNotAlwaysClosed, ExceptionInfo, UseOfExit, and CatchingBaseException.

This commit adds a `mayThrow` predicate over expressions that are known
sources of implicit exceptions in Python (calls, attribute access,
subscripts, arithmetic/comparison operators, imports, await/yield/yield
from) plus `from m import *` at the statement level, and routes them
through the shared CFG's `beginAbruptCompletion(_, _, ExceptionSuccessor,
always=false)` hook.

The set of exception sources is restricted to nodes that are
syntactically inside a `try`/`with` statement in the same scope.
This mirrors Java's `ControlFlowGraph::mayThrow`, which only emits
exception edges where local handling can observe them — outside such
contexts, the edges add CFG complexity (weakening BarrierGuard
precision and breaking SSA continuity around augmented assignments and
subscript stores) without analysis benefit, since exceptions just
propagate to the function exit anyway.

Net effect on the test suite: ~100 alerts restored across the exception-
related query tests (StackTraceExposure +29, ExceptionInfo +17,
FileNotAlwaysClosed +52, UseOfExit +1, CatchingBaseException restored)
with no precision regressions. Affected `.expected` files and the
regression-guard `dead_under_no_raise.py` are updated accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 08:10:06 +00:00
yoff
5b9803e03c Python: switch dataflow library to new (shared) CFG + SSA
Flips the Python dataflow trunk from the legacy CFG (semmle/python/Flow.qll)
and legacy ESSA SSA (semmle/python/essa/*) to the new shared CFG facade
(semmle.python.controlflow.internal.Cfg) and the new SSA adapter
(semmle.python.dataflow.new.internal.SsaImpl), both introduced
additively in the preceding PRs in this stack.

This is the trunk-flip equivalent of the original draft PR #21894 (kept
around as documentation), rebased on top of the four preparatory PRs:

  P1: Remove AstNode.getAFlowNode() and rewrite callers (#21919).
  P2: Qualify Flow.qll's AST references with Py:: prefix (#21920).
  P3: Add new shared-CFG-backed control flow graph (#21921).
  P4: Add new shared-SSA-backed SSA adapter (#21923).

The Python dataflow library (semmle/python/dataflow/new/) now imports
the new CFG facade and SSA adapter. All CFG-typed predicates
(ControlFlowNode, CallNode, BasicBlock, NameNode, AttrNode, ...) are
qualified with the Cfg:: prefix; SSA references switch from
EssaVariable/EssaDefinition to SsaImpl::Definition/SourceVariable.

GuardNode is redesigned to use the new CFG's outcome-node model
(isAfterTrue / isAfterFalse) instead of the legacy ConditionBlock +
flipped indirection. Only BarrierGuard<...> is preserved as public
API.

Framework files (Bottle, FastApi, Django, Tornado, Pyramid, Stdlib,
...) are updated to take CFG nodes from the new facade.

A handful of dataflow consistency tweaks for the new CFG:
- Augmented-assignment targets are treated as both load and store.
- 'from X import *' produces uncertain SSA writes for unknown names.
- CFG nodes are canonicalised so dataflow does not see equivalent
  pre/post-order pairs as distinct nodes.

Two AST tweaks for the new CFG:
- AstNodeImpl: omit PEP 695 type-parameter names from
  FunctionDefExpr / ClassDefExpr children.
- ImportResolution: drop the legacy essa import.

Test churn (~175 files): reblessed library- and query-test .expected
files reflect slightly different CFG granularity, different toString
output, and a handful of true alert deltas in security queries.

Verification: all 367 lib + src + consistency-queries compile clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 08:04:01 +00:00
Copilot
b2ff09f70a Python: add new shared-SSA-backed SSA adapter
Preparatory refactor for the shared-CFG dataflow migration. Adds the
new Python SSA adapter additively, without changing any production
behaviour.

Library additions:

- semmle.python.dataflow.new.internal.SsaImpl — Python SSA
  implementation built on the new (shared) CFG. Mirrors the Java SSA
  adapter (java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll):
  an InputSig is defined in terms of positional (BasicBlock, int)
  variable references, and the shared
  codeql.ssa.Ssa::Make<Location, Cfg, Input> module is then
  instantiated.

  SourceVariable is the AST-level Py::Variable. Variable references
  are looked up via the new CFG facade's NameNode.defines/uses/deletes
  predicates (added in the preceding PR), which themselves are
  one-line bridges to AST-level Name.defines/uses/deletes.

  Implicit-entry definitions are inserted for non-local/global/builtin
  reads, captured variables, and (when needed) parameters.

Test additions:

- library-tests/dataflow-new-ssa/ — exercises the new SSA over a
  representative test corpus and checks expected def/use chains.

- library-tests/dataflow-new-ssa-vs-legacy/ — runs both new SSA and
  legacy ESSA over the same corpus and diffs the results, so any
  semantic divergence shows up as a test failure.

Production impact:

None. The new SSA adapter has zero callers in lib/ and src/ — the
legacy ESSA SSA (semmle/python/essa/*) remains the default. The
dataflow library is not migrated yet; that lands in a follow-up PR.

Verified by:
- All 367 lib + src + consistency-queries compile clean.
- All 641 ControlFlow + PointsTo + dataflow + essa + consistency
  library-tests pass.
- Both new dataflow-new-ssa[/vs-legacy] test packs pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 08:03:48 +00:00
Copilot
4aee0b3c87 Python: add new shared-CFG-backed control flow graph
Preparatory refactor for the shared-CFG dataflow migration. Adds the
new Python CFG library additively, without changing any production
behaviour.

Library additions:

- semmle.python.controlflow.internal.AstNodeImpl — mediates between
  the Python AST and the shared codeql.controlflow.ControlFlowGraph
  signature. Wraps Python's Stmt/Expr/Scope/Pattern and adds two
  synthetic kinds of node (BlockStmt for body slots, intermediate
  nodes for multi-operand boolean expressions).

- semmle.python.controlflow.internal.Cfg — public facade
  re-exposing the same API surface as semmle/python/Flow.qll
  (ControlFlowNode, CallNode, BasicBlock, NameNode, DefinitionNode,
  CompareNode, ...), backed by the shared CFG.

- lib/printCfgNew.ql — debug/visualisation query for the new CFG.

- consistency-queries/CfgConsistency.ql — consistency query running
  the shared CFG's standard checks against Python.

Shared library:

- shared.controlflow.ControlFlowGraph — adds two defaulted
  getWhileElse / getForeachElse predicates to AstSig so Python can
  model while-else / for-else (no behavioural change for other
  languages).

Test additions:

- ControlFlow/bindings/* — annotation-driven SSA-binding tests for
  the new CFG (annassign, compound, comprehension, decorated,
  except_handler, imports, match_pattern, parameters, simple,
  type_params, walrus_starred, with_stmt, dead_under_no_raise).

- ControlFlow/store-load/* — basic store/load coverage.

- ControlFlow/evaluation-order/NewCfg*.ql — mirrors of the existing
  OldCfg evaluation-order self-validation suite, run against the
  new CFG via NewCfgImpl.qll.

- Minor extensions to existing test_if.py / test_boolean.py +
  cosmetic .expected churn on a handful of OldCfg tests.

No dataflow, SSA, or production query is migrated yet — that lands in
follow-up PRs. The new CFG library has zero callers in lib/ and src/.

Verified by:
- All lib + src + consistency-queries compile clean (367 queries).
- All 56 ControlFlow library-tests pass.
- All 474 dataflow + PointsTo library-tests + consistency tests pass.
- syntax_error/CONSISTENCY/CfgConsistency passes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 08:03:29 +00:00
yoff
a2295e7216 Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-05 07:57:43 +00:00
Copilot
0623acc7f5 Python: qualify Flow.qll's AST references with Py:: prefix
Preparatory refactor for the shared-CFG dataflow migration. Switches
'import python' to 'import python as Py' inside Flow.qll, and qualifies
every AST-class reference (Expr, Bytes, Dict, AssignExpr, Compare,
Module, Scope, Call, Attribute, SsaVariable, AugAssign, etc.) with the
Py:: prefix.

Flow.qll's own CFG types (ControlFlowNode, BasicBlock, CallNode,
NameNode, DefinitionNode, CompareNode, ...) keep their unqualified
names — they remain the public CFG API exported from this file.

This is a semantic noop: the qualification was applied mechanically by
script and no name resolution changes. Verified by:
- All 361 lib/ + src/ queries compile clean.
- All 186 ControlFlow + PointsTo + dataflow library-tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 07:57:42 +00:00
yoff
dc5aa8e0f5 Python: deprecate Function.getAReturnValueFlowNode() and rewrite internal callers
Follow-up to the getAFlowNode deprecation in the same PR: same AST→legacy-CFG
bridge pattern. The 11 internal call sites (across objects/, types/,
frameworks/, and TypeTrackingImpl) are rewritten to bind a `Return ret`
explicitly, then constrain via `ret.getScope() = f and n.getNode() = ret.getValue()`.

The predicate itself is preserved with a deprecation note so external
users do not experience churn.

Semantic noop.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 07:57:42 +00:00
Copilot
db1e5035b4 Python: deprecate AstNode.getAFlowNode() and rewrite internal callers
Preparatory refactor for the shared-CFG dataflow migration.

Deprecates the AstNode.getAFlowNode() cached predicate on the public
Python QL API and rewrites all ~140 internal callers across lib/, src/,
test/, and tools/ from `expr.getAFlowNode() = cfgNode` to
`cfgNode.getNode() = expr`, using ControlFlowNode.getNode() which
already exists in Flow.qll.

The predicate itself is preserved (with a deprecation note pointing at
the new pattern) so external users do not experience churn — they can
migrate at their own pace and the AST/CFG hierarchies still get the
intended untangling once the deprecation eventually elapses.

Semantic noop verified by:
- All 361 lib/ + src/ queries compile clean.
- All 122 ControlFlow + PointsTo library-tests pass.
- All 64 dataflow library-tests pass.
- All 113 Variables/Exceptions/Expressions/Statements/Functions/Imports/
  Security/CWE-798/ModificationOfParameterWithDefault query-tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 07:57:42 +00:00
yoff
7a3f546587 Python: inline init_module_submodule_defn into ImportResolution
The new-dataflow ImportResolution module only used
semmle.python.essa.SsaDefinitions for the 5-line helper predicate
SsaSource::init_module_submodule_defn. Inline it locally and drop the
dependency on legacy SsaDefinitions. This is the only remaining direct
import of semmle.python.essa.* in the new dataflow stack, so dropping
it makes the layering cleaner.

Semantic noop on the current SSA: SsaSourceVariable.getName() and
GlobalVariable.getId() both project the same DB column
(variable(_,_,result)), and the old call's 'init.getEntryNode() = f'
join was just constraining init = package via Scope.getEntryNode()'s
functional uniqueness. RA dump of accesses.ql confirms only the
expected predicate-rename shuffle; all 70 dataflow + ApiGraphs library
tests pass.

This factors out commit 8cab5a20f2 from the larger shared-CFG
migration #21925.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 07:57:42 +00:00
yoff
821325b7e5 Python: simplify decorator-detection predicates to pure AST match
The internal predicates that identify `@staticmethod`, `@classmethod` and
`@property` decorators previously required the decorator's `NameNode` to
satisfy `isGlobal()` (i.e. no SSA def reaches the decorator's name use).
That filter was correct but unnecessarily indirect: these three names
are builtins, and even when a class body redefines one, the class body
has not started executing at the decorator position, so Python uses the
builtin.

Match the decorator's AST `Name` directly instead, dropping the CFG/SSA
detour. The slight semantic change — `isGlobal()` would have rejected
module-level shadowing of these builtins — is negligible in practice
and explicitly documented in the change note.

`hasContextmanagerDecorator` and `hasOverloadDecorator` keep the
`NameNode.isGlobal()` check because their target names (`contextmanager`,
`overload`) are imported, not builtin, and local shadowing is a real
concern.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 07:57:42 +00:00
yoff
4d2296d4f0 Shared CFG: add defaulted getWhileElse/getForeachElse/getCatchType to AstSig
Adds three new defaulted signature predicates to the shared CFG library:

- getWhileElse / getForeachElse: `else` block of a while/for loop, if
  any (used by Python's `while-else` / `for-else` constructs).
- getCatchType: type expression of a catch clause, if any (used by
  Python's `except SomeExpr:` where the catch type is a runtime
  expression that needs CFG evaluation).

Each predicate defaults to `none()`, so behaviour is unchanged for any
language that doesn't override it (verified by re-running
java/ql/test/library-tests/controlflow/).

The Make0 succession rules are extended:
- WhileStmt/ForeachStmt: route the loop-exit edge through the else
  block before reaching the after-position.
- CatchClause: route the matching-evaluation through the type
  expression (if present) before reaching the after-value position.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-05 07:57:37 +00:00
745 changed files with 13609 additions and 35064 deletions

View File

@@ -1,208 +0,0 @@
name: Update Go version
on:
workflow_dispatch:
schedule:
- cron: "0 3 * * 1" # Run weekly on Mondays at 3 AM UTC (1 = Monday)
permissions:
contents: write
pull-requests: write
jobs:
update-go-version:
name: Check and update Go version
if: github.repository == 'github/codeql'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Git
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Fetch latest Go version
id: fetch-version
run: |
LATEST_GO_VERSION=$(curl -s https://go.dev/dl/?mode=json | jq -r '.[0].version')
if [ -z "$LATEST_GO_VERSION" ] || [ "$LATEST_GO_VERSION" = "null" ]; then
echo "Error: Failed to fetch latest Go version from go.dev"
exit 1
fi
echo "Latest Go version from go.dev: $LATEST_GO_VERSION"
echo "version=$LATEST_GO_VERSION" >> $GITHUB_OUTPUT
# Extract version numbers (e.g., go1.26.0 -> 1.26.0)
LATEST_VERSION_NUM=$(echo $LATEST_GO_VERSION | sed 's/^go//')
echo "version_num=$LATEST_VERSION_NUM" >> $GITHUB_OUTPUT
# Extract major.minor version (e.g., 1.26.0 -> 1.26)
LATEST_MAJOR_MINOR=$(echo $LATEST_VERSION_NUM | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
echo "major_minor=$LATEST_MAJOR_MINOR" >> $GITHUB_OUTPUT
- name: Check current Go version
id: current-version
run: |
CURRENT_VERSION=$(sed -n 's/.*go_sdk\.download(version = \"\([^\"]*\)\".*/\1/p' MODULE.bazel)
if [ -z "$CURRENT_VERSION" ]; then
echo "Error: Could not extract Go version from MODULE.bazel"
exit 1
fi
echo "Current Go version in MODULE.bazel: $CURRENT_VERSION"
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
# Extract major.minor version
CURRENT_MAJOR_MINOR=$(echo $CURRENT_VERSION | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
echo "major_minor=$CURRENT_MAJOR_MINOR" >> $GITHUB_OUTPUT
- name: Compare versions
id: compare
run: |
LATEST="${{ steps.fetch-version.outputs.version_num }}"
CURRENT="${{ steps.current-version.outputs.version }}"
echo "Latest: $LATEST"
echo "Current: $CURRENT"
if [ "$LATEST" = "$CURRENT" ]; then
echo "Go version is up to date"
echo "needs_update=false" >> $GITHUB_OUTPUT
else
echo "Go version needs update from $CURRENT to $LATEST"
echo "needs_update=true" >> $GITHUB_OUTPUT
fi
- name: Update Go version in files
if: steps.compare.outputs.needs_update == 'true'
run: |
LATEST_VERSION_NUM="${{ steps.fetch-version.outputs.version_num }}"
LATEST_MAJOR_MINOR="${{ steps.fetch-version.outputs.major_minor }}"
CURRENT_VERSION="${{ steps.current-version.outputs.version }}"
CURRENT_MAJOR_MINOR="${{ steps.current-version.outputs.major_minor }}"
echo "Updating from $CURRENT_VERSION to $LATEST_VERSION_NUM"
# Escape dots in current version strings for use in sed patterns
CURRENT_VERSION_ESCAPED=$(echo "$CURRENT_VERSION" | sed 's/\./\\./g')
CURRENT_MAJOR_MINOR_ESCAPED=$(echo "$CURRENT_MAJOR_MINOR" | sed 's/\./\\./g')
# Update MODULE.bazel
sed -i "s/go_sdk\.download(version = \"$CURRENT_VERSION_ESCAPED\")/go_sdk.download(version = \"$LATEST_VERSION_NUM\")/" MODULE.bazel
if ! grep -q "go_sdk.download(version = \"$LATEST_VERSION_NUM\")" MODULE.bazel; then
echo "Error: Failed to update MODULE.bazel"
exit 1
fi
# Update go/extractor/go.mod
if ! sed -i "s/^go $CURRENT_MAJOR_MINOR_ESCAPED\$/go $LATEST_MAJOR_MINOR/" go/extractor/go.mod; then
echo "Warning: Failed to update go directive in go.mod"
fi
if ! sed -i "s/^toolchain go$CURRENT_VERSION_ESCAPED\$/toolchain go$LATEST_VERSION_NUM/" go/extractor/go.mod; then
echo "Warning: Failed to update toolchain in go.mod"
fi
# Update go/extractor/autobuilder/build-environment.go
if ! sed -i "s/var maxGoVersion = util\.NewSemVer(\"$CURRENT_MAJOR_MINOR_ESCAPED\")/var maxGoVersion = util.NewSemVer(\"$LATEST_MAJOR_MINOR\")/" go/extractor/autobuilder/build-environment.go; then
echo "Warning: Failed to update build-environment.go"
fi
# Update go/actions/test/action.yml
if ! sed -i "s/default: \"~$CURRENT_VERSION_ESCAPED\"/default: \"~$LATEST_VERSION_NUM\"/" go/actions/test/action.yml; then
echo "Warning: Failed to update action.yml"
fi
# Show what changed
git diff
- name: Check for changes
id: check-changes
if: steps.compare.outputs.needs_update == 'true'
run: |
if git diff --quiet; then
echo "No changes detected"
echo "has_changes=false" >> $GITHUB_OUTPUT
else
echo "Changes detected"
echo "has_changes=true" >> $GITHUB_OUTPUT
fi
- name: Check for existing PR
if: steps.check-changes.outputs.has_changes == 'true'
id: check-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH_NAME="workflow/go-version-update"
PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq '.[0].number')
if [ -n "$PR_NUMBER" ]; then
echo "Existing PR found: #$PR_NUMBER"
echo "pr_exists=true" >> $GITHUB_OUTPUT
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
else
echo "No existing PR found"
echo "pr_exists=false" >> $GITHUB_OUTPUT
fi
- name: Commit and push changes
if: steps.check-changes.outputs.has_changes == 'true'
run: |
BRANCH_NAME="workflow/go-version-update"
LATEST_VERSION_NUM="${{ steps.fetch-version.outputs.version_num }}"
LATEST_MAJOR_MINOR="${{ steps.fetch-version.outputs.major_minor }}"
# Create or switch to branch
git checkout -B "$BRANCH_NAME"
# Stage and commit changes
git add MODULE.bazel go/extractor/go.mod go/extractor/autobuilder/build-environment.go go/actions/test/action.yml
git commit -m "Go: Update to $LATEST_VERSION_NUM"
# Push changes
git push --force-with-lease origin "$BRANCH_NAME"
- name: Create or update PR
if: steps.check-changes.outputs.has_changes == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH_NAME="workflow/go-version-update"
LATEST_VERSION_NUM="${{ steps.fetch-version.outputs.version_num }}"
CURRENT_VERSION="${{ steps.current-version.outputs.version }}"
PR_TITLE="Go: Update to $LATEST_VERSION_NUM"
PR_BODY=$(cat <<EOF
This PR updates Go from $CURRENT_VERSION to $LATEST_VERSION_NUM.
Updated files:
- \`MODULE.bazel\` - go_sdk.download version
- \`go/extractor/go.mod\` - go directive and toolchain
- \`go/extractor/autobuilder/build-environment.go\` - maxGoVersion (only if MAJOR.MINOR changes)
- \`go/actions/test/action.yml\` - default go-test-version
This PR was automatically created by the [Go version update workflow](https://github.com/${{ github.repository }}/blob/main/.github/workflows/go-version-update.yml).
EOF
)
if [ "${{ steps.check-pr.outputs.pr_exists }}" = "true" ]; then
echo "Updating existing PR #${{ steps.check-pr.outputs.pr_number }}"
gh pr edit "${{ steps.check-pr.outputs.pr_number }}" --title "$PR_TITLE" --body "$PR_BODY"
else
echo "Creating new PR"
gh pr create \
--title "$PR_TITLE" \
--body "$PR_BODY" \
--base main \
--head "$BRANCH_NAME" \
--label "Go"
fi

View File

@@ -273,7 +273,7 @@ use_repo(
) )
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
go_sdk.download(version = "1.26.4") go_sdk.download(version = "1.26.0")
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//go/extractor:go.mod") go_deps.from_file(go_mod = "//go/extractor:go.mod")

View File

@@ -11,6 +11,10 @@
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll", "java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll" "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll"
], ],
"Bound Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/Bound.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll"
],
"ModulusAnalysis Java/C#": [ "ModulusAnalysis Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll", "java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll" "csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll"

View File

@@ -1,2 +0,0 @@
description: Fix NameQualifier inconsistency
compatibility: full

View File

@@ -1071,7 +1071,7 @@ class NullPointerType extends BuiltInType {
* const float fa[40]; * const float fa[40];
* ``` * ```
*/ */
class DerivedType extends Type, NameQualifyingElement, @derivedtype { class DerivedType extends Type, @derivedtype {
override string toString() { result = this.getName() } override string toString() { result = this.getName() }
override string getName() { derivedtypes(underlyingElement(this), result, _, _) } override string getName() { derivedtypes(underlyingElement(this), result, _, _) }

View File

@@ -1430,8 +1430,7 @@ specialnamequalifyingelements(
@namequalifyingelement = @namespace @namequalifyingelement = @namespace
| @specialnamequalifyingelement | @specialnamequalifyingelement
| @usertype | @usertype
| @decltype | @decltype;
| @derivedtype;
namequalifiers( namequalifiers(
unique int id: @namequalifier, unique int id: @namequalifier,

View File

@@ -1,2 +0,0 @@
description: Fix NameQualifier inconsistency
compatibility: full

View File

@@ -1,7 +1,3 @@
| inconsistency2.cpp:3:3:3:5 | T:: | inconsistency2.cpp:3:3:3:6 | x | inconsistency2.cpp:2:20:2:20 | T |
| inconsistency2.cpp:3:3:3:11 | const s:: | inconsistency2.cpp:3:3:3:6 | x | file://:0:0:0:0 | const s |
| inconsistency.cpp:7:20:7:22 | S:: | inconsistency.cpp:7:20:7:23 | (int)... | inconsistency.cpp:4:8:4:8 | S |
| inconsistency.cpp:7:20:7:22 | S:: | inconsistency.cpp:7:20:7:23 | A | inconsistency.cpp:4:8:4:8 | S |
| name_qualifiers.cpp:29:7:29:8 | :: | name_qualifiers.cpp:29:7:29:9 | x | file://:0:0:0:0 | (global namespace) | | name_qualifiers.cpp:29:7:29:8 | :: | name_qualifiers.cpp:29:7:29:9 | x | file://:0:0:0:0 | (global namespace) |
| name_qualifiers.cpp:31:7:31:10 | N1:: | name_qualifiers.cpp:31:7:31:12 | nx | name_qualifiers.cpp:4:11:4:12 | N1 | | name_qualifiers.cpp:31:7:31:10 | N1:: | name_qualifiers.cpp:31:7:31:12 | nx | name_qualifiers.cpp:4:11:4:12 | N1 |
| name_qualifiers.cpp:34:7:34:8 | :: | name_qualifiers.cpp:34:9:34:12 | N1:: | file://:0:0:0:0 | (global namespace) | | name_qualifiers.cpp:34:7:34:8 | :: | name_qualifiers.cpp:34:9:34:12 | N1:: | file://:0:0:0:0 | (global namespace) |

View File

@@ -1,5 +1,7 @@
import cpp import cpp
from NameQualifier nq, Location l from NameQualifier nq, Location l
where l = nq.getQualifiedElement().getLocation() where
l = nq.getQualifiedElement().getLocation() and
l.getFile().getShortName() = "name_qualifiers"
select nq, nq.getQualifiedElement(), nq.getQualifyingElement() select nq, nq.getQualifiedElement(), nq.getQualifyingElement()

View File

@@ -1,8 +1,8 @@
// This file is present to test whether name-qualifying an enum constant leads to a database inconsistency. // This file is present to test whether name-qualifying an enum constant leads to a database inconsistency.
// As such, there is no QL part of the test.
struct S { enum E { A }; }; struct S { enum E { A }; };
static void f() { static int f() {
switch(0) { case S::A: break; } switch(0) { case S::A: break; }
} }

View File

@@ -1,12 +0,0 @@
namespace {
template <typename T> T f() {
T::x;
return {};
}
struct s {
static int x;
};
struct t {
s x = f<const s>();
};
}

View File

@@ -9,7 +9,6 @@ dependencies:
codeql/controlflow: ${workspace} codeql/controlflow: ${workspace}
codeql/dataflow: ${workspace} codeql/dataflow: ${workspace}
codeql/mad: ${workspace} codeql/mad: ${workspace}
codeql/rangeanalysis: ${workspace}
codeql/ssa: ${workspace} codeql/ssa: ${workspace}
codeql/threat-models: ${workspace} codeql/threat-models: ${workspace}
codeql/tutorial: ${workspace} codeql/tutorial: ${workspace}

View File

@@ -4,31 +4,67 @@
overlay[local?] overlay[local?]
module; module;
private import csharp as CS private import internal.rangeanalysis.BoundSpecific
private import semmle.code.csharp.dataflow.SSA::Ssa
private import semmle.code.csharp.dataflow.internal.rangeanalysis.ConstantUtils as CU
private import semmle.code.csharp.dataflow.internal.rangeanalysis.RangeUtils as RU
private import semmle.code.csharp.dataflow.internal.rangeanalysis.SsaUtils as SU
private import codeql.rangeanalysis.Bound as SharedBound
/** Provides C#-specific definitions for bounds. */ private newtype TBound =
private module BoundDefs implements SharedBound::BoundDefinitions<CS::Location> { TBoundZero() or
class Type = CS::Type; TBoundSsa(SsaVariable v) { v.getSourceVariable().getType() instanceof IntegralType } or
TBoundExpr(Expr e) {
interestingExprBound(e) and
not exists(SsaVariable v | e = v.getAUse())
}
class SsaVariable = SU::SsaVariable; /**
* A bound that may be inferred for an expression plus/minus an integer delta.
*/
abstract class Bound extends TBound {
/** Gets a textual representation of this bound. */
abstract string toString();
class SsaSourceVariable = SourceVariable; /** Gets an expression that equals this bound plus `delta`. */
abstract Expr getExpr(int delta);
class Expr = CS::ControlFlowNodes::ExprNode; /** Gets an expression that equals this bound. */
Expr getExpr() { result = this.getExpr(0) }
class IntegralType = CS::IntegralType; /** Gets the location of this bound. */
abstract Location getLocation();
class ConstantIntegerExpr = CU::ConstantIntegerExpr;
/** Holds if `e` is a bound expression and it is not an SSA variable read. */
predicate interestingExprBound(Expr e) { CU::systemArrayLengthAccess(e.getExpr()) }
} }
module BoundImpl = SharedBound::Bound<CS::Location, BoundDefs>; /**
* The bound that corresponds to the integer 0. This is used to represent all
* integer bounds as bounds are always accompanied by an added integer delta.
*/
class ZeroBound extends Bound, TBoundZero {
override string toString() { result = "0" }
import BoundImpl override Expr getExpr(int delta) { result.(ConstantIntegerExpr).getIntValue() = delta }
override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) }
}
/**
* A bound corresponding to the value of an SSA variable.
*/
class SsaBound extends Bound, TBoundSsa {
/** Gets the SSA variable that equals this bound. */
SsaVariable getSsa() { this = TBoundSsa(result) }
override string toString() { result = this.getSsa().toString() }
override Expr getExpr(int delta) { result = this.getSsa().getAUse() and delta = 0 }
override Location getLocation() { result = this.getSsa().getLocation() }
}
/**
* A bound that corresponds to the value of a specific expression that might be
* interesting, but isn't otherwise represented by the value of an SSA variable.
*/
class ExprBound extends Bound, TBoundExpr {
override string toString() { result = this.getExpr().toString() }
override Expr getExpr(int delta) { this = TBoundExpr(result) and delta = 0 }
override Location getLocation() { result = this.getExpr().getLocation() }
}

View File

@@ -0,0 +1,22 @@
/**
* Provides C#-specific definitions for bounds.
*/
private import csharp as CS
private import semmle.code.csharp.dataflow.SSA::Ssa as Ssa
private import semmle.code.csharp.dataflow.internal.rangeanalysis.ConstantUtils as CU
private import semmle.code.csharp.dataflow.internal.rangeanalysis.RangeUtils as RU
private import semmle.code.csharp.dataflow.internal.rangeanalysis.SsaUtils as SU
class SsaVariable = SU::SsaVariable;
class Expr = CS::ControlFlowNodes::ExprNode;
class Location = CS::Location;
class IntegralType = CS::IntegralType;
class ConstantIntegerExpr = CU::ConstantIntegerExpr;
/** Holds if `e` is a bound expression and it is not an SSA variable read. */
predicate interestingExprBound(Expr e) { CU::systemArrayLengthAccess(e.getExpr()) }

View File

@@ -1,139 +0,0 @@
.. _codeql-cli-2.25.6:
==========================
CodeQL 2.25.6 (2026-06-04)
==========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: none
This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/application-security/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
Security Coverage
-----------------
CodeQL 2.25.6 runs a total of 496 security queries when configured with the Default suite (covering 169 CWE). The Extended suite enables an additional 131 queries (covering 32 more CWE).
CodeQL CLI
----------
Improvements
~~~~~~~~~~~~
* When the :code:`git` executable is available, CodeQL can now obtain configuration and queries from SHA-256 Git repositories, and infer Git metadata about them.
Miscellaneous
~~~~~~~~~~~~~
* The build of Eclipse Temurin OpenJDK that is used to run the CodeQL CLI has been updated to version 21.0.11.
Query Packs
-----------
Bug Fixes
~~~~~~~~~
GitHub Actions
""""""""""""""
* Adjusted (minor) help file descriptions for queries: :code:`actions/untrusted-checkout/critical`, :code:`actions/untrusted-checkout/high`, :code:`actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check.
Major Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
GitHub Actions
""""""""""""""
* Adjusted :code:`actions/untrusted-checkout/critical` to align more with other untrusted resource queries, where the alert location is the location where the artifact is obtained from (the checkout point). This aligns with the other 2 related queries. This will cause the same alerts to re-open for closed alerts of this query.
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
GitHub Actions
""""""""""""""
* Altered the alert message for clarity for queries: :code:`actions/untrusted-checkout/critical`, :code:`actions/untrusted-checkout/high`.
* The :code:`actions/unpinned-tag` query now recognizes 64-character SHA-256 commit hashes as properly pinned references, in addition to 40-character SHA-1 hashes.
Query Metadata Changes
~~~~~~~~~~~~~~~~~~~~~~
GitHub Actions
""""""""""""""
* Reversed adjustment of the name of :code:`actions/untrusted-checkout/high`, but kept the portion of the previous change for the word "trusted" to "privileged". Added a missing "a" to phrasing in :code:`actions/untrusted-checkout/high` and :code:`actions/untrusted-checkout/medium`.
Language Libraries
------------------
Major Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Swift
"""""
* Upgraded to allow analysis of Swift 6.3.2.
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* Added flow source models for :code:`scanf_s` and related functions.
* Added a :code:`Call` column to :code:`LocalFlowSourceFunction::hasLocalFlowSource` and :code:`RemoteFlowSourceFunction::hasRemoteFlowSource`. The old predicates without a :code:`Call` column continue to be supported.
C#
""
* Full support for C# 14 / .NET 10. All new language features are now supported by the extractor. The QL library and data flow analysis now support the new C# 14 language constructs and include generated Models as Data (MaD) models for the .NET 10 runtime.
* C# 14: Added support for user-defined instance increment/decrement operators.
Java/Kotlin
"""""""""""
* Added LLM-generated source and sink models for :code:`org.apache.avro`.
JavaScript/TypeScript
"""""""""""""""""""""
* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example :code:`js/clear-text-logging`) may find more correct results and fewer false positive results after these changes.
Python
""""""
* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example :code:`py/clear-text-logging-sensitive-data`) may find more correct results and fewer false positive results after these changes.
Swift
"""""
* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example :code:`swift/cleartext-logging`) may find more correct results and fewer false positive results after these changes.
GitHub Actions
""""""""""""""
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like :code:`^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a SHA-1 or SHA-256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.
Rust
""""
* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example :code:`rust/cleartext-logging`) may find more correct results and fewer false positive results after these changes.
Deprecated APIs
~~~~~~~~~~~~~~~
C/C++
"""""
* The :code:`UsingAliasTypedefType` class has been deprecated. Use :code:`TypeAliasType` instead.
New Features
~~~~~~~~~~~~
C/C++
"""""
* Added a :code:`getOriginalTemplate` predicate to :code:`TemplateClass`, :code:`TemplateFunction`, :code:`TemplateVariable`, and :code:`AliasTemplateType`, which yields the class member template the template was generated from. The predicates only have results for templates that are members of class template instantiations.
* Added :code:`AliasTemplateType` and :code:`AliasTemplateInstantiationType` classes, representing C++ alias templates and their instantiations.

View File

@@ -11,7 +11,6 @@ A list of queries for each suite and language `is available here <https://docs.g
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
codeql-cli-2.25.6
codeql-cli-2.25.5 codeql-cli-2.25.5
codeql-cli-2.25.4 codeql-cli-2.25.4
codeql-cli-2.25.3 codeql-cli-2.25.3

View File

@@ -4,7 +4,7 @@ inputs:
go-test-version: go-test-version:
description: Which Go version to use for running the tests description: Which Go version to use for running the tests
required: false required: false
default: "~1.26.4" default: "~1.26.0"
run-code-checks: run-code-checks:
description: Whether to run formatting, code and qhelp generation checks description: Whether to run formatting, code and qhelp generation checks
required: false required: false

View File

@@ -2,14 +2,14 @@ module github.com/github/codeql-go/extractor
go 1.26 go 1.26
toolchain go1.26.4 toolchain go1.26.0
// when updating this, run // when updating this, run
// bazel run @rules_go//go -- mod tidy // bazel run @rules_go//go -- mod tidy
// when adding or removing dependencies, run // when adding or removing dependencies, run
// bazel mod tidy // bazel mod tidy
require ( require (
golang.org/x/mod v0.37.0 golang.org/x/mod v0.36.0
golang.org/x/tools v0.45.0 golang.org/x/tools v0.45.0
) )

View File

@@ -6,8 +6,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=

View File

@@ -1,4 +1,4 @@
/** /*
* @name Web Cache Deception * @name Web Cache Deception
* @description A caching system has been detected on the application and is vulnerable to web cache deception. By manipulating the URL it is possible to force the application to cache pages that are only accessible by an authenticated user. Once cached, these pages can be accessed by an unauthenticated user. * @description A caching system has been detected on the application and is vulnerable to web cache deception. By manipulating the URL it is possible to force the application to cache pages that are only accessible by an authenticated user. Once cached, these pages can be accessed by an unauthenticated user.
* @kind problem * @kind problem

View File

@@ -54,31 +54,31 @@ func main() {}
// bad is an example of a bad implementation // bad is an example of a bad implementation
func (ld *Ldap) bad(req *http.Request) { func (ld *Ldap) bad(req *http.Request) {
// ... // ...
untrusted := req.UserAgent() // $ Source untrusted := req.UserAgent()
goldap.NewSearchRequest( goldap.NewSearchRequest(
untrusted, // $ Alert // BAD: untrusted dn untrusted, // BAD: untrusted dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false, goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+untrusted, // $ Alert // BAD: untrusted filter "(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
[]string{"dn", "cn", untrusted}, // $ Alert // BAD: untrusted attribute []string{"dn", "cn", untrusted}, // BAD: untrusted attribute
nil, nil,
) )
goldapv3.NewSearchRequest( goldapv3.NewSearchRequest(
untrusted, // $ Alert // BAD: untrusted dn untrusted, // BAD: untrusted dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false, goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+untrusted, // $ Alert // BAD: untrusted filter "(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
[]string{"dn", "cn", untrusted}, // $ Alert // BAD: untrusted attribute []string{"dn", "cn", untrusted}, // BAD: untrusted attribute
nil, nil,
) )
gopkgldapv2.NewSearchRequest( gopkgldapv2.NewSearchRequest(
untrusted, // $ Alert // BAD: untrusted dn untrusted, // BAD: untrusted dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false, goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+untrusted, // $ Alert // BAD: untrusted filter "(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
[]string{"dn", "cn", untrusted}, // $ Alert // BAD: untrusted attribute []string{"dn", "cn", untrusted}, // BAD: untrusted attribute
nil, nil,
) )
client := &ldapclient.LDAPClient{} client := &ldapclient.LDAPClient{}
client.Authenticate(untrusted, "123456") // $ Alert // BAD: untrusted filter client.Authenticate(untrusted, "123456") // BAD: untrusted filter
client.GetGroupsOfUser(untrusted) // $ Alert // BAD: untrusted filter client.GetGroupsOfUser(untrusted) // BAD: untrusted filter
// ... // ...
} }

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-090/LDAPInjection.ql query: experimental/CWE-090/LDAPInjection.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-203/Timing.ql query: experimental/CWE-203/Timing.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -12,9 +12,9 @@ func bad(w http.ResponseWriter, req *http.Request) (interface{}, error) {
secret := "MySuperSecretPasscode" secret := "MySuperSecretPasscode"
secretHeader := "X-Secret" secretHeader := "X-Secret"
headerSecret := req.Header.Get(secretHeader) // $ Source headerSecret := req.Header.Get(secretHeader)
secretStr := string(secret) secretStr := string(secret)
if len(headerSecret) != 0 && headerSecret != secretStr { // $ Alert if len(headerSecret) != 0 && headerSecret != secretStr {
return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret) return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret)
} }
return nil, nil return nil, nil
@@ -25,9 +25,9 @@ func bad2(w http.ResponseWriter, req *http.Request) (interface{}, error) {
secret := "MySuperSecretPasscode" secret := "MySuperSecretPasscode"
secretHeader := "X-Secret" secretHeader := "X-Secret"
headerSecret := req.Header.Get(secretHeader) // $ Source headerSecret := req.Header.Get(secretHeader)
secretStr := string(secret) secretStr := string(secret)
if len(headerSecret) != 0 && strings.Compare(headerSecret, secretStr) != 0 { // $ Alert if len(headerSecret) != 0 && strings.Compare(headerSecret, secretStr) != 0 {
return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret) return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret)
} }
return nil, nil return nil, nil
@@ -38,8 +38,8 @@ func bad4(w http.ResponseWriter, req *http.Request) (interface{}, error) {
secret := "MySuperSecretPasscode" secret := "MySuperSecretPasscode"
secretHeader := "X-Secret" secretHeader := "X-Secret"
headerSecret := req.Header.Get(secretHeader) // $ Source headerSecret := req.Header.Get(secretHeader)
if len(secret) != 0 && headerSecret != "SecretStringLiteral" { // $ Alert if len(secret) != 0 && headerSecret != "SecretStringLiteral" {
return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret) return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret)
} }
return nil, nil return nil, nil

View File

@@ -1,2 +1 @@
query: experimental/CWE-285/PamAuthBypass.ql experimental/CWE-285/PamAuthBypass.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -9,7 +9,7 @@ import (
func bad() error { func bad() error {
t, _ := pam.StartFunc("", "", func(s pam.Style, msg string) (string, error) { t, _ := pam.StartFunc("", "", func(s pam.Style, msg string) (string, error) {
return "", nil return "", nil
}) // $ Alert })
return t.Authenticate(0) return t.Authenticate(0)
} }

View File

@@ -15,7 +15,7 @@ func bad(w http.ResponseWriter, req *http.Request) (interface{}, error) {
ldapServer := "ldap.example.com" ldapServer := "ldap.example.com"
ldapPort := 389 ldapPort := 389
bindDN := "cn=admin,dc=example,dc=com" bindDN := "cn=admin,dc=example,dc=com"
bindPassword := req.URL.Query()["password"][0] // $ Source bindPassword := req.URL.Query()["password"][0]
// Connect to the LDAP server // Connect to the LDAP server
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
@@ -25,7 +25,7 @@ func bad(w http.ResponseWriter, req *http.Request) (interface{}, error) {
defer l.Close() defer l.Close()
// BAD: user input is not sanetized // BAD: user input is not sanetized
err = l.Bind(bindDN, bindPassword) // $ Alert err = l.Bind(bindDN, bindPassword)
if err != nil { if err != nil {
return fmt.Errorf("LDAP bind failed: %v", err), err return fmt.Errorf("LDAP bind failed: %v", err), err
} }
@@ -84,7 +84,7 @@ func bad2(req *http.Request) {
ldapPort := 389 ldapPort := 389
bindDN := "cn=admin,dc=example,dc=com" bindDN := "cn=admin,dc=example,dc=com"
// BAD : empty password // BAD : empty password
bindPassword := "" // $ Source bindPassword := ""
// Connect to the LDAP server // Connect to the LDAP server
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
@@ -94,7 +94,7 @@ func bad2(req *http.Request) {
defer l.Close() defer l.Close()
// BAD : bindPassword is empty // BAD : bindPassword is empty
err = l.Bind(bindDN, bindPassword) // $ Alert err = l.Bind(bindDN, bindPassword)
if err != nil { if err != nil {
log.Fatalf("LDAP bind failed: %v", err) log.Fatalf("LDAP bind failed: %v", err)
} }

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-287/ImproperLdapAuth.ql query: experimental/CWE-287/ImproperLdapAuth.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,6 +1,3 @@
#select
| go-jose.v3.go:24:32:24:37 | JwtKey | go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:24:32:24:37 | JwtKey | This $@. | go-jose.v3.go:13:21:13:33 | "AllYourBase" | Constant Key is used as JWT Secret key |
| golang-jwt-v5.go:27:9:27:15 | JwtKey1 | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | golang-jwt-v5.go:27:9:27:15 | JwtKey1 | This $@. | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | Constant Key is used as JWT Secret key |
edges edges
| go-jose.v3.go:13:14:13:34 | type conversion | go-jose.v3.go:24:32:24:37 | JwtKey | provenance | | | go-jose.v3.go:13:14:13:34 | type conversion | go-jose.v3.go:24:32:24:37 | JwtKey | provenance | |
| go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:13:14:13:34 | type conversion | provenance | | | go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:13:14:13:34 | type conversion | provenance | |
@@ -14,3 +11,6 @@ nodes
| golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | semmle.label | "AllYourBase" | | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | semmle.label | "AllYourBase" |
| golang-jwt-v5.go:27:9:27:15 | JwtKey1 | semmle.label | JwtKey1 | | golang-jwt-v5.go:27:9:27:15 | JwtKey1 | semmle.label | JwtKey1 |
subpaths subpaths
#select
| go-jose.v3.go:24:32:24:37 | JwtKey | go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:24:32:24:37 | JwtKey | This $@. | go-jose.v3.go:13:21:13:33 | "AllYourBase" | Constant Key is used as JWT Secret key |
| golang-jwt-v5.go:27:9:27:15 | JwtKey1 | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | golang-jwt-v5.go:27:9:27:15 | JwtKey1 | This $@. | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | Constant Key is used as JWT Secret key |

View File

@@ -1,2 +1 @@
query: experimental/CWE-321-V2/HardCodedKeys.ql experimental/CWE-321-V2/HardCodedKeys.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -10,7 +10,7 @@ import (
) )
// NOT OK // NOT OK
var JwtKey = []byte("AllYourBase") // $ Source var JwtKey = []byte("AllYourBase")
func main2(r *http.Request) { func main2(r *http.Request) {
signedToken := r.URL.Query().Get("signedToken") signedToken := r.URL.Query().Get("signedToken")
@@ -21,7 +21,7 @@ func verifyJWT(signedToken string) {
fmt.Println("verifying JWT") fmt.Println("verifying JWT")
DecodedToken, _ := jwt.ParseSigned(signedToken) DecodedToken, _ := jwt.ParseSigned(signedToken)
out := CustomerInfo{} out := CustomerInfo{}
if err := DecodedToken.Claims(JwtKey, &out); err != nil { // $ Alert if err := DecodedToken.Claims(JwtKey, &out); err != nil {
panic(err) panic(err)
} }
fmt.Printf("%v\n", out) fmt.Printf("%v\n", out)

View File

@@ -16,7 +16,7 @@ type CustomerInfo struct {
} }
// BAD constant key // BAD constant key
var JwtKey1 = []byte("AllYourBase") // $ Source var JwtKey1 = []byte("AllYourBase")
func main1(r *http.Request) { func main1(r *http.Request) {
signedToken := r.URL.Query().Get("signedToken") signedToken := r.URL.Query().Get("signedToken")
@@ -24,7 +24,7 @@ func main1(r *http.Request) {
} }
func LoadJwtKey(token *jwt.Token) (interface{}, error) { func LoadJwtKey(token *jwt.Token) (interface{}, error) {
return JwtKey1, nil // $ Alert return JwtKey1, nil
} }
func verifyJWT_golangjwt(signedToken string) { func verifyJWT_golangjwt(signedToken string) {

View File

@@ -7,37 +7,37 @@ import (
) )
func myHandler1(w http.ResponseWriter, r *http.Request) { func myHandler1(w http.ResponseWriter, r *http.Request) {
param1 := r.URL.Query()["param1"][0] // $ Source param1 := r.URL.Query()["param1"][0]
value, _ := strconv.Atoi(param1) value, _ := strconv.Atoi(param1)
out := 1337 / value // $ Alert out := 1337 / value
fmt.Println(out) fmt.Println(out)
} }
func myHandler2(w http.ResponseWriter, r *http.Request) { func myHandler2(w http.ResponseWriter, r *http.Request) {
param1 := r.URL.Query()["param1"][0] // $ Source param1 := r.URL.Query()["param1"][0]
value := int(param1[0]) value := int(param1[0])
out := 1337 / value // $ Alert out := 1337 / value
fmt.Println(out) fmt.Println(out)
} }
func myHandler3(w http.ResponseWriter, r *http.Request) { func myHandler3(w http.ResponseWriter, r *http.Request) {
param1 := r.URL.Query()["param1"][0] // $ Source param1 := r.URL.Query()["param1"][0]
value, _ := strconv.ParseInt(param1, 10, 64) value, _ := strconv.ParseInt(param1, 10, 64)
out := 1337 / value // $ Alert out := 1337 / value
fmt.Println(out) fmt.Println(out)
} }
func myHandler4(w http.ResponseWriter, r *http.Request) { func myHandler4(w http.ResponseWriter, r *http.Request) {
param1 := r.URL.Query()["param1"][0] // $ Source param1 := r.URL.Query()["param1"][0]
value, _ := strconv.ParseFloat(param1, 32) value, _ := strconv.ParseFloat(param1, 32)
out := 1337 / value // $ Alert out := 1337 / value
fmt.Println(out) fmt.Println(out)
} }
func myHandler5(w http.ResponseWriter, r *http.Request) { func myHandler5(w http.ResponseWriter, r *http.Request) {
param1 := r.URL.Query()["param1"][0] // $ Source param1 := r.URL.Query()["param1"][0]
value, _ := strconv.ParseUint(param1, 10, 64) value, _ := strconv.ParseUint(param1, 10, 64)
out := 1337 / value // $ Alert out := 1337 / value
fmt.Println(out) fmt.Println(out)
} }
@@ -51,10 +51,10 @@ func myHandler6(w http.ResponseWriter, r *http.Request) {
} }
func myHandler7(w http.ResponseWriter, r *http.Request) { func myHandler7(w http.ResponseWriter, r *http.Request) {
param1 := r.URL.Query()["param1"][0] // $ Source param1 := r.URL.Query()["param1"][0]
value := int(param1[0]) value := int(param1[0])
if value >= 0 { if value >= 0 {
out := 1337 / value // $ Alert out := 1337 / value
fmt.Println(out) fmt.Println(out)
} }
} }

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-369/DivideByZero.ql query: experimental/CWE-369/DivideByZero.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,7 +1,3 @@
#select
| DatabaseCallInLoop.go:9:3:9:41 | call to First | DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First | This calls call to First in a $@. | DatabaseCallInLoop.go:7:2:11:2 | range statement | loop |
| test.go:11:2:11:13 | call to Take | test.go:20:2:22:2 | for statement | test.go:11:2:11:13 | call to Take | This calls call to Take in a $@. | test.go:20:2:22:2 | for statement | loop |
| test.go:11:2:11:13 | call to Take | test.go:24:2:26:2 | for statement | test.go:11:2:11:13 | call to Take | This calls call to Take in a $@. | test.go:24:2:26:2 | for statement | loop |
edges edges
| DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First | | DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First |
| test.go:10:1:12:1 | function declaration | test.go:11:2:11:13 | call to Take | | test.go:10:1:12:1 | function declaration | test.go:11:2:11:13 | call to Take |
@@ -11,3 +7,7 @@ edges
| test.go:21:3:21:14 | call to runQuery | test.go:10:1:12:1 | function declaration | | test.go:21:3:21:14 | call to runQuery | test.go:10:1:12:1 | function declaration |
| test.go:24:2:26:2 | for statement | test.go:25:3:25:17 | call to runRunQuery | | test.go:24:2:26:2 | for statement | test.go:25:3:25:17 | call to runRunQuery |
| test.go:25:3:25:17 | call to runRunQuery | test.go:14:1:16:1 | function declaration | | test.go:25:3:25:17 | call to runRunQuery | test.go:14:1:16:1 | function declaration |
#select
| DatabaseCallInLoop.go:9:3:9:41 | call to First | DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First | This calls call to First in a $@. | DatabaseCallInLoop.go:7:2:11:2 | range statement | loop |
| test.go:11:2:11:13 | call to Take | test.go:20:2:22:2 | for statement | test.go:11:2:11:13 | call to Take | This calls call to Take in a $@. | test.go:20:2:22:2 | for statement | loop |
| test.go:11:2:11:13 | call to Take | test.go:24:2:26:2 | for statement | test.go:11:2:11:13 | call to Take | This calls call to Take in a $@. | test.go:24:2:26:2 | for statement | loop |

View File

@@ -6,8 +6,8 @@ func getUsers(db *gorm.DB, names []string) []User {
res := make([]User, 0, len(names)) res := make([]User, 0, len(names))
for _, name := range names { for _, name := range names {
var user User var user User
db.Where("name = ?", name).First(&user) // $ Alert db.Where("name = ?", name).First(&user)
res = append(res, user) res = append(res, user)
} // $ Source }
return res return res
} }

View File

@@ -1,2 +1 @@
query: experimental/CWE-400/DatabaseCallInLoop.ql experimental/CWE-400/DatabaseCallInLoop.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -8,7 +8,7 @@ type User struct {
} }
func runQuery(db *gorm.DB) { func runQuery(db *gorm.DB) {
db.Take(nil) // $ Alert db.Take(nil)
} }
func runRunQuery(db *gorm.DB) { func runRunQuery(db *gorm.DB) {
@@ -19,9 +19,9 @@ func main() {
var db *gorm.DB var db *gorm.DB
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
runQuery(db) runQuery(db)
} // $ Source }
for i := 10; i > 0; i-- { for i := 10; i > 0; i-- {
runRunQuery(db) runRunQuery(db)
} // $ Source }
} }

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql query: experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -56,41 +56,41 @@ func main() {
func DecompressHandler(w http.ResponseWriter, request *http.Request) { func DecompressHandler(w http.ResponseWriter, request *http.Request) {
GZipOpenReaderSafe(request.PostFormValue("test")) GZipOpenReaderSafe(request.PostFormValue("test"))
ZipOpenReaderSafe(request.PostFormValue("test")) ZipOpenReaderSafe(request.PostFormValue("test"))
ZipOpenReader(request.FormValue("filepath")) // $ Source ZipOpenReader(request.FormValue("filepath"))
ZipNewReader(request.Body) // $ Source ZipNewReader(request.Body)
ZipNewReaderKlauspost(request.Body) // $ Source ZipNewReaderKlauspost(request.Body)
Bzip2Dsnet(request.Body) // $ Source Bzip2Dsnet(request.Body)
Bzip2DsnetSafe(request.Body) Bzip2DsnetSafe(request.Body)
Bzip2(request.Body) // $ Source Bzip2(request.Body)
Bzip2Safe(request.Body) Bzip2Safe(request.Body)
Flate(request.Body) // $ Source Flate(request.Body)
FlateSafe(request.Body) FlateSafe(request.Body)
FlateKlauspost(request.Body) // $ Source FlateKlauspost(request.Body)
FlateKlauspostSafe(request.Body) FlateKlauspostSafe(request.Body)
FlateDsnet(request.Body) // $ Source FlateDsnet(request.Body)
FlateDsnetSafe(request.Body) FlateDsnetSafe(request.Body)
ZlibKlauspost(request.Body) // $ Source ZlibKlauspost(request.Body)
ZlibKlauspostSafe(request.Body) ZlibKlauspostSafe(request.Body)
Zlib(request.Body) // $ Source Zlib(request.Body)
ZlibSafe(request.Body) ZlibSafe(request.Body)
Snappy(request.Body) // $ Source Snappy(request.Body)
SnappySafe(request.Body) SnappySafe(request.Body)
SnappyKlauspost(request.Body) // $ Source SnappyKlauspost(request.Body)
SnappyKlauspostSafe(request.Body) SnappyKlauspostSafe(request.Body)
S2(request.Body) // $ Source S2(request.Body)
S2Safe(request.Body) S2Safe(request.Body)
Gzip(request.Body) // $ Source Gzip(request.Body)
GzipSafe(request.Body) GzipSafe(request.Body)
GZipIoReader(request.Body, "dest") // $ Source GZipIoReader(request.Body, "dest")
GzipKlauspost(request.Body) // $ Source GzipKlauspost(request.Body)
GzipKlauspostSafe(request.Body) GzipKlauspostSafe(request.Body)
PzipKlauspost(request.Body) // $ Source PzipKlauspost(request.Body)
PzipKlauspostSafe(request.Body) PzipKlauspostSafe(request.Body)
Zstd_Klauspost(request.Body) // $ Source Zstd_Klauspost(request.Body)
Zstd_KlauspostSafe(request.Body) Zstd_KlauspostSafe(request.Body)
Zstd_DataDog(request.Body) // $ Source Zstd_DataDog(request.Body)
Zstd_DataDogSafe(request.Body) Zstd_DataDogSafe(request.Body)
Xz(request.Body) // $ Source Xz(request.Body)
XzSafe(request.Body) XzSafe(request.Body)
} }
@@ -131,7 +131,7 @@ func ZipOpenReader(filename string) {
for _, f := range zipReader.File { for _, f := range zipReader.File {
rc, _ := f.Open() rc, _ := f.Open()
for { for {
result, _ := io.CopyN(os.Stdout, rc, 68) // $ hasValueFlow="rc" Alert result, _ := io.CopyN(os.Stdout, rc, 68) // $ hasValueFlow="rc"
if result == 0 { if result == 0 {
_ = rc.Close() _ = rc.Close()
break break
@@ -144,7 +144,7 @@ func ZipOpenReader(filename string) {
for _, f := range zipKlauspostReader.File { for _, f := range zipKlauspostReader.File {
rc, _ := f.Open() rc, _ := f.Open()
for { for {
result, _ := io.CopyN(os.Stdout, rc, 68) // $ hasValueFlow="rc" Alert result, _ := io.CopyN(os.Stdout, rc, 68) // $ hasValueFlow="rc"
if result == 0 { if result == 0 {
_ = rc.Close() _ = rc.Close()
break break
@@ -161,7 +161,7 @@ func ZipNewReader(file io.Reader) {
for _, file := range zipReader.File { for _, file := range zipReader.File {
fileWriter := bytes.NewBuffer([]byte{}) fileWriter := bytes.NewBuffer([]byte{})
fileReaderCloser, _ := file.Open() fileReaderCloser, _ := file.Open()
result, _ := io.Copy(fileWriter, fileReaderCloser) // $ hasValueFlow="fileReaderCloser" Alert result, _ := io.Copy(fileWriter, fileReaderCloser) // $ hasValueFlow="fileReaderCloser"
fmt.Print(result) fmt.Print(result)
} }
} }
@@ -173,7 +173,7 @@ func ZipNewReaderKlauspost(file io.Reader) {
fileWriter := bytes.NewBuffer([]byte{}) fileWriter := bytes.NewBuffer([]byte{})
// file.OpenRaw() // file.OpenRaw()
fileReaderCloser, _ := file.Open() fileReaderCloser, _ := file.Open()
result, _ := io.Copy(fileWriter, fileReaderCloser) // $ hasValueFlow="fileReaderCloser" Alert result, _ := io.Copy(fileWriter, fileReaderCloser) // $ hasValueFlow="fileReaderCloser"
fmt.Print(result) fmt.Print(result)
} }
} }
@@ -183,7 +183,7 @@ func Bzip2Dsnet(file io.Reader) {
bzip2Reader, _ := bzip2Dsnet.NewReader(file, &bzip2Dsnet.ReaderConfig{}) bzip2Reader, _ := bzip2Dsnet.NewReader(file, &bzip2Dsnet.ReaderConfig{})
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
bzip2Reader.Read(out) // $ hasValueFlow="bzip2Reader" Alert bzip2Reader.Read(out) // $ hasValueFlow="bzip2Reader"
tarRead = tar.NewReader(bzip2Reader) tarRead = tar.NewReader(bzip2Reader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -210,7 +210,7 @@ func Bzip2(file io.Reader) {
bzip2Reader := bzip2.NewReader(file) bzip2Reader := bzip2.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
bzip2Reader.Read(out) // $ hasValueFlow="bzip2Reader" Alert bzip2Reader.Read(out) // $ hasValueFlow="bzip2Reader"
tarRead = tar.NewReader(bzip2Reader) tarRead = tar.NewReader(bzip2Reader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -235,7 +235,7 @@ func Flate(file io.Reader) {
flateReader := flate.NewReader(file) flateReader := flate.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
flateReader.Read(out) // $ hasValueFlow="flateReader" Alert flateReader.Read(out) // $ hasValueFlow="flateReader"
tarRead = tar.NewReader(flateReader) tarRead = tar.NewReader(flateReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -260,7 +260,7 @@ func FlateKlauspost(file io.Reader) {
flateReader := flateKlauspost.NewReader(file) flateReader := flateKlauspost.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
flateReader.Read(out) // $ hasValueFlow="flateReader" Alert flateReader.Read(out) // $ hasValueFlow="flateReader"
tarRead = tar.NewReader(flateReader) tarRead = tar.NewReader(flateReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -285,7 +285,7 @@ func FlateDsnet(file io.Reader) {
flateReader, _ := flateDsnet.NewReader(file, &flateDsnet.ReaderConfig{}) flateReader, _ := flateDsnet.NewReader(file, &flateDsnet.ReaderConfig{})
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
flateReader.Read(out) // $ hasValueFlow="flateReader" Alert flateReader.Read(out) // $ hasValueFlow="flateReader"
tarRead = tar.NewReader(flateReader) tarRead = tar.NewReader(flateReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -310,7 +310,7 @@ func ZlibKlauspost(file io.Reader) {
zlibReader, _ := zlibKlauspost.NewReader(file) zlibReader, _ := zlibKlauspost.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
zlibReader.Read(out) // $ hasValueFlow="zlibReader" Alert zlibReader.Read(out) // $ hasValueFlow="zlibReader"
tarRead = tar.NewReader(zlibReader) tarRead = tar.NewReader(zlibReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -335,7 +335,7 @@ func Zlib(file io.Reader) {
zlibReader, _ := zlib.NewReader(file) zlibReader, _ := zlib.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
zlibReader.Read(out) // $ hasValueFlow="zlibReader" Alert zlibReader.Read(out) // $ hasValueFlow="zlibReader"
tarRead = tar.NewReader(zlibReader) tarRead = tar.NewReader(zlibReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -360,8 +360,8 @@ func Snappy(file io.Reader) {
snappyReader := snappy.NewReader(file) snappyReader := snappy.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
snappyReader.Read(out) // $ hasValueFlow="snappyReader" Alert snappyReader.Read(out) // $ hasValueFlow="snappyReader"
snappyReader.ReadByte() // $ hasValueFlow="snappyReader" Alert snappyReader.ReadByte() // $ hasValueFlow="snappyReader"
tarRead = tar.NewReader(snappyReader) tarRead = tar.NewReader(snappyReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -386,10 +386,10 @@ func SnappyKlauspost(file io.Reader) {
snappyReader := snappyKlauspost.NewReader(file) snappyReader := snappyKlauspost.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
snappyReader.Read(out) // $ hasValueFlow="snappyReader" Alert snappyReader.Read(out) // $ hasValueFlow="snappyReader"
var buf bytes.Buffer var buf bytes.Buffer
snappyReader.DecodeConcurrent(&buf, 2) // $ hasValueFlow="snappyReader" Alert snappyReader.DecodeConcurrent(&buf, 2) // $ hasValueFlow="snappyReader"
snappyReader.ReadByte() // $ hasValueFlow="snappyReader" Alert snappyReader.ReadByte() // $ hasValueFlow="snappyReader"
tarRead = tar.NewReader(snappyReader) tarRead = tar.NewReader(snappyReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -414,10 +414,10 @@ func S2(file io.Reader) {
s2Reader := s2.NewReader(file) s2Reader := s2.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
s2Reader.Read(out) // $ hasValueFlow="s2Reader" Alert s2Reader.Read(out) // $ hasValueFlow="s2Reader"
s2Reader.ReadByte() // $ hasValueFlow="s2Reader" Alert s2Reader.ReadByte() // $ hasValueFlow="s2Reader"
var buf bytes.Buffer var buf bytes.Buffer
s2Reader.DecodeConcurrent(&buf, 2) // $ hasValueFlow="s2Reader" Alert s2Reader.DecodeConcurrent(&buf, 2) // $ hasValueFlow="s2Reader"
tarRead = tar.NewReader(s2Reader) tarRead = tar.NewReader(s2Reader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -442,14 +442,14 @@ func GZipIoReader(src io.Reader, dst string) {
dstF, _ := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) dstF, _ := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
defer dstF.Close() defer dstF.Close()
newSrc := io.Reader(gzipReader) newSrc := io.Reader(gzipReader)
_, _ = io.Copy(dstF, newSrc) // $ hasValueFlow="newSrc" Alert _, _ = io.Copy(dstF, newSrc) // $ hasValueFlow="newSrc"
} }
func Gzip(file io.Reader) { func Gzip(file io.Reader) {
var tarRead *tar.Reader var tarRead *tar.Reader
gzipReader, _ := gzip.NewReader(file) gzipReader, _ := gzip.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
gzipReader.Read(out) // $ hasValueFlow="gzipReader" Alert gzipReader.Read(out) // $ hasValueFlow="gzipReader"
tarRead = tar.NewReader(gzipReader) tarRead = tar.NewReader(gzipReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -474,9 +474,9 @@ func GzipKlauspost(file io.Reader) {
gzipReader, _ := gzipKlauspost.NewReader(file) gzipReader, _ := gzipKlauspost.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
gzipReader.Read(out) // $ hasValueFlow="gzipReader" Alert gzipReader.Read(out) // $ hasValueFlow="gzipReader"
var buf bytes.Buffer var buf bytes.Buffer
gzipReader.WriteTo(&buf) // $ hasValueFlow="gzipReader" Alert gzipReader.WriteTo(&buf) // $ hasValueFlow="gzipReader"
tarRead = tar.NewReader(gzipReader) tarRead = tar.NewReader(gzipReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -501,9 +501,9 @@ func PzipKlauspost(file io.Reader) {
pgzipReader, _ := pgzipKlauspost.NewReader(file) pgzipReader, _ := pgzipKlauspost.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
pgzipReader.Read(out) // $ hasValueFlow="pgzipReader" Alert pgzipReader.Read(out) // $ hasValueFlow="pgzipReader"
var buf bytes.Buffer var buf bytes.Buffer
pgzipReader.WriteTo(&buf) // $ hasValueFlow="pgzipReader" Alert pgzipReader.WriteTo(&buf) // $ hasValueFlow="pgzipReader"
tarRead = tar.NewReader(pgzipReader) tarRead = tar.NewReader(pgzipReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -528,11 +528,11 @@ func Zstd_Klauspost(file io.Reader) {
zstdReader, _ := zstdKlauspost.NewReader(file) zstdReader, _ := zstdKlauspost.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
zstdReader.Read(out) // $ hasValueFlow="zstdReader" Alert zstdReader.Read(out) // $ hasValueFlow="zstdReader"
var buf bytes.Buffer var buf bytes.Buffer
zstdReader.WriteTo(&buf) // $ hasValueFlow="zstdReader" Alert zstdReader.WriteTo(&buf) // $ hasValueFlow="zstdReader"
var src []byte var src []byte
zstdReader.DecodeAll(src, nil) // $ hasValueFlow="zstdReader" Alert zstdReader.DecodeAll(src, nil) // $ hasValueFlow="zstdReader"
tarRead = tar.NewReader(zstdReader) tarRead = tar.NewReader(zstdReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -557,7 +557,7 @@ func Zstd_DataDog(file io.Reader) {
zstdReader := zstdDataDog.NewReader(file) zstdReader := zstdDataDog.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
zstdReader.Read(out) // $ hasValueFlow="zstdReader" Alert zstdReader.Read(out) // $ hasValueFlow="zstdReader"
tarRead = tar.NewReader(zstdReader) tarRead = tar.NewReader(zstdReader)
TarDecompressor(tarRead) TarDecompressor(tarRead)
@@ -582,7 +582,7 @@ func Xz(file io.Reader) {
xzReader, _ := xz.NewReader(file) xzReader, _ := xz.NewReader(file)
var out []byte = make([]byte, 70) var out []byte = make([]byte, 70)
xzReader.Read(out) // $ hasValueFlow="xzReader" Alert xzReader.Read(out) // $ hasValueFlow="xzReader"
tarRead = tar.NewReader(xzReader) tarRead = tar.NewReader(xzReader)
fmt.Println(io.SeekStart) fmt.Println(io.SeekStart)
@@ -618,7 +618,7 @@ func TarDecompressor(tarRead *tar.Reader) {
if cur.Typeflag != tar.TypeReg { if cur.Typeflag != tar.TypeReg {
continue continue
} }
data, _ := io.ReadAll(tarRead) // $ hasValueFlow="tarRead" Alert data, _ := io.ReadAll(tarRead) // $ hasValueFlow="tarRead"
files[cur.Name] = &fstest.MapFile{Data: data} files[cur.Name] = &fstest.MapFile{Data: data}
} }
fmt.Print(files) fmt.Print(files)
@@ -626,7 +626,7 @@ func TarDecompressor(tarRead *tar.Reader) {
func TarDecompressor2(tarRead *tar.Reader) { func TarDecompressor2(tarRead *tar.Reader) {
var tarOut []byte = make([]byte, 70) var tarOut []byte = make([]byte, 70)
tarRead.Read(tarOut) // $ hasValueFlow="tarRead" Alert tarRead.Read(tarOut) // $ hasValueFlow="tarRead"
fmt.Println("do sth with output:", tarOut) fmt.Println("do sth with output:", tarOut)
} }

View File

@@ -1,2 +1 @@
query: experimental/CWE-525/WebCacheDeception.ql experimental/CWE-525/WebCacheDeception.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -79,7 +79,7 @@ func badRoutingNet() {
http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/")))) http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/"))))
http.HandleFunc("/adminusers/", ShowAdminPageCache) // $ Alert http.HandleFunc("/adminusers/", ShowAdminPageCache)
err := http.ListenAndServe(":1337", nil) err := http.ListenAndServe(":1337", nil)
if err != nil { if err != nil {
log.Fatal("ListenAndServe: ", err) log.Fatal("ListenAndServe: ", err)

View File

@@ -12,12 +12,12 @@ func badRouting() {
log.Println("We are logging in Golang!") log.Println("We are logging in Golang!")
// GET /api/register // GET /api/register
app.Get("/api/*", func(c *fiber.Ctx) error { // $ Alert app.Get("/api/*", func(c *fiber.Ctx) error {
msg := fmt.Sprintf("✋") msg := fmt.Sprintf("✋")
return c.SendString(msg) // => ✋ register return c.SendString(msg) // => ✋ register
}) })
app.Post("/api/*", func(c *fiber.Ctx) error { // $ Alert app.Post("/api/*", func(c *fiber.Ctx) error {
msg := fmt.Sprintf("✋") msg := fmt.Sprintf("✋")
return c.SendString(msg) // => ✋ register return c.SendString(msg) // => ✋ register
}) })

View File

@@ -10,7 +10,7 @@ import (
func badRoutingChi() { func badRoutingChi() {
r := chi.NewRouter() r := chi.NewRouter()
r.Use(middleware.Logger) r.Use(middleware.Logger)
r.Get("/*", func(w http.ResponseWriter, r *http.Request) { // $ Alert r.Get("/*", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("welcome")) w.Write([]byte("welcome"))
}) })
http.ListenAndServe(":3000", r) http.ListenAndServe(":3000", r)

View File

@@ -18,7 +18,7 @@ func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
func badHTTPRouter() { func badHTTPRouter() {
router := httprouter.New() router := httprouter.New()
router.GET("/test/*test", Index) // $ Alert router.GET("/test/*test", Index)
router.GET("/hello/:name", Hello) router.GET("/hello/:name", Hello)
log.Fatal(http.ListenAndServe(":8082", router)) log.Fatal(http.ListenAndServe(":8082", router))

View File

@@ -23,10 +23,10 @@ func good() (interface{}, error) {
} }
func bad() interface{} { func bad() interface{} {
name2 := os.Args[1:] // $ Source[go/dsn-injection-local] name2 := os.Args[1:]
// This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files. // This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files.
dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, name2[0]) dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, name2[0])
db, _ := sql.Open("mysql", dbDSN) // $ Alert[go/dsn-injection-local] db, _ := sql.Open("mysql", dbDSN)
return db return db
} }
@@ -44,10 +44,10 @@ func good2(w http.ResponseWriter, req *http.Request) (interface{}, error) {
} }
func bad2(w http.ResponseWriter, req *http.Request) interface{} { func bad2(w http.ResponseWriter, req *http.Request) interface{} {
name := req.FormValue("name") // $ Source[go/dsn-injection] name := req.FormValue("name")
// This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files. // This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files.
dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, name) dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, name)
db, _ := sql.Open("mysql", dbDSN) // $ Alert[go/dsn-injection] db, _ := sql.Open("mysql", dbDSN)
return db return db
} }
@@ -60,12 +60,12 @@ func (Config) Parse([]string) error { return nil }
func RegexFuncModelTest(w http.ResponseWriter, req *http.Request) (interface{}, error) { func RegexFuncModelTest(w http.ResponseWriter, req *http.Request) (interface{}, error) {
cfg := NewConfig() cfg := NewConfig()
err := cfg.Parse(os.Args[1:]) // $ Source[go/dsn-injection-local] // This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files. err := cfg.Parse(os.Args[1:]) // This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files.
if err != nil { if err != nil {
return nil, err return nil, err
} }
dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, cfg.dsn) dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, cfg.dsn)
db, _ := sql.Open("mysql", dbDSN) // $ Alert[go/dsn-injection-local] db, _ := sql.Open("mysql", dbDSN)
return db, nil return db, nil
} }

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-74/DsnInjection.ql query: experimental/CWE-74/DsnInjection.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-74/DsnInjectionLocal.ql query: experimental/CWE-74/DsnInjectionLocal.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,2 +1 @@
query: experimental/CWE-807/SensitiveConditionBypass.ql experimental/CWE-807/SensitiveConditionBypass.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -4,7 +4,7 @@ import "net/http"
func example(w http.ResponseWriter, r *http.Request) { func example(w http.ResponseWriter, r *http.Request) {
test2 := "test" test2 := "test"
if r.Header.Get("X-Password") != test2 { // $ Alert if r.Header.Get("X-Password") != test2 {
login() login()
} }
} }

View File

@@ -13,7 +13,7 @@ const test = "localhost"
// Should alert as authkey is sensitive // Should alert as authkey is sensitive
func ex1(w http.ResponseWriter, r *http.Request) { func ex1(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Origin") != test { // $ Alert if r.Header.Get("Origin") != test {
authkey := "randomDatta" authkey := "randomDatta"
io.WriteString(w, authkey) io.WriteString(w, authkey)
} }
@@ -22,7 +22,7 @@ func ex1(w http.ResponseWriter, r *http.Request) {
// Should alert as authkey is sensitive // Should alert as authkey is sensitive
func ex2(w http.ResponseWriter, r *http.Request) { func ex2(w http.ResponseWriter, r *http.Request) {
test2 := "test" test2 := "test"
if r.Header.Get("Origin") != test2 { // $ Alert if r.Header.Get("Origin") != test2 {
authkey := "randomDatta2" authkey := "randomDatta2"
io.WriteString(w, authkey) io.WriteString(w, authkey)
} }
@@ -31,7 +31,7 @@ func ex2(w http.ResponseWriter, r *http.Request) {
// Should alert as login() is sensitive // Should alert as login() is sensitive
func ex3(w http.ResponseWriter, r *http.Request) { func ex3(w http.ResponseWriter, r *http.Request) {
test2 := "test" test2 := "test"
if r.Header.Get("Origin") != test2 { // $ Alert if r.Header.Get("Origin") != test2 {
login() login()
} }
} }

View File

@@ -1,2 +1 @@
query: experimental/CWE-840/ConditionalBypass.ql experimental/CWE-840/ConditionalBypass.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -6,7 +6,7 @@ import (
func exampleHandlerBad(w http.ResponseWriter, r *http.Request) { func exampleHandlerBad(w http.ResponseWriter, r *http.Request) {
// BAD: the Origin and Host headers are user controlled // BAD: the Origin and Host headers are user controlled
if r.Header.Get("Origin") != "http://"+r.Host { // $ Alert if r.Header.Get("Origin") != "http://"+r.Host {
//do something //do something
} }
} }

View File

@@ -6,14 +6,14 @@ import (
// BAD: taken from https://www.gorillatoolkit.org/pkg/websocket // BAD: taken from https://www.gorillatoolkit.org/pkg/websocket
func ex1(w http.ResponseWriter, r *http.Request) { func ex1(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Origin") != "http://"+r.Host { // $ Alert if r.Header.Get("Origin") != "http://"+r.Host {
//do something //do something
} }
} }
// BAD: both operands are from remote sources // BAD: both operands are from remote sources
func ex2(w http.ResponseWriter, r *http.Request) { func ex2(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Origin") != "http://"+r.Header.Get("Header") { // $ Alert if r.Header.Get("Origin") != "http://"+r.Header.Get("Header") {
//do something //do something
} }
} }

View File

@@ -5,7 +5,7 @@ import "os"
func openFiles(filenames []string) { func openFiles(filenames []string) {
for _, filename := range filenames { for _, filename := range filenames {
file, err := os.Open(filename) file, err := os.Open(filename)
defer file.Close() // $ Alert[go/examples/deferinloop] defer file.Close()
if err != nil { if err != nil {
// handle error // handle error
} }

View File

@@ -1,2 +1 @@
query: experimental/InconsistentCode/DeferInLoop.ql experimental/InconsistentCode/DeferInLoop.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -4,6 +4,6 @@ import "gorm.io/gorm"
func getUserId(db *gorm.DB, name string) int64 { func getUserId(db *gorm.DB, name string) int64 {
var user User var user User
db.Where("name = ?", name).First(&user) // $ Alert[go/examples/gorm-error-not-checked] db.Where("name = ?", name).First(&user)
return user.Id return user.Id
} }

View File

@@ -1,2 +1 @@
query: experimental/InconsistentCode/GORMErrorNotChecked.ql experimental/InconsistentCode/GORMErrorNotChecked.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -3,24 +3,24 @@ package main
func test() { func test() {
var xs []int var xs []int
for _ = range xs { for _ = range xs {
defer test() // $ Alert[go/examples/deferinloop] // not ok defer test() // not ok
} }
for _ = range xs { for _ = range xs {
if true { if true {
defer test() // $ Alert[go/examples/deferinloop] // not ok defer test() // not ok
} }
} }
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
defer test() // $ Alert[go/examples/deferinloop] defer test()
} }
for true { for true {
defer test() // $ Alert[go/examples/deferinloop] // not ok defer test() // not ok
} }
for false { for false {
defer test() // $ Alert[go/examples/deferinloop] // fine but caught defer test() // fine but caught
} }
} }

View File

@@ -1,15 +1,3 @@
#select
| WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | WrongUsageOfUnsafe.go:77:27:77:54 | type conversion | WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | $@. | WrongUsageOfUnsafe.go:77:27:77:54 | type conversion | Dangerous array type casting to [8]uint8 from an index expression ([8]uint8)[2] (the destination type is 2 elements longer) |
| WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | WrongUsageOfUnsafe.go:111:31:111:58 | type conversion | WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | $@. | WrongUsageOfUnsafe.go:111:31:111:58 | type conversion | Dangerous array type casting to [17]uint8 from an index expression ([8]uint8)[0] (the destination type is 9 elements longer) |
| WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | WrongUsageOfUnsafe.go:129:31:129:55 | type conversion | WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | $@. | WrongUsageOfUnsafe.go:129:31:129:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
| WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | WrongUsageOfUnsafe.go:149:31:149:55 | type conversion | WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | $@. | WrongUsageOfUnsafe.go:149:31:149:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
| WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | $@. | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | Dangerous array type casting to [17]string from [8]string |
| WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | $@. | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | Dangerous type up-casting to [17]uint8 from struct type |
| WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | $@. | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
| WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | $@. | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
| WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | $@. | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | Dangerous array type casting to [4]int64 from [1]int64 |
| WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | $@. | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | Dangerous numeric type casting to int64 from int8 |
| WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | $@. | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | Dangerous numeric type casting to int from int8 |
edges edges
| WrongUsageOfUnsafe.go:17:24:17:48 | type conversion | WrongUsageOfUnsafe.go:17:13:17:49 | type conversion | provenance | | | WrongUsageOfUnsafe.go:17:24:17:48 | type conversion | WrongUsageOfUnsafe.go:17:13:17:49 | type conversion | provenance | |
| WrongUsageOfUnsafe.go:34:24:34:51 | type conversion | WrongUsageOfUnsafe.go:34:13:34:52 | type conversion | provenance | | | WrongUsageOfUnsafe.go:34:24:34:51 | type conversion | WrongUsageOfUnsafe.go:34:13:34:52 | type conversion | provenance | |
@@ -60,3 +48,15 @@ nodes
| WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | semmle.label | type conversion | | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | semmle.label | type conversion |
| WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | semmle.label | type conversion | | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | semmle.label | type conversion |
subpaths subpaths
#select
| WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | WrongUsageOfUnsafe.go:77:27:77:54 | type conversion | WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | $@. | WrongUsageOfUnsafe.go:77:27:77:54 | type conversion | Dangerous array type casting to [8]uint8 from an index expression ([8]uint8)[2] (the destination type is 2 elements longer) |
| WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | WrongUsageOfUnsafe.go:111:31:111:58 | type conversion | WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | $@. | WrongUsageOfUnsafe.go:111:31:111:58 | type conversion | Dangerous array type casting to [17]uint8 from an index expression ([8]uint8)[0] (the destination type is 9 elements longer) |
| WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | WrongUsageOfUnsafe.go:129:31:129:55 | type conversion | WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | $@. | WrongUsageOfUnsafe.go:129:31:129:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
| WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | WrongUsageOfUnsafe.go:149:31:149:55 | type conversion | WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | $@. | WrongUsageOfUnsafe.go:149:31:149:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
| WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | $@. | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | Dangerous array type casting to [17]string from [8]string |
| WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | $@. | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | Dangerous type up-casting to [17]uint8 from struct type |
| WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | $@. | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
| WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | $@. | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
| WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | $@. | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | Dangerous array type casting to [4]int64 from [1]int64 |
| WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | $@. | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | Dangerous numeric type casting to int64 from int8 |
| WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | $@. | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | Dangerous numeric type casting to int from int8 |

View File

@@ -74,7 +74,7 @@ func badIndexExpr() {
// the address of the 3rd element of the `harmless` array, // the address of the 3rd element of the `harmless` array,
// and continue for 8 bytes, going out of the boundaries of // and continue for 8 bytes, going out of the boundaries of
// `harmless` and crossing into the memory occupied by `secret`. // `harmless` and crossing into the memory occupied by `secret`.
var leaking = (*[8]byte)(unsafe.Pointer(&harmless[2])) // $ Alert // BAD var leaking = (*[8]byte)(unsafe.Pointer(&harmless[2])) // BAD
fmt.Println(string((*leaking)[:])) fmt.Println(string((*leaking)[:]))
@@ -108,7 +108,7 @@ func bad0() {
// Read before secret, overflowing into secret // Read before secret, overflowing into secret
// (notice we get the pointer to the first byte of harmless) // (notice we get the pointer to the first byte of harmless)
var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless[0])) // $ Alert // BAD var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless[0])) // BAD
fmt.Println(string((*leaking)[:])) fmt.Println(string((*leaking)[:]))
@@ -126,7 +126,7 @@ func bad1() {
// Read before secret, overflowing into secret // Read before secret, overflowing into secret
// (notice we read more than the length of harmless) // (notice we read more than the length of harmless)
var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // $ Alert // BAD var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // BAD
fmt.Println(string((*leaking)[:])) fmt.Println(string((*leaking)[:]))
@@ -146,7 +146,7 @@ func bad2() {
// Read before secret, overflowing into secret // Read before secret, overflowing into secret
// (notice we read more than the length of harmless) // (notice we read more than the length of harmless)
var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // $ Alert // BAD var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // BAD
fmt.Println(string((*leaking)[:])) fmt.Println(string((*leaking)[:]))
@@ -163,7 +163,7 @@ func bad3() {
// Read before secret, overflowing into secret // Read before secret, overflowing into secret
// (notice we read more than the length of harmless) // (notice we read more than the length of harmless)
var leaking = (*[8 + 9]string)(unsafe.Pointer(&harmless)) // $ Alert // BAD var leaking = (*[8 + 9]string)(unsafe.Pointer(&harmless)) // BAD
fmt.Println(*leaking) fmt.Println(*leaking)
fmt.Println([17]string((*leaking))) fmt.Println([17]string((*leaking)))
@@ -186,7 +186,7 @@ func bad4() {
// Read before secret, overflowing into secret // Read before secret, overflowing into secret
// (notice we read more than the length of harmless) // (notice we read more than the length of harmless)
var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // $ Alert // BAD var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // BAD
fmt.Println(string((*leaking)[:])) fmt.Println(string((*leaking)[:]))
@@ -208,7 +208,7 @@ func bad5() {
// Read before secret, overflowing into secret // Read before secret, overflowing into secret
// (notice we read more than the length of harmless) // (notice we read more than the length of harmless)
var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless.Data)) // $ Alert // BAD var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless.Data)) // BAD
fmt.Println(string(leaking[:])) fmt.Println(string(leaking[:]))
@@ -224,7 +224,7 @@ func bad6() {
secret := [9]byte{'s', 'e', 'n', 's', 'i', 't', 'i', 'v', 'e'} secret := [9]byte{'s', 'e', 'n', 's', 'i', 't', 'i', 'v', 'e'}
// Read before secret: // Read before secret:
var leaking = buffer_request(unsafe.Pointer(&harmless)) // $ Source // BAD (see inside buffer_request func) var leaking = buffer_request(unsafe.Pointer(&harmless)) // BAD (see inside buffer_request func)
fmt.Println((string)(leaking[:])) fmt.Println((string)(leaking[:]))
@@ -240,7 +240,7 @@ func buffer_request(req unsafe.Pointer) [8 + 9]byte {
// will be read, the read will also contain pieces of // will be read, the read will also contain pieces of
// data from `secret`. // data from `secret`.
var buf [8 + 9]byte var buf [8 + 9]byte
buf = *(*[8 + 9]byte)(req) // $ Alert // BAD (from above func) buf = *(*[8 + 9]byte)(req) // BAD (from above func)
return buf return buf
} }
func bad7() { func bad7() {
@@ -253,7 +253,7 @@ func bad7() {
// (notice we read more than the length of harmless); // (notice we read more than the length of harmless);
// the leaking array will not contain letters, // the leaking array will not contain letters,
// but integers representing bytes from `secret`. // but integers representing bytes from `secret`.
var leaking = (*[4]int64)(unsafe.Pointer(&harmless)) // $ Alert // BAD var leaking = (*[4]int64)(unsafe.Pointer(&harmless)) // BAD
fmt.Println(*leaking) fmt.Println(*leaking)
@@ -271,7 +271,7 @@ func bad8() {
// Read before secret, overflowing into secret // Read before secret, overflowing into secret
// (notice we read more than the length of harmless); // (notice we read more than the length of harmless);
// the leaking data will contain some bits from `secret`. // the leaking data will contain some bits from `secret`.
var leaking = (*int64)(unsafe.Pointer(&harmless)) // $ Alert // BAD var leaking = (*int64)(unsafe.Pointer(&harmless)) // BAD
fmt.Println(*leaking) fmt.Println(*leaking)
@@ -289,7 +289,7 @@ func bad9() {
// Read before secret, overflowing into secret // Read before secret, overflowing into secret
// (notice we read more than the length of harmless); // (notice we read more than the length of harmless);
// the leaking data will contain some bits from `secret`. // the leaking data will contain some bits from `secret`.
var leaking = (*int)(unsafe.Pointer(&harmless)) // $ Alert // BAD var leaking = (*int)(unsafe.Pointer(&harmless)) // BAD
fmt.Println(*leaking) fmt.Println(*leaking)

View File

@@ -1,2 +1 @@
query: experimental/Unsafe/WrongUsageOfUnsafe.ql experimental/Unsafe/WrongUsageOfUnsafe.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -9,9 +9,9 @@ import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import utils.test.InlineFlowTest import utils.test.InlineFlowTest
module Config implements DataFlow::ConfigSig { module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { sourceNode(source, "qltest") } predicate isSource(DataFlow::Node src) { sourceNode(src, "qltest") }
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "qltest") } predicate isSink(DataFlow::Node src) { sinkNode(src, "qltest") }
} }
import ValueFlowTest<Config> import ValueFlowTest<Config>

View File

@@ -1,2 +0,0 @@
reverseRead
| main.go:23:3:23:5 | out | Origin of readStep is missing a PostUpdateNode. |

View File

@@ -4,7 +4,7 @@ func source() string {
return "untrusted data" return "untrusted data"
} }
func sink(any) { func sink(string) {
} }
type A struct { type A struct {
@@ -19,10 +19,6 @@ func functionWithVarArgsParameter(s ...string) string {
return s[1] return s[1]
} }
func functionWithVarArgsOutParameter(in string, out ...*string) {
*out[0] = in
}
func functionWithSliceOfStructsParameter(s []A) string { func functionWithSliceOfStructsParameter(s []A) string {
return s[1].f return s[1].f
} }
@@ -42,12 +38,6 @@ func main() {
sink(functionWithVarArgsParameter(sSlice...)) // $ hasValueFlow="call to functionWithVarArgsParameter" sink(functionWithVarArgsParameter(sSlice...)) // $ hasValueFlow="call to functionWithVarArgsParameter"
sink(functionWithVarArgsParameter(s0, s1)) // $ hasValueFlow="call to functionWithVarArgsParameter" sink(functionWithVarArgsParameter(s0, s1)) // $ hasValueFlow="call to functionWithVarArgsParameter"
var out1 *string
var out2 *string
functionWithVarArgsOutParameter(source(), out1, out2)
sink(out1) // $ MISSING: hasValueFlow="out1"
sink(out2) // $ MISSING: hasValueFlow="out2"
sliceOfStructs := []A{{f: source()}} sliceOfStructs := []A{{f: source()}}
sink(sliceOfStructs[0].f) // $ hasValueFlow="selection of f" sink(sliceOfStructs[0].f) // $ hasValueFlow="selection of f"

View File

@@ -1,2 +0,0 @@
invalidModelRow
testFailures

View File

@@ -1,21 +0,0 @@
extensions:
- addsTo:
pack: codeql/go-all
extensible: summaryModel
data:
- ["github.com/nonexistent/test", "", False, "FunctionWithParameter", "", "", "Argument[0]", "ReturnValue", "value", "manual"]
- ["github.com/nonexistent/test", "", False, "FunctionWithSliceParameter", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"]
- ["github.com/nonexistent/test", "", False, "FunctionWithVarArgsParameter", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"]
- ["github.com/nonexistent/test", "", False, "FunctionWithVarArgsOutParameter", "", "", "Argument[0]", "Argument[1].ArrayElement", "value", "manual"]
- ["github.com/nonexistent/test", "", False, "FunctionWithSliceOfStructsParameter", "", "", "Argument[0].ArrayElement.Field[github.com/nonexistent/test.A.Field]", "ReturnValue", "value", "manual"]
- ["github.com/nonexistent/test", "", False, "FunctionWithVarArgsOfStructsParameter", "", "", "Argument[0].ArrayElement.Field[github.com/nonexistent/test.A.Field]", "ReturnValue", "value", "manual"]
- addsTo:
pack: codeql/go-all
extensible: sourceModel
data:
- ["github.com/nonexistent/test", "", False, "VariadicSource", "", "", "Argument[0]", "qltest", "manual"]
- addsTo:
pack: codeql/go-all
extensible: sinkModel
data:
- ["github.com/nonexistent/test", "", False, "VariadicSink", "", "", "Argument[0]", "qltest", "manual"]

View File

@@ -1,22 +0,0 @@
import go
import semmle.go.dataflow.ExternalFlow
import ModelValidation
import utils.test.InlineFlowTest
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
sourceNode(source, "qltest")
or
exists(Function fn | fn.hasQualifiedName(_, ["source", "taint"]) |
source = fn.getACall().getResult()
)
}
predicate isSink(DataFlow::Node sink) {
sinkNode(sink, "qltest")
or
exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument())
}
}
import FlowTest<Config, Config>

View File

@@ -1,5 +0,0 @@
module semmle.go.Packages
go 1.25
require github.com/nonexistent/test v0.0.0-20200203000000-0000000000000

View File

@@ -1,56 +0,0 @@
package main
import (
"github.com/nonexistent/test"
)
func source() string {
return "untrusted data"
}
func sink(any) {
}
func main() {
s := source()
sink(test.FunctionWithParameter(s)) // $ hasValueFlow="call to FunctionWithParameter"
stringSlice := []string{source()}
sink(stringSlice[0]) // $ hasValueFlow="index expression"
s0 := ""
s1 := source()
sSlice := []string{s0, s1}
sink(test.FunctionWithParameter(sSlice[1])) // $ hasValueFlow="call to FunctionWithParameter"
sink(test.FunctionWithSliceParameter(sSlice)) // $ hasValueFlow="call to FunctionWithSliceParameter"
sink(test.FunctionWithVarArgsParameter(sSlice...)) // $ hasValueFlow="call to FunctionWithVarArgsParameter"
sink(test.FunctionWithVarArgsParameter(s0, s1)) // $ hasValueFlow="call to FunctionWithVarArgsParameter"
var out1 *string
var out2 *string
test.FunctionWithVarArgsOutParameter(source(), out1, out2)
sink(out1) // $ MISSING: hasValueFlow="out1"
sink(out2) // $ MISSING: hasValueFlow="out2"
sliceOfStructs := []test.A{{Field: source()}}
sink(sliceOfStructs[0].Field) // $ hasValueFlow="selection of Field"
a0 := test.A{Field: ""}
a1 := test.A{Field: source()}
aSlice := []test.A{a0, a1}
sink(test.FunctionWithSliceOfStructsParameter(aSlice)) // $ hasValueFlow="call to FunctionWithSliceOfStructsParameter"
sink(test.FunctionWithVarArgsOfStructsParameter(aSlice...)) // $ hasValueFlow="call to FunctionWithVarArgsOfStructsParameter"
sink(test.FunctionWithVarArgsOfStructsParameter(a0, a1)) // $ hasValueFlow="call to FunctionWithVarArgsOfStructsParameter"
var variadicSource string
test.VariadicSource(&variadicSource)
sink(variadicSource) // $ MISSING: hasTaintFlow="variadicSource"
sink(&variadicSource) // $ MISSING: hasTaintFlow="&..."
var variadicSourcePtr *string
test.VariadicSource(variadicSourcePtr)
sink(variadicSourcePtr) // $ MISSING: hasTaintFlow="variadicSourcePtr"
sink(*variadicSourcePtr) // $ MISSING: hasTaintFlow="star expression"
test.VariadicSink(source()) // $ hasTaintFlow="[]type{args}"
}

View File

@@ -1,32 +0,0 @@
package test
type A struct {
Field string
}
func FunctionWithParameter(s string) string {
return ""
}
func FunctionWithSliceParameter(s []string) string {
return ""
}
func FunctionWithVarArgsParameter(s ...string) string {
return ""
}
func FunctionWithVarArgsOutParameter(in string, out ...*string) {
}
func FunctionWithSliceOfStructsParameter(s []A) string {
return ""
}
func FunctionWithVarArgsOfStructsParameter(s ...A) string {
return ""
}
func VariadicSource(s ...*string) {}
func VariadicSink(s ...string) {}

View File

@@ -1,3 +0,0 @@
# github.com/nonexistent/test v0.0.0-20200203000000-0000000000000
## explicit
github.com/nonexistent/test

View File

@@ -20,9 +20,6 @@ class SummaryModelTest extends DataFlow::FunctionModel {
this.hasQualifiedName("github.com/nonexistent/test", "FunctionWithVarArgsParameter") and this.hasQualifiedName("github.com/nonexistent/test", "FunctionWithVarArgsParameter") and
(inp.isParameter(_) and outp.isResult()) (inp.isParameter(_) and outp.isResult())
or or
this.hasQualifiedName("github.com/nonexistent/test", "FunctionWithVarArgsOutParameter") and
(inp.isParameter(0) and outp.isParameter(any(int i | i >= 1)))
or
this.hasQualifiedName("github.com/nonexistent/test", "FunctionWithSliceOfStructsParameter") and this.hasQualifiedName("github.com/nonexistent/test", "FunctionWithSliceOfStructsParameter") and
(inp.isParameter(0) and outp.isResult()) (inp.isParameter(0) and outp.isResult())
or or

View File

@@ -1,5 +1,5 @@
module semmle.go.Packages module semmle.go.Packages
go 1.25 go 1.17
require github.com/nonexistent/test v0.0.0-20200203000000-0000000000000 require github.com/nonexistent/test v0.0.0-20200203000000-0000000000000

View File

@@ -8,7 +8,7 @@ func source() string {
return "untrusted data" return "untrusted data"
} }
func sink(any) { func sink(string) {
} }
func main() { func main() {
@@ -21,17 +21,10 @@ func main() {
s0 := "" s0 := ""
s1 := source() s1 := source()
sSlice := []string{s0, s1} sSlice := []string{s0, s1}
sink(test.FunctionWithParameter(sSlice[1])) // $ hasValueFlow="call to FunctionWithParameter" sink(test.FunctionWithParameter(sSlice[1])) // $ hasValueFlow="call to FunctionWithParameter"
sink(test.FunctionWithSliceParameter(sSlice)) // $ hasTaintFlow="call to FunctionWithSliceParameter" MISSING: hasValueFlow="call to FunctionWithSliceParameter" sink(test.FunctionWithSliceParameter(sSlice)) // $ hasTaintFlow="call to FunctionWithSliceParameter" MISSING: hasValueFlow="call to FunctionWithSliceParameter"
sink(test.FunctionWithVarArgsParameter(sSlice...)) // $ hasTaintFlow="call to FunctionWithVarArgsParameter" MISSING: hasValueFlow="call to FunctionWithVarArgsParameter" sink(test.FunctionWithVarArgsParameter(sSlice...)) // $ hasTaintFlow="call to FunctionWithVarArgsParameter" MISSING: hasValueFlow="call to FunctionWithVarArgsParameter"
randomFunctionWithMoreThanOneParameter(1, 2, 3, 4, 5) // This is needed to make the next line pass, because we need to have seen a call to a function with at least 2 parameters for ParameterInput to exist with index 1. sink(test.FunctionWithVarArgsParameter(s0, s1)) // $ MISSING: hasValueFlow="call to FunctionWithVarArgsParameter"
sink(test.FunctionWithVarArgsParameter(s0, s1)) // $ hasValueFlow="call to FunctionWithVarArgsParameter"
var out1 *string
var out2 *string
test.FunctionWithVarArgsOutParameter(source(), out1, out2)
sink(out1) // $ hasValueFlow="out1"
sink(out2) // $ hasValueFlow="out2"
sliceOfStructs := []test.A{{Field: source()}} sliceOfStructs := []test.A{{Field: source()}}
sink(sliceOfStructs[0].Field) // $ hasValueFlow="selection of Field" sink(sliceOfStructs[0].Field) // $ hasValueFlow="selection of Field"
@@ -44,6 +37,3 @@ func main() {
sink(test.FunctionWithVarArgsOfStructsParameter(aSlice...)) // $ MISSING: hasValueFlow="call to FunctionWithVarArgsOfStructsParameter" sink(test.FunctionWithVarArgsOfStructsParameter(aSlice...)) // $ MISSING: hasValueFlow="call to FunctionWithVarArgsOfStructsParameter"
sink(test.FunctionWithVarArgsOfStructsParameter(a0, a1)) // $ MISSING: hasValueFlow="call to FunctionWithVarArgsOfStructsParameter" sink(test.FunctionWithVarArgsOfStructsParameter(a0, a1)) // $ MISSING: hasValueFlow="call to FunctionWithVarArgsOfStructsParameter"
} }
func randomFunctionWithMoreThanOneParameter(i1, i2, i3, i4, i5 int) {
}

View File

@@ -16,9 +16,6 @@ func FunctionWithVarArgsParameter(s ...string) string {
return "" return ""
} }
func FunctionWithVarArgsOutParameter(in string, out ...*string) {
}
func FunctionWithSliceOfStructsParameter(s []A) string { func FunctionWithSliceOfStructsParameter(s []A) string {
return "" return ""
} }

View File

@@ -1,4 +1,2 @@
query: Security/CWE-089/SqlInjection.ql query: Security/CWE-089/SqlInjection.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,4 +1,2 @@
query: Security/CWE-079/StoredXss.ql query: Security/CWE-079/StoredXss.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -8,61 +8,61 @@ import (
// BAD: using untrusted data in SQL queries // BAD: using untrusted data in SQL queries
func testDbMethods(bdb *orm.DB, untrustedSource *http.Request) { func testDbMethods(bdb *orm.DB, untrustedSource *http.Request) {
untrusted := untrustedSource.UserAgent() // $ Source[go/sql-injection] untrusted := untrustedSource.UserAgent()
bdb.Exec(untrusted) // $ querystring=untrusted Alert[go/sql-injection] bdb.Exec(untrusted) // $ querystring=untrusted
bdb.ExecContext(nil, untrusted) // $ querystring=untrusted Alert[go/sql-injection] bdb.ExecContext(nil, untrusted) // $ querystring=untrusted
bdb.Prepare(untrusted) // $ querystring=untrusted Alert[go/sql-injection] bdb.Prepare(untrusted) // $ querystring=untrusted
bdb.PrepareContext(nil, untrusted) // $ querystring=untrusted Alert[go/sql-injection] bdb.PrepareContext(nil, untrusted) // $ querystring=untrusted
bdb.Query(untrusted) // $ querystring=untrusted Alert[go/sql-injection] bdb.Query(untrusted) // $ querystring=untrusted
bdb.QueryContext(nil, untrusted) // $ querystring=untrusted Alert[go/sql-injection] bdb.QueryContext(nil, untrusted) // $ querystring=untrusted
bdb.QueryRow(untrusted) // $ querystring=untrusted Alert[go/sql-injection] bdb.QueryRow(untrusted) // $ querystring=untrusted
bdb.QueryRowContext(nil, untrusted) // $ querystring=untrusted Alert[go/sql-injection] bdb.QueryRowContext(nil, untrusted) // $ querystring=untrusted
} }
// BAD: using untrusted data to build SQL queries (QueryBuilder does not sanitize its arguments) // BAD: using untrusted data to build SQL queries (QueryBuilder does not sanitize its arguments)
func testQueryBuilderMethods(qb orm.QueryBuilder, untrustedSource *http.Request) { func testQueryBuilderMethods(qb orm.QueryBuilder, untrustedSource *http.Request) {
untrusted := untrustedSource.UserAgent() // $ Source[go/sql-injection] untrusted := untrustedSource.UserAgent()
untrusted2 := untrustedSource.UserAgent() // $ Source[go/sql-injection] untrusted2 := untrustedSource.UserAgent()
qb.Select(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.Select(untrusted) // $ querystring=untrusted
qb.From(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.From(untrusted) // $ querystring=untrusted
qb.InnerJoin(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.InnerJoin(untrusted) // $ querystring=untrusted
qb.LeftJoin(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.LeftJoin(untrusted) // $ querystring=untrusted
qb.RightJoin(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.RightJoin(untrusted) // $ querystring=untrusted
qb.On(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.On(untrusted) // $ querystring=untrusted
qb.Where(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.Where(untrusted) // $ querystring=untrusted
qb.And(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.And(untrusted) // $ querystring=untrusted
qb.Or(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.Or(untrusted) // $ querystring=untrusted
qb.In(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.In(untrusted) // $ querystring=untrusted
qb.OrderBy(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.OrderBy(untrusted) // $ querystring=untrusted
qb.GroupBy(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.GroupBy(untrusted) // $ querystring=untrusted
qb.Having(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.Having(untrusted) // $ querystring=untrusted
qb.Update(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.Update(untrusted) // $ querystring=untrusted
qb.Set(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.Set(untrusted) // $ querystring=untrusted
qb.Delete(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.Delete(untrusted) // $ querystring=untrusted
qb.InsertInto(untrusted, untrusted2) // $ querystring=untrusted querystring=untrusted2 Alert[go/sql-injection] qb.InsertInto(untrusted, untrusted2) // $ querystring=untrusted querystring=untrusted2
qb.Values(untrusted) // $ querystring=untrusted Alert[go/sql-injection] qb.Values(untrusted) // $ querystring=untrusted
qb.Subquery(untrusted, untrusted2) // $ querystring=untrusted querystring=untrusted2 Alert[go/sql-injection] qb.Subquery(untrusted, untrusted2) // $ querystring=untrusted querystring=untrusted2
} }
func testOrmerRaw(ormer orm.Ormer, untrustedSource *http.Request) { func testOrmerRaw(ormer orm.Ormer, untrustedSource *http.Request) {
untrusted := untrustedSource.UserAgent() // $ Source[go/sql-injection] untrusted := untrustedSource.UserAgent()
untrusted2 := untrustedSource.UserAgent() untrusted2 := untrustedSource.UserAgent()
ormer.Raw(untrusted, untrusted2) // $ querystring=untrusted Alert[go/sql-injection] // BAD: using an untrusted string as a query ormer.Raw(untrusted, untrusted2) // $ querystring=untrusted // BAD: using an untrusted string as a query
ormer.Raw("FROM ? SELECT ?", untrusted, untrusted2) // $ querystring="FROM ? SELECT ?" // GOOD: untrusted string used in argument context ormer.Raw("FROM ? SELECT ?", untrusted, untrusted2) // $ querystring="FROM ? SELECT ?" // GOOD: untrusted string used in argument context
} }
func testFilterRaw(querySeter orm.QuerySeter, untrustedSource *http.Request) { func testFilterRaw(querySeter orm.QuerySeter, untrustedSource *http.Request) {
untrusted := untrustedSource.UserAgent() // $ Source[go/sql-injection] untrusted := untrustedSource.UserAgent()
querySeter.FilterRaw(untrusted, "safe") // $ querystring="safe" // GOOD: untrusted used as a column name querySeter.FilterRaw(untrusted, "safe") // $ querystring="safe" // GOOD: untrusted used as a column name
querySeter.FilterRaw("safe", untrusted) // $ querystring=untrusted Alert[go/sql-injection] // BAD: untrusted used as a SQL fragment querySeter.FilterRaw("safe", untrusted) // $ querystring=untrusted // BAD: untrusted used as a SQL fragment
} }
func testConditionRaw(cond orm.Condition, untrustedSource *http.Request) { func testConditionRaw(cond orm.Condition, untrustedSource *http.Request) {
untrusted := untrustedSource.UserAgent() // $ Source[go/sql-injection] untrusted := untrustedSource.UserAgent()
cond.Raw(untrusted, "safe") // $ querystring="safe" // GOOD: untrusted used as a column name cond.Raw(untrusted, "safe") // $ querystring="safe" // GOOD: untrusted used as a column name
cond.Raw("safe", untrusted) // $ querystring=untrusted Alert[go/sql-injection] // BAD: untrusted used as a SQL fragment cond.Raw("safe", untrusted) // $ querystring=untrusted // BAD: untrusted used as a SQL fragment
} }
type SubStruct struct { type SubStruct struct {
@@ -77,90 +77,90 @@ type MyStruct struct {
// BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response // BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response
func testOrmerReads(ormer orm.Ormer, sink http.ResponseWriter) { func testOrmerReads(ormer orm.Ormer, sink http.ResponseWriter) {
obj := MyStruct{} obj := MyStruct{}
ormer.Read(&obj) // $ Source[go/stored-xss] ormer.Read(&obj)
sink.Write([]byte(obj.field)) // $ Alert[go/stored-xss] sink.Write([]byte(obj.field))
sink.Write([]byte(obj.substructs[0].field)) // $ Alert[go/stored-xss] sink.Write([]byte(obj.substructs[0].field))
obj2 := MyStruct{} obj2 := MyStruct{}
ormer.ReadForUpdate(&obj2) // $ Source[go/stored-xss] ormer.ReadForUpdate(&obj2)
sink.Write([]byte(obj2.field)) // $ Alert[go/stored-xss] sink.Write([]byte(obj2.field))
obj3 := MyStruct{} obj3 := MyStruct{}
ormer.ReadOrCreate(&obj3, "arg") // $ Source[go/stored-xss] ormer.ReadOrCreate(&obj3, "arg")
sink.Write([]byte(obj3.field)) // $ Alert[go/stored-xss] sink.Write([]byte(obj3.field))
} }
// BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response // BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response
func testFieldReads(textField *orm.TextField, jsonField *orm.JSONField, jsonbField *orm.JsonbField, sink http.ResponseWriter) { func testFieldReads(textField *orm.TextField, jsonField *orm.JSONField, jsonbField *orm.JsonbField, sink http.ResponseWriter) {
sink.Write([]byte(textField.Value())) // $ Alert[go/stored-xss] sink.Write([]byte(textField.Value()))
sink.Write([]byte(textField.RawValue().(string))) // $ Alert[go/stored-xss] sink.Write([]byte(textField.RawValue().(string)))
sink.Write([]byte(textField.String())) // $ Alert[go/stored-xss] sink.Write([]byte(textField.String()))
sink.Write([]byte(jsonField.Value())) // $ Alert[go/stored-xss] sink.Write([]byte(jsonField.Value()))
sink.Write([]byte(jsonField.RawValue().(string))) // $ Alert[go/stored-xss] sink.Write([]byte(jsonField.RawValue().(string)))
sink.Write([]byte(jsonField.String())) // $ Alert[go/stored-xss] sink.Write([]byte(jsonField.String()))
sink.Write([]byte(jsonbField.Value())) // $ Alert[go/stored-xss] sink.Write([]byte(jsonbField.Value()))
sink.Write([]byte(jsonbField.RawValue().(string))) // $ Alert[go/stored-xss] sink.Write([]byte(jsonbField.RawValue().(string)))
sink.Write([]byte(jsonbField.String())) // $ Alert[go/stored-xss] sink.Write([]byte(jsonbField.String()))
} }
// BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response // BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response
func testQuerySeterReads(qs orm.QuerySeter, sink http.ResponseWriter) { func testQuerySeterReads(qs orm.QuerySeter, sink http.ResponseWriter) {
var objs []*MyStruct var objs []*MyStruct
qs.All(&objs) // $ Source[go/stored-xss] qs.All(&objs)
sink.Write([]byte(objs[0].field)) // $ Alert[go/stored-xss] sink.Write([]byte(objs[0].field))
var obj MyStruct var obj MyStruct
qs.One(&obj) // $ Source[go/stored-xss] qs.One(&obj)
sink.Write([]byte(obj.field)) // $ Alert[go/stored-xss] sink.Write([]byte(obj.field))
var allMaps []orm.Params var allMaps []orm.Params
qs.Values(&allMaps) // $ Source[go/stored-xss] qs.Values(&allMaps)
sink.Write([]byte(allMaps[0]["field"].(string))) // $ Alert[go/stored-xss] sink.Write([]byte(allMaps[0]["field"].(string)))
var allLists []orm.ParamsList var allLists []orm.ParamsList
qs.ValuesList(&allLists) // $ Source[go/stored-xss] qs.ValuesList(&allLists)
sink.Write([]byte(allLists[0][0].(string))) // $ Alert[go/stored-xss] sink.Write([]byte(allLists[0][0].(string)))
var oneList orm.ParamsList var oneList orm.ParamsList
qs.ValuesFlat(&oneList, "colname") // $ Source[go/stored-xss] qs.ValuesFlat(&oneList, "colname")
sink.Write([]byte(oneList[0].(string))) // $ Alert[go/stored-xss] sink.Write([]byte(oneList[0].(string)))
var oneRowMap orm.Params var oneRowMap orm.Params
qs.RowsToMap(&oneRowMap, "key", "value") // $ Source[go/stored-xss] qs.RowsToMap(&oneRowMap, "key", "value")
sink.Write([]byte(oneRowMap["field"].(string))) // $ Alert[go/stored-xss] sink.Write([]byte(oneRowMap["field"].(string)))
var oneRowStruct MyStruct var oneRowStruct MyStruct
qs.RowsToStruct(&oneRowStruct, "key", "value") // $ Source[go/stored-xss] qs.RowsToStruct(&oneRowStruct, "key", "value")
sink.Write([]byte(oneRowStruct.field)) // $ Alert[go/stored-xss] sink.Write([]byte(oneRowStruct.field))
} }
// BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response // BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response
func testRawSeterReads(rs orm.RawSeter, sink http.ResponseWriter) { func testRawSeterReads(rs orm.RawSeter, sink http.ResponseWriter) {
var allMaps []orm.Params var allMaps []orm.Params
rs.Values(&allMaps) // $ Source[go/stored-xss] rs.Values(&allMaps)
sink.Write([]byte(allMaps[0]["field"].(string))) // $ Alert[go/stored-xss] sink.Write([]byte(allMaps[0]["field"].(string)))
var allLists []orm.ParamsList var allLists []orm.ParamsList
rs.ValuesList(&allLists) // $ Source[go/stored-xss] rs.ValuesList(&allLists)
sink.Write([]byte(allLists[0][0].(string))) // $ Alert[go/stored-xss] sink.Write([]byte(allLists[0][0].(string)))
var oneList orm.ParamsList var oneList orm.ParamsList
rs.ValuesFlat(&oneList, "colname") // $ Source[go/stored-xss] rs.ValuesFlat(&oneList, "colname")
sink.Write([]byte(oneList[0].(string))) // $ Alert[go/stored-xss] sink.Write([]byte(oneList[0].(string)))
var oneRowMap orm.Params var oneRowMap orm.Params
rs.RowsToMap(&oneRowMap, "key", "value") // $ Source[go/stored-xss] rs.RowsToMap(&oneRowMap, "key", "value")
sink.Write([]byte(oneRowMap["field"].(string))) // $ Alert[go/stored-xss] sink.Write([]byte(oneRowMap["field"].(string)))
var oneRowStruct MyStruct var oneRowStruct MyStruct
rs.RowsToStruct(&oneRowStruct, "key", "value") // $ Source[go/stored-xss] rs.RowsToStruct(&oneRowStruct, "key", "value")
sink.Write([]byte(oneRowStruct.field)) // $ Alert[go/stored-xss] sink.Write([]byte(oneRowStruct.field))
var strField string var strField string
rs.QueryRow(&strField) // $ Source[go/stored-xss] rs.QueryRow(&strField)
sink.Write([]byte(strField)) // $ Alert[go/stored-xss] sink.Write([]byte(strField))
var strFields []string var strFields []string
rs.QueryRows(&strFields) // $ Source[go/stored-xss] rs.QueryRows(&strFields)
sink.Write([]byte(strFields[0])) // $ Alert[go/stored-xss] sink.Write([]byte(strFields[0]))
} }

View File

@@ -1,4 +1,2 @@
query: Security/CWE-079/ReflectedXss.ql query: Security/CWE-079/ReflectedXss.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -10,7 +10,7 @@ var hidden string
func hideUserData(next http.Handler) http.Handler { func hideUserData(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
hidden = r.URL.Path // $ Source hidden = r.URL.Path
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })
} }
@@ -18,10 +18,10 @@ func hideUserData(next http.Handler) http.Handler {
func main() { func main() {
r := chi.NewRouter() r := chi.NewRouter()
r.With(hideUserData).Get("/", func(w http.ResponseWriter, r *http.Request) { r.With(hideUserData).Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(hidden)) // $ Alert w.Write([]byte(hidden))
w.Write([]byte(chi.URLParam(r, "someParam"))) // $ Alert w.Write([]byte(chi.URLParam(r, "someParam")))
w.Write([]byte(chi.URLParamFromCtx(r.Context(), "someKey"))) // $ Alert w.Write([]byte(chi.URLParamFromCtx(r.Context(), "someKey")))
w.Write([]byte(chi.RouteContext(r.Context()).URLParam("someOtherKey"))) // $ Alert w.Write([]byte(chi.RouteContext(r.Context()).URLParam("someOtherKey")))
}) })
http.ListenAndServe(":3000", r) http.ListenAndServe(":3000", r)
} }

View File

@@ -1,4 +1,2 @@
query: Security/CWE-601/OpenUrlRedirect.ql query: Security/CWE-601/OpenUrlRedirect.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,4 +1,2 @@
query: Security/CWE-079/ReflectedXss.ql query: Security/CWE-079/ReflectedXss.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,4 +1,2 @@
query: Security/CWE-022/TaintedPath.ql query: Security/CWE-022/TaintedPath.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -12,81 +12,81 @@ import (
// All are XSS vulnerabilities, except as specifically noted. // All are XSS vulnerabilities, except as specifically noted.
func testParam(ctx echo.Context) error { func testParam(ctx echo.Context) error {
param := ctx.Param("someParam") // $ Source[go/reflected-xss] param := ctx.Param("someParam")
ctx.HTML(200, param) // $ Alert[go/reflected-xss] ctx.HTML(200, param)
return nil return nil
} }
func testParamValues(ctx echo.Context) error { func testParamValues(ctx echo.Context) error {
param := ctx.ParamValues()[0] // $ Source[go/reflected-xss] param := ctx.ParamValues()[0]
ctx.HTML(200, param) // $ Alert[go/reflected-xss] ctx.HTML(200, param)
return nil return nil
} }
func testQueryParam(ctx echo.Context) error { func testQueryParam(ctx echo.Context) error {
param := ctx.QueryParam("someParam") // $ Source[go/reflected-xss] param := ctx.QueryParam("someParam")
ctx.HTML(200, param) // $ Alert[go/reflected-xss] ctx.HTML(200, param)
return nil return nil
} }
func testQueryParams(ctx echo.Context) error { func testQueryParams(ctx echo.Context) error {
param := ctx.QueryParams()["someParam"][0] // $ Source[go/reflected-xss] param := ctx.QueryParams()["someParam"][0]
ctx.HTML(200, param) // $ Alert[go/reflected-xss] ctx.HTML(200, param)
return nil return nil
} }
func testQueryString(ctx echo.Context) error { func testQueryString(ctx echo.Context) error {
qstr := ctx.QueryString() // $ Source[go/reflected-xss] qstr := ctx.QueryString()
ctx.HTML(200, qstr) // $ Alert[go/reflected-xss] ctx.HTML(200, qstr)
return nil return nil
} }
func testFormValue(ctx echo.Context) error { func testFormValue(ctx echo.Context) error {
val := ctx.FormValue("someField") // $ Source[go/reflected-xss] val := ctx.FormValue("someField")
ctx.HTML(200, val) // $ Alert[go/reflected-xss] ctx.HTML(200, val)
return nil return nil
} }
func testFormParams(ctx echo.Context) error { func testFormParams(ctx echo.Context) error {
params, _ := ctx.FormParams() // $ Source[go/reflected-xss] params, _ := ctx.FormParams()
ctx.HTML(200, params["someField"][0]) // $ Alert[go/reflected-xss] ctx.HTML(200, params["someField"][0])
return nil return nil
} }
func testFormFile(ctx echo.Context) error { func testFormFile(ctx echo.Context) error {
fileHeader, _ := ctx.FormFile("someFilename") // $ Source[go/reflected-xss] fileHeader, _ := ctx.FormFile("someFilename")
file, _ := fileHeader.Open() file, _ := fileHeader.Open()
buffer := make([]byte, 100) buffer := make([]byte, 100)
file.Read(buffer) file.Read(buffer)
ctx.HTMLBlob(200, buffer) // $ Alert[go/reflected-xss] ctx.HTMLBlob(200, buffer)
return nil return nil
} }
func testMultipartFormValue(ctx echo.Context) error { func testMultipartFormValue(ctx echo.Context) error {
form, _ := ctx.MultipartForm() // $ Source[go/reflected-xss] form, _ := ctx.MultipartForm()
ctx.HTML(200, form.Value["someField"][0]) // $ Alert[go/reflected-xss] ctx.HTML(200, form.Value["someField"][0])
return nil return nil
} }
func testMultipartFormFile(ctx echo.Context) error { func testMultipartFormFile(ctx echo.Context) error {
form, _ := ctx.MultipartForm() // $ Source[go/reflected-xss] form, _ := ctx.MultipartForm()
fileHeader := form.File["someFilename"][0] fileHeader := form.File["someFilename"][0]
file, _ := fileHeader.Open() file, _ := fileHeader.Open()
buffer := make([]byte, 100) buffer := make([]byte, 100)
file.Read(buffer) file.Read(buffer)
ctx.HTMLBlob(200, buffer) // $ Alert[go/reflected-xss] ctx.HTMLBlob(200, buffer)
return nil return nil
} }
func testCookie(ctx echo.Context) error { func testCookie(ctx echo.Context) error {
val, _ := ctx.Cookie("someKey") // $ Source[go/reflected-xss] val, _ := ctx.Cookie("someKey")
ctx.HTML(200, val.Value) // $ Alert[go/reflected-xss] ctx.HTML(200, val.Value)
return nil return nil
} }
func testCookies(ctx echo.Context) error { func testCookies(ctx echo.Context) error {
cookies := ctx.Cookies() // $ Source[go/reflected-xss] cookies := ctx.Cookies()
ctx.HTML(200, cookies[0].Value) // $ Alert[go/reflected-xss] ctx.HTML(200, cookies[0].Value)
return nil return nil
} }
@@ -96,8 +96,8 @@ type myStruct struct {
func testBind(ctx echo.Context) error { func testBind(ctx echo.Context) error {
data := myStruct{} data := myStruct{}
ctx.Bind(&data) // $ Source[go/reflected-xss] ctx.Bind(&data)
ctx.HTML(200, data.s) // $ Alert[go/reflected-xss] ctx.HTML(200, data.s)
return nil return nil
} }
@@ -110,8 +110,8 @@ func testGetSetEmpty(ctx echo.Context) error {
} }
func testGetSet(ctx echo.Context) error { func testGetSet(ctx echo.Context) error {
ctx.Set("someKey", ctx.Param("someParam")) // $ Source[go/reflected-xss] ctx.Set("someKey", ctx.Param("someParam"))
ctx.HTML(200, ctx.Get("someKey").(string)) // $ Alert[go/reflected-xss] // BAD, the context is tainted ctx.HTML(200, ctx.Get("someKey").(string)) // BAD, the context is tainted
return nil return nil
} }
@@ -121,20 +121,20 @@ func testGetSet(ctx echo.Context) error {
// All are XSS vulnerabilities, except as specifically noted. // All are XSS vulnerabilities, except as specifically noted.
func testHTML(ctx echo.Context) error { func testHTML(ctx echo.Context) error {
param := ctx.Param("someParam") // $ Source[go/reflected-xss] param := ctx.Param("someParam")
ctx.HTML(200, param) // $ Alert[go/reflected-xss] ctx.HTML(200, param)
return nil return nil
} }
func testHTMLBlob(ctx echo.Context) error { func testHTMLBlob(ctx echo.Context) error {
param := ctx.Param("someParam") // $ Source[go/reflected-xss] param := ctx.Param("someParam")
ctx.HTMLBlob(200, []byte(param)) // $ Alert[go/reflected-xss] ctx.HTMLBlob(200, []byte(param))
return nil return nil
} }
func testBlob(ctx echo.Context) error { func testBlob(ctx echo.Context) error {
param := ctx.Param("someParam") // $ Source[go/reflected-xss] param := ctx.Param("someParam")
ctx.Blob(200, "text/html", []byte(param)) // $ Alert[go/reflected-xss] // BAD, the content-type is HTML ctx.Blob(200, "text/html", []byte(param)) // BAD, the content-type is HTML
return nil return nil
} }
@@ -145,9 +145,9 @@ func testBlobSafe(ctx echo.Context) error {
} }
func testStream(ctx echo.Context) error { func testStream(ctx echo.Context) error {
param := ctx.Param("someParam") // $ Source[go/reflected-xss] param := ctx.Param("someParam")
reader := strings.NewReader(param) reader := strings.NewReader(param)
ctx.Stream(200, "text/html", reader) // $ Alert[go/reflected-xss] // BAD, the content-type is HTML ctx.Stream(200, "text/html", reader) // BAD, the content-type is HTML
return nil return nil
} }
@@ -161,28 +161,28 @@ func testStreamSafe(ctx echo.Context) error {
// Section: testing output methods defined on Response (XSS vulnerability) // Section: testing output methods defined on Response (XSS vulnerability)
func testResponseWrite(ctx echo.Context) error { func testResponseWrite(ctx echo.Context) error {
param := ctx.Param("someParam") // $ Source[go/reflected-xss] param := ctx.Param("someParam")
ctx.Response().Write([]byte(param)) // $ Alert[go/reflected-xss] ctx.Response().Write([]byte(param))
return nil return nil
} }
// Section: test detecting an open redirect using the Context.Redirect function: // Section: test detecting an open redirect using the Context.Redirect function:
func testRedirect(ctx echo.Context) error { func testRedirect(ctx echo.Context) error {
param := ctx.Param("someParam") // $ Source[go/unvalidated-url-redirection] param := ctx.Param("someParam")
ctx.Redirect(301, param) // $ Alert[go/unvalidated-url-redirection] ctx.Redirect(301, param)
return nil return nil
} }
func testLocalRedirects(ctx echo.Context) error { func testLocalRedirects(ctx echo.Context) error {
param := ctx.Param("someParam") // $ Source[go/unvalidated-url-redirection] param := ctx.Param("someParam")
param2 := param param2 := param
param3 := param param3 := param
// Gratuitous copy because sanitization of uses propagates to subsequent uses // Gratuitous copy because sanitization of uses propagates to subsequent uses
// GOOD: local redirects are unproblematic // GOOD: local redirects are unproblematic
ctx.Redirect(301, "/local"+param) ctx.Redirect(301, "/local"+param)
// BAD: this could be a non-local redirect // BAD: this could be a non-local redirect
ctx.Redirect(301, "/"+param2) // $ Alert[go/unvalidated-url-redirection] ctx.Redirect(301, "/"+param2)
// GOOD: localhost redirects are unproblematic // GOOD: localhost redirects are unproblematic
ctx.Redirect(301, "//localhost/"+param3) ctx.Redirect(301, "//localhost/"+param3)
return nil return nil
@@ -221,12 +221,12 @@ func testNonExploitableFields(ctx echo.Context) error {
func fsOpsTest() { func fsOpsTest() {
e := echo.New() e := echo.New()
e.GET("/", func(c echo.Context) error { e.GET("/", func(c echo.Context) error {
filepath := c.QueryParam("filePath") // $ Source[go/path-injection] filepath := c.QueryParam("filePath")
return c.File(filepath) // $ FileSystemAccess=filepath Alert[go/path-injection] return c.File(filepath) // $ FileSystemAccess=filepath
}) })
e.GET("/attachment", func(c echo.Context) error { e.GET("/attachment", func(c echo.Context) error {
filepath := c.QueryParam("filePath") // $ Source[go/path-injection] filepath := c.QueryParam("filePath")
return c.Attachment(filepath, "file name in response") // $ FileSystemAccess=filepath Alert[go/path-injection] return c.Attachment(filepath, "file name in response") // $ FileSystemAccess=filepath
}) })
_ = e.Start(":1323") _ = e.Start(":1323")
} }

View File

@@ -1,8 +1,8 @@
#select
| main.go:21:28:21:31 | name | main.go:18:46:18:48 | definition of req | main.go:21:28:21:31 | name | This log entry depends on a $@. | main.go:18:46:18:48 | definition of req | user-provided value |
edges edges
| main.go:18:46:18:48 | definition of req | main.go:21:28:21:31 | name | provenance | | | main.go:18:46:18:48 | definition of req | main.go:21:28:21:31 | name | provenance | |
nodes nodes
| main.go:18:46:18:48 | definition of req | semmle.label | definition of req | | main.go:18:46:18:48 | definition of req | semmle.label | definition of req |
| main.go:21:28:21:31 | name | semmle.label | name | | main.go:21:28:21:31 | name | semmle.label | name |
subpaths subpaths
#select
| main.go:21:28:21:31 | name | main.go:18:46:18:48 | definition of req | main.go:21:28:21:31 | name | This log entry depends on a $@. | main.go:18:46:18:48 | definition of req | user-provided value |

View File

@@ -1,2 +1 @@
query: Security/CWE-117/LogInjection.ql Security/CWE-117/LogInjection.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -15,10 +15,10 @@ import (
type Greeter struct{} type Greeter struct{}
func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error { // $ serverRequest="definition of req" Source func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error { // $ serverRequest="definition of req"
// var access // var access
name := req.Name name := req.Name
fmt.Println("Name :: %s", name) // $ Alert fmt.Println("Name :: %s", name)
return nil return nil
} }

View File

@@ -1,28 +1,28 @@
reverseRead reverseRead
| EndToEnd.go:31:35:31:35 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:30:35:30:35 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:31:35:31:42 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:30:35:30:42 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:37:18:37:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:36:18:36:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:37:18:37:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:36:18:36:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:45:18:45:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:44:18:44:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:45:18:45:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:44:18:44:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:52:20:52:20 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:51:20:51:20 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:52:20:52:27 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:51:20:51:27 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:59:18:59:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:58:18:58:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:59:18:59:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:58:18:58:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:65:26:65:26 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:64:26:64:26 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:65:26:65:33 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:64:26:64:33 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:70:22:70:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:69:22:69:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:70:22:70:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:69:22:69:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:75:22:75:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:74:22:74:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:75:22:75:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:74:22:74:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:80:35:80:35 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:79:35:79:35 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:80:35:80:42 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:79:35:79:42 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:85:22:85:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:84:22:84:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:85:22:85:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:84:22:84:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:90:21:90:21 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:89:21:89:21 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:90:21:90:28 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:89:21:89:28 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:95:20:95:20 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:94:20:94:20 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| EndToEnd.go:95:20:95:27 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | EndToEnd.go:94:20:94:27 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| Revel.go:26:7:26:7 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | Revel.go:26:7:26:7 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| Revel.go:27:7:27:7 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | Revel.go:27:7:27:7 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. |
| Revel.go:27:7:27:14 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | Revel.go:27:7:27:14 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |

View File

@@ -3,11 +3,10 @@ package main
import ( import (
"bytes" "bytes"
"errors" "errors"
"os"
"time"
staticControllers "github.com/revel/modules/static/app/controllers" staticControllers "github.com/revel/modules/static/app/controllers"
"github.com/revel/revel" "github.com/revel/revel"
"os"
"time"
) )
// Use typical inheritence pattern, per github.com/revel/examples/booking: // Use typical inheritence pattern, per github.com/revel/examples/booking:
@@ -34,8 +33,8 @@ func (c MyRoute) Handler1() revel.Result {
func (c MyRoute) Handler2() revel.Result { func (c MyRoute) Handler2() revel.Result {
// BAD: the RenderBinary function copies an `io.Reader` to the user's browser. // BAD: the RenderBinary function copies an `io.Reader` to the user's browser.
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
buf.WriteString(c.Params.Form.Get("someField")) // $ Source[go/reflected-xss] buf.WriteString(c.Params.Form.Get("someField"))
return c.RenderBinary(buf, "index.html", revel.Inline, time.Now()) // $ responsebody='buf' Alert[go/reflected-xss] return c.RenderBinary(buf, "index.html", revel.Inline, time.Now()) // $ responsebody='buf'
} }
func (c MyRoute) Handler3() revel.Result { func (c MyRoute) Handler3() revel.Result {
@@ -56,18 +55,18 @@ func (c MyRoute) Handler4() revel.Result {
func (c MyRoute) Handler5() revel.Result { func (c MyRoute) Handler5() revel.Result {
// BAD: returning an arbitrary file (but this is detected at the os.Open call, not // BAD: returning an arbitrary file (but this is detected at the os.Open call, not
// due to modelling Revel) // due to modelling Revel)
f, _ := os.Open(c.Params.Form.Get("someField")) // $ Alert[go/path-injection] f, _ := os.Open(c.Params.Form.Get("someField"))
return c.RenderFile(f, revel.Inline) return c.RenderFile(f, revel.Inline)
} }
func (c MyRoute) Handler6() revel.Result { func (c MyRoute) Handler6() revel.Result {
// BAD: returning an arbitrary file (detected as a user-controlled file-op, not XSS) // BAD: returning an arbitrary file (detected as a user-controlled file-op, not XSS)
return c.RenderFileName(c.Params.Form.Get("someField"), revel.Inline) // $ Alert[go/path-injection] return c.RenderFileName(c.Params.Form.Get("someField"), revel.Inline)
} }
func (c MyRoute) Handler7() revel.Result { func (c MyRoute) Handler7() revel.Result {
// BAD: straightforward XSS // BAD: straightforward XSS
return c.RenderHTML(c.Params.Form.Get("someField")) // $ responsebody='call to Get' Alert[go/reflected-xss] return c.RenderHTML(c.Params.Form.Get("someField")) // $ responsebody='call to Get'
} }
func (c MyRoute) Handler8() revel.Result { func (c MyRoute) Handler8() revel.Result {
@@ -92,5 +91,5 @@ func (c MyRoute) Handler11() revel.Result {
func (c MyRoute) Handler12() revel.Result { func (c MyRoute) Handler12() revel.Result {
// BAD: open redirect // BAD: open redirect
return c.Redirect(c.Params.Form.Get("someField")) // $ Alert[go/unvalidated-url-redirection] return c.Redirect(c.Params.Form.Get("someField"))
} }

View File

@@ -1,19 +1,19 @@
#select #select
| EndToEnd.go:95:20:95:49 | call to Get | EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:49 | call to Get | This path to an untrusted URL redirection depends on a $@. | EndToEnd.go:95:20:95:27 | selection of Params | user-provided value | | EndToEnd.go:94:20:94:49 | call to Get | EndToEnd.go:94:20:94:27 | selection of Params | EndToEnd.go:94:20:94:49 | call to Get | This path to an untrusted URL redirection depends on a $@. | EndToEnd.go:94:20:94:27 | selection of Params | user-provided value |
edges edges
| EndToEnd.go:95:20:95:27 | implicit dereference | EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | provenance | Config | | EndToEnd.go:94:20:94:27 | implicit dereference | EndToEnd.go:94:20:94:27 | selection of Params [postupdate] | provenance | Config |
| EndToEnd.go:95:20:95:27 | implicit dereference | EndToEnd.go:95:20:95:32 | selection of Form | provenance | Config | | EndToEnd.go:94:20:94:27 | implicit dereference | EndToEnd.go:94:20:94:32 | selection of Form | provenance | Config |
| EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:27 | implicit dereference | provenance | Src:MaD:2 Config | | EndToEnd.go:94:20:94:27 | selection of Params | EndToEnd.go:94:20:94:27 | implicit dereference | provenance | Src:MaD:2 Config |
| EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:32 | selection of Form | provenance | Src:MaD:2 Config | | EndToEnd.go:94:20:94:27 | selection of Params | EndToEnd.go:94:20:94:32 | selection of Form | provenance | Src:MaD:2 Config |
| EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | EndToEnd.go:95:20:95:27 | implicit dereference | provenance | Config | | EndToEnd.go:94:20:94:27 | selection of Params [postupdate] | EndToEnd.go:94:20:94:27 | implicit dereference | provenance | Config |
| EndToEnd.go:95:20:95:32 | selection of Form | EndToEnd.go:95:20:95:49 | call to Get | provenance | Config Sink:MaD:1 | | EndToEnd.go:94:20:94:32 | selection of Form | EndToEnd.go:94:20:94:49 | call to Get | provenance | Config Sink:MaD:1 |
models models
| 1 | Sink: group:revel; Controller; true; Redirect; ; ; Argument[0]; url-redirection; manual | | 1 | Sink: group:revel; Controller; true; Redirect; ; ; Argument[0]; url-redirection; manual |
| 2 | Source: group:revel; Controller; true; Params; ; ; ; remote; manual | | 2 | Source: group:revel; Controller; true; Params; ; ; ; remote; manual |
nodes nodes
| EndToEnd.go:95:20:95:27 | implicit dereference | semmle.label | implicit dereference | | EndToEnd.go:94:20:94:27 | implicit dereference | semmle.label | implicit dereference |
| EndToEnd.go:95:20:95:27 | selection of Params | semmle.label | selection of Params | | EndToEnd.go:94:20:94:27 | selection of Params | semmle.label | selection of Params |
| EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | semmle.label | selection of Params [postupdate] | | EndToEnd.go:94:20:94:27 | selection of Params [postupdate] | semmle.label | selection of Params [postupdate] |
| EndToEnd.go:95:20:95:32 | selection of Form | semmle.label | selection of Form | | EndToEnd.go:94:20:94:32 | selection of Form | semmle.label | selection of Form |
| EndToEnd.go:95:20:95:49 | call to Get | semmle.label | call to Get | | EndToEnd.go:94:20:94:49 | call to Get | semmle.label | call to Get |
subpaths subpaths

View File

@@ -1,4 +1,2 @@
query: Security/CWE-601/OpenUrlRedirect.ql query: Security/CWE-601/OpenUrlRedirect.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,16 +1,16 @@
#select #select
| EndToEnd.go:38:24:38:26 | buf | EndToEnd.go:37:18:37:25 | selection of Params | EndToEnd.go:38:24:38:26 | buf | Cross-site scripting vulnerability due to $@. | EndToEnd.go:37:18:37:25 | selection of Params | user-provided value | EndToEnd.go:0:0:0:0 | EndToEnd.go | | | EndToEnd.go:37:24:37:26 | buf | EndToEnd.go:36:18:36:25 | selection of Params | EndToEnd.go:37:24:37:26 | buf | Cross-site scripting vulnerability due to $@. | EndToEnd.go:36:18:36:25 | selection of Params | user-provided value | EndToEnd.go:0:0:0:0 | EndToEnd.go | |
| EndToEnd.go:70:22:70:51 | call to Get | EndToEnd.go:70:22:70:29 | selection of Params | EndToEnd.go:70:22:70:51 | call to Get | Cross-site scripting vulnerability due to $@. | EndToEnd.go:70:22:70:29 | selection of Params | user-provided value | EndToEnd.go:0:0:0:0 | EndToEnd.go | | | EndToEnd.go:69:22:69:51 | call to Get | EndToEnd.go:69:22:69:29 | selection of Params | EndToEnd.go:69:22:69:51 | call to Get | Cross-site scripting vulnerability due to $@. | EndToEnd.go:69:22:69:29 | selection of Params | user-provided value | EndToEnd.go:0:0:0:0 | EndToEnd.go | |
| Revel.go:70:22:70:35 | selection of Query | Revel.go:70:22:70:29 | selection of Params | Revel.go:70:22:70:35 | selection of Query | Cross-site scripting vulnerability due to $@. The value is $@. | Revel.go:70:22:70:29 | selection of Params | user-provided value | views/myAppController/rawRead.html:1:1:2:9 | {{raw .Foo}}\n{{.Bar}}\n | instantiated as a raw template | | Revel.go:70:22:70:35 | selection of Query | Revel.go:70:22:70:29 | selection of Params | Revel.go:70:22:70:35 | selection of Query | Cross-site scripting vulnerability due to $@. The value is $@. | Revel.go:70:22:70:29 | selection of Params | user-provided value | views/myAppController/rawRead.html:1:1:2:9 | {{raw .Foo}}\n{{.Bar}}\n | instantiated as a raw template |
| examples/booking/app/init.go:36:44:36:53 | selection of Path | examples/booking/app/init.go:36:44:36:48 | selection of URL | examples/booking/app/init.go:36:44:36:53 | selection of Path | Cross-site scripting vulnerability due to $@. | examples/booking/app/init.go:36:44:36:48 | selection of URL | user-provided value | examples/booking/app/init.go:0:0:0:0 | examples/booking/app/init.go | | | examples/booking/app/init.go:36:44:36:53 | selection of Path | examples/booking/app/init.go:36:44:36:48 | selection of URL | examples/booking/app/init.go:36:44:36:53 | selection of Path | Cross-site scripting vulnerability due to $@. | examples/booking/app/init.go:36:44:36:48 | selection of URL | user-provided value | examples/booking/app/init.go:0:0:0:0 | examples/booking/app/init.go | |
| examples/booking/app/init.go:40:49:40:58 | selection of Path | examples/booking/app/init.go:40:49:40:53 | selection of URL | examples/booking/app/init.go:40:49:40:58 | selection of Path | Cross-site scripting vulnerability due to $@. | examples/booking/app/init.go:40:49:40:53 | selection of URL | user-provided value | examples/booking/app/init.go:0:0:0:0 | examples/booking/app/init.go | | | examples/booking/app/init.go:40:49:40:58 | selection of Path | examples/booking/app/init.go:40:49:40:53 | selection of URL | examples/booking/app/init.go:40:49:40:58 | selection of Path | Cross-site scripting vulnerability due to $@. | examples/booking/app/init.go:40:49:40:53 | selection of URL | user-provided value | examples/booking/app/init.go:0:0:0:0 | examples/booking/app/init.go | |
edges edges
| EndToEnd.go:37:2:37:4 | buf [postupdate] | EndToEnd.go:38:24:38:26 | buf | provenance | | | EndToEnd.go:36:2:36:4 | buf [postupdate] | EndToEnd.go:37:24:37:26 | buf | provenance | |
| EndToEnd.go:37:18:37:25 | selection of Params | EndToEnd.go:37:18:37:30 | selection of Form | provenance | Src:MaD:1 | | EndToEnd.go:36:18:36:25 | selection of Params | EndToEnd.go:36:18:36:30 | selection of Form | provenance | Src:MaD:1 |
| EndToEnd.go:37:18:37:30 | selection of Form | EndToEnd.go:37:18:37:47 | call to Get | provenance | MaD:4 | | EndToEnd.go:36:18:36:30 | selection of Form | EndToEnd.go:36:18:36:47 | call to Get | provenance | MaD:4 |
| EndToEnd.go:37:18:37:47 | call to Get | EndToEnd.go:37:2:37:4 | buf [postupdate] | provenance | MaD:3 | | EndToEnd.go:36:18:36:47 | call to Get | EndToEnd.go:36:2:36:4 | buf [postupdate] | provenance | MaD:3 |
| EndToEnd.go:70:22:70:29 | selection of Params | EndToEnd.go:70:22:70:34 | selection of Form | provenance | Src:MaD:1 | | EndToEnd.go:69:22:69:29 | selection of Params | EndToEnd.go:69:22:69:34 | selection of Form | provenance | Src:MaD:1 |
| EndToEnd.go:70:22:70:34 | selection of Form | EndToEnd.go:70:22:70:51 | call to Get | provenance | MaD:4 | | EndToEnd.go:69:22:69:34 | selection of Form | EndToEnd.go:69:22:69:51 | call to Get | provenance | MaD:4 |
| Revel.go:70:22:70:29 | selection of Params | Revel.go:70:22:70:35 | selection of Query | provenance | Src:MaD:1 | | Revel.go:70:22:70:29 | selection of Params | Revel.go:70:22:70:35 | selection of Query | provenance | Src:MaD:1 |
| examples/booking/app/init.go:36:44:36:48 | selection of URL | examples/booking/app/init.go:36:44:36:53 | selection of Path | provenance | Src:MaD:2 | | examples/booking/app/init.go:36:44:36:48 | selection of URL | examples/booking/app/init.go:36:44:36:53 | selection of Path | provenance | Src:MaD:2 |
| examples/booking/app/init.go:40:49:40:53 | selection of URL | examples/booking/app/init.go:40:49:40:58 | selection of Path | provenance | Src:MaD:2 | | examples/booking/app/init.go:40:49:40:53 | selection of URL | examples/booking/app/init.go:40:49:40:58 | selection of Path | provenance | Src:MaD:2 |
@@ -20,14 +20,14 @@ models
| 3 | Summary: io; StringWriter; true; WriteString; ; ; Argument[0]; Argument[receiver]; taint; manual | | 3 | Summary: io; StringWriter; true; WriteString; ; ; Argument[0]; Argument[receiver]; taint; manual |
| 4 | Summary: net/url; Values; true; Get; ; ; Argument[receiver]; ReturnValue; taint; manual | | 4 | Summary: net/url; Values; true; Get; ; ; Argument[receiver]; ReturnValue; taint; manual |
nodes nodes
| EndToEnd.go:37:2:37:4 | buf [postupdate] | semmle.label | buf [postupdate] | | EndToEnd.go:36:2:36:4 | buf [postupdate] | semmle.label | buf [postupdate] |
| EndToEnd.go:37:18:37:25 | selection of Params | semmle.label | selection of Params | | EndToEnd.go:36:18:36:25 | selection of Params | semmle.label | selection of Params |
| EndToEnd.go:37:18:37:30 | selection of Form | semmle.label | selection of Form | | EndToEnd.go:36:18:36:30 | selection of Form | semmle.label | selection of Form |
| EndToEnd.go:37:18:37:47 | call to Get | semmle.label | call to Get | | EndToEnd.go:36:18:36:47 | call to Get | semmle.label | call to Get |
| EndToEnd.go:38:24:38:26 | buf | semmle.label | buf | | EndToEnd.go:37:24:37:26 | buf | semmle.label | buf |
| EndToEnd.go:70:22:70:29 | selection of Params | semmle.label | selection of Params | | EndToEnd.go:69:22:69:29 | selection of Params | semmle.label | selection of Params |
| EndToEnd.go:70:22:70:34 | selection of Form | semmle.label | selection of Form | | EndToEnd.go:69:22:69:34 | selection of Form | semmle.label | selection of Form |
| EndToEnd.go:70:22:70:51 | call to Get | semmle.label | call to Get | | EndToEnd.go:69:22:69:51 | call to Get | semmle.label | call to Get |
| Revel.go:70:22:70:29 | selection of Params | semmle.label | selection of Params | | Revel.go:70:22:70:29 | selection of Params | semmle.label | selection of Params |
| Revel.go:70:22:70:35 | selection of Query | semmle.label | selection of Query | | Revel.go:70:22:70:35 | selection of Query | semmle.label | selection of Query |
| examples/booking/app/init.go:36:44:36:48 | selection of URL | semmle.label | selection of URL | | examples/booking/app/init.go:36:44:36:48 | selection of URL | semmle.label | selection of URL |

View File

@@ -1,4 +1,2 @@
query: Security/CWE-079/ReflectedXss.ql query: Security/CWE-079/ReflectedXss.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -67,7 +67,7 @@ func (c myAppController) accessingParamsJSONIsUnsafe() {
func (c myAppController) rawRead() { // $ responsebody='argument corresponding to c' func (c myAppController) rawRead() { // $ responsebody='argument corresponding to c'
c.ViewArgs["Foo"] = "<p>raw HTML</p>" // $ responsebody='"<p>raw HTML</p>"' c.ViewArgs["Foo"] = "<p>raw HTML</p>" // $ responsebody='"<p>raw HTML</p>"'
c.ViewArgs["Bar"] = "<p>not raw HTML</p>" c.ViewArgs["Bar"] = "<p>not raw HTML</p>"
c.ViewArgs["Foo"] = c.Params.Query // $ responsebody='selection of Query' Alert[go/reflected-xss] c.ViewArgs["Foo"] = c.Params.Query // $ responsebody='selection of Query'
c.Render() c.Render()
} }

Some files were not shown because too many files have changed in this diff Show More