Compare commits

..

3 Commits

Author SHA1 Message Date
yoff
0b473e3763 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-02 08:41:44 +00:00
Copilot
a13dfaa44f 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-02 08:37:30 +00:00
yoff
ac5fa629ef 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-02 08:24:17 +00:00
505 changed files with 6881 additions and 34020 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.download(version = "1.26.4")
go_sdk.download(version = "1.26.0")
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
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",
"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#": [
"java/ql/lib/semmle/code/java/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];
* ```
*/
class DerivedType extends Type, NameQualifyingElement, @derivedtype {
class DerivedType extends Type, @derivedtype {
override string toString() { result = this.getName() }
override string getName() { derivedtypes(underlyingElement(this), result, _, _) }

View File

@@ -1430,8 +1430,7 @@ specialnamequalifyingelements(
@namequalifyingelement = @namespace
| @specialnamequalifyingelement
| @usertype
| @decltype
| @derivedtype;
| @decltype;
namequalifiers(
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: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) |

View File

@@ -1,5 +1,7 @@
import cpp
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()

View File

@@ -1,8 +1,8 @@
// 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 }; };
static void f() {
static int f() {
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/dataflow: ${workspace}
codeql/mad: ${workspace}
codeql/rangeanalysis: ${workspace}
codeql/ssa: ${workspace}
codeql/threat-models: ${workspace}
codeql/tutorial: ${workspace}

View File

@@ -4,31 +4,67 @@
overlay[local?]
module;
private import csharp as CS
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
private import internal.rangeanalysis.BoundSpecific
/** Provides C#-specific definitions for bounds. */
private module BoundDefs implements SharedBound::BoundDefinitions<CS::Location> {
class Type = CS::Type;
private newtype TBound =
TBoundZero() or
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;
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()) }
/** Gets the location of this bound. */
abstract Location getLocation();
}
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::
:maxdepth: 1
codeql-cli-2.25.6
codeql-cli-2.25.5
codeql-cli-2.25.4
codeql-cli-2.25.3

View File

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

View File

@@ -2,14 +2,14 @@ module github.com/github/codeql-go/extractor
go 1.26
toolchain go1.26.4
toolchain go1.26.0
// when updating this, run
// bazel run @rules_go//go -- mod tidy
// when adding or removing dependencies, run
// bazel mod tidy
require (
golang.org/x/mod v0.37.0
golang.org/x/mod v0.36.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/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
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.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
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/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* More logging functions are now recognized as not returning or panicking.

View File

@@ -413,13 +413,17 @@ private class ExternalLoggerCall extends LoggerCall::Range, DataFlow::CallNode {
}
}
private class HeuristicLoggerFunction extends Method {
string logFunctionPrefix;
HeuristicLoggerFunction() {
exists(string tp, string name |
this.hasQualifiedName(_, tp, name) and
this.getReceiverBaseType().getUnderlyingType() instanceof InterfaceType
/**
* A call to an interface that looks like a logger. It is common to use a
* locally-defined interface for logging to make it easy to changing logging
* library.
*/
private class HeuristicLoggerCall extends LoggerCall::Range, DataFlow::CallNode {
HeuristicLoggerCall() {
exists(Method m, string tp, string logFunctionPrefix, string name |
m = this.getTarget() and
m.hasQualifiedName(_, tp, name) and
m.getReceiverBaseType().getUnderlyingType() instanceof InterfaceType
|
tp.regexpMatch(".*[lL]ogger") and
logFunctionPrefix =
@@ -431,19 +435,6 @@ private class HeuristicLoggerFunction extends Method {
)
}
override predicate mayReturnNormally() { logFunctionPrefix != "Fatal" }
override predicate mustPanic() { logFunctionPrefix = "Panic" }
}
/**
* A call to an interface that looks like a logger. It is common to use a
* locally-defined interface for logging to make it easy to change logging
* library.
*/
private class HeuristicLoggerCall extends LoggerCall::Range, DataFlow::CallNode {
HeuristicLoggerCall() { this.getTarget() instanceof HeuristicLoggerFunction }
override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() }
}

View File

@@ -12,37 +12,17 @@ import go
* forks.
*/
module Glog {
/** Gets a package name for `glog` or `klog` (which is a fork). */
string packagePath() {
result =
package([
"github.com/golang/glog", "gopkg.in/glog", "k8s.io/klog", "github.com/barakmich/glog"
], "")
}
private class GlogFunction extends Function {
int firstPrintedArg;
string format;
string level;
GlogFunction() {
exists(string pkg, string context, int nContextArgs, string depth, int nDepthArgs, string fn |
pkg = packagePath() and
exists(string pkg, string fn, string level |
pkg = package(["github.com/golang/glog", "gopkg.in/glog", "k8s.io/klog"], "") and
level = ["Error", "Exit", "Fatal", "Info", "Warning"] and
(
context = "" and nContextArgs = 0
fn = level + ["", "f", "ln"] and firstPrintedArg = 0
or
context = "Context" and nContextArgs = 1
) and
(
depth = "" and nDepthArgs = 0
or
depth = "Depth" and nDepthArgs = 1
) and
format = ["", "f", "ln"] and
(
fn = level + context + depth + format and
firstPrintedArg = nContextArgs + nDepthArgs
fn = level + "Depth" and firstPrintedArg = 1
)
|
this.hasQualifiedName(pkg, fn)
@@ -55,15 +35,10 @@ module Glog {
* Gets the index of the first argument that may be output, including a format string if one is present.
*/
int getFirstPrintedArg() { result = firstPrintedArg }
/** Holds if this function takes a format string. */
predicate formatter() { format = "f" }
override predicate mayReturnNormally() { level != "Fatal" and level != "Exit" }
}
private class StringFormatter extends StringOps::Formatting::Range instanceof GlogFunction {
StringFormatter() { this.formatter() }
StringFormatter() { this.getName().matches("%f") }
override int getFormatStringIndex() { result = super.getFirstPrintedArg() }
}

View File

@@ -28,12 +28,6 @@ module Logrus {
this.(Method).hasQualifiedName(packagePath(), ["Entry", "Logger"], name)
)
}
override predicate mayReturnNormally() {
not exists(string level, string suffix | level = ["Fatal", "Panic"] |
this.getName() = level + suffix
)
}
}
private class StringFormatters extends StringOps::Formatting::Range instanceof LogFunction {

View File

@@ -47,7 +47,7 @@ module Zap {
}
/** A Zap logging function which always panics. */
private class FatalLogMethod extends ZapFunction {
private class FatalLogMethod extends Method {
FatalLogMethod() {
this.hasQualifiedName(packagePath(), "Logger", "Fatal")
or
@@ -58,7 +58,7 @@ module Zap {
}
/** A Zap logging function which always panics. */
private class MustPanicLogMethod extends ZapFunction {
private class MustPanicLogMethod extends Method {
MustPanicLogMethod() {
this.hasQualifiedName(packagePath(), "Logger", "Panic")
or

View File

@@ -29,37 +29,18 @@ module Log {
}
private class LogFormatter extends StringOps::Formatting::Range instanceof LogFunction {
LogFormatter() { this.getName() = ["Fatalf", "Panicf", "Printf", "Panic", "Panicf", "Panicln"] }
LogFormatter() { this.getName() = ["Fatalf", "Panicf", "Printf"] }
override int getFormatStringIndex() { result = 0 }
}
/** A fatal log function, which calls `os.Exit`. */
private class FatalLogFunction extends Function {
FatalLogFunction() {
exists(string fn | fn = ["Fatal", "Fatalf", "Fatalln"] |
this.hasQualifiedName("log", fn)
or
this.(Method).hasQualifiedName("log", "Logger", fn)
)
}
FatalLogFunction() { this.hasQualifiedName("log", ["Fatal", "Fatalf", "Fatalln"]) }
override predicate mayReturnNormally() { none() }
}
/** A log function which must panic. */
private class PanicLogFunction extends Function {
PanicLogFunction() {
exists(string fn | fn = ["Panic", "Panicf", "Panicln"] |
this.hasQualifiedName("log", fn)
or
this.(Method).hasQualifiedName("log", "Logger", fn)
)
}
override predicate mustPanic() { any() }
}
// These models are not implemented using Models-as-Data because they represent reverse flow.
private class FunctionModels extends TaintTracking::FunctionModel {
FunctionInput inp;
@@ -82,6 +63,30 @@ module Log {
FunctionOutput outp;
MethodModels() {
// signature: func (*Logger) Fatal(v ...interface{})
this.hasQualifiedName("log", "Logger", "Fatal") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger) Fatalf(format string, v ...interface{})
this.hasQualifiedName("log", "Logger", "Fatalf") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger) Fatalln(v ...interface{})
this.hasQualifiedName("log", "Logger", "Fatalln") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger) Panic(v ...interface{})
this.hasQualifiedName("log", "Logger", "Panic") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger) Panicf(format string, v ...interface{})
this.hasQualifiedName("log", "Logger", "Panicf") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger) Panicln(v ...interface{})
this.hasQualifiedName("log", "Logger", "Panicln") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger) Print(v ...interface{})
this.hasQualifiedName("log", "Logger", "Print") and
(inp.isParameter(_) and outp.isReceiver())

View File

@@ -1,4 +1,4 @@
/**
/*
* @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.
* @kind problem

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-287/ImproperLdapAuth.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql
postprocess: utils/test/PrettyPrintModels.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
| 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 | |
@@ -14,3 +11,6 @@ nodes
| golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | semmle.label | "AllYourBase" |
| golang-jwt-v5.go:27:9:27:15 | JwtKey1 | semmle.label | JwtKey1 |
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
postprocess: utils/test/InlineExpectationsTestQuery.ql
experimental/CWE-321-V2/HardCodedKeys.ql

View File

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

View File

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

View File

@@ -7,37 +7,37 @@ import (
)
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)
out := 1337 / value // $ Alert
out := 1337 / value
fmt.Println(out)
}
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])
out := 1337 / value // $ Alert
out := 1337 / value
fmt.Println(out)
}
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)
out := 1337 / value // $ Alert
out := 1337 / value
fmt.Println(out)
}
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)
out := 1337 / value // $ Alert
out := 1337 / value
fmt.Println(out)
}
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)
out := 1337 / value // $ Alert
out := 1337 / value
fmt.Println(out)
}
@@ -51,10 +51,10 @@ func myHandler6(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])
if value >= 0 {
out := 1337 / value // $ Alert
out := 1337 / value
fmt.Println(out)
}
}

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-369/DivideByZero.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql
postprocess: utils/test/PrettyPrintModels.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
| 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 |
@@ -11,3 +7,7 @@ edges
| 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: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))
for _, name := range names {
var user User
db.Where("name = ?", name).First(&user) // $ Alert
db.Where("name = ?", name).First(&user)
res = append(res, user)
} // $ Source
}
return res
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -79,7 +79,7 @@ func badRoutingNet() {
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)
if err != nil {
log.Fatal("ListenAndServe: ", err)

View File

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

View File

@@ -10,7 +10,7 @@ import (
func badRoutingChi() {
r := chi.NewRouter()
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"))
})
http.ListenAndServe(":3000", r)

View File

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

View File

@@ -23,10 +23,10 @@ func good() (interface{}, error) {
}
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.
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
}
@@ -44,10 +44,10 @@ func good2(w http.ResponseWriter, req *http.Request) (interface{}, error) {
}
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.
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
}
@@ -60,12 +60,12 @@ func (Config) Parse([]string) error { return nil }
func RegexFuncModelTest(w http.ResponseWriter, req *http.Request) (interface{}, error) {
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 {
return nil, err
}
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
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@ import (
func exampleHandlerBad(w http.ResponseWriter, r *http.Request) {
// 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
}
}

View File

@@ -6,14 +6,14 @@ import (
// BAD: taken from https://www.gorillatoolkit.org/pkg/websocket
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
}
}
// BAD: both operands are from remote sources
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
}
}

View File

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

View File

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

View File

@@ -4,6 +4,6 @@ import "gorm.io/gorm"
func getUserId(db *gorm.DB, name string) int64 {
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
}

View File

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

View File

@@ -3,24 +3,24 @@ package main
func test() {
var xs []int
for _ = range xs {
defer test() // $ Alert[go/examples/deferinloop] // not ok
defer test() // not ok
}
for _ = range xs {
if true {
defer test() // $ Alert[go/examples/deferinloop] // not ok
defer test() // not ok
}
}
for i := 0; i < 10; i++ {
defer test() // $ Alert[go/examples/deferinloop]
defer test()
}
for true {
defer test() // $ Alert[go/examples/deferinloop] // not ok
defer test() // not ok
}
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
| 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 | |
@@ -60,3 +48,15 @@ nodes
| WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | semmle.label | type conversion |
| WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | semmle.label | type conversion |
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,
// and continue for 8 bytes, going out of the boundaries of
// `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)[:]))
@@ -108,7 +108,7 @@ func bad0() {
// Read before secret, overflowing into secret
// (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)[:]))
@@ -126,7 +126,7 @@ func bad1() {
// Read before secret, overflowing into secret
// (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)[:]))
@@ -146,7 +146,7 @@ func bad2() {
// Read before secret, overflowing into secret
// (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)[:]))
@@ -163,7 +163,7 @@ func bad3() {
// Read before secret, overflowing into secret
// (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([17]string((*leaking)))
@@ -186,7 +186,7 @@ func bad4() {
// Read before secret, overflowing into secret
// (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)[:]))
@@ -208,7 +208,7 @@ func bad5() {
// Read before secret, overflowing into secret
// (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[:]))
@@ -224,7 +224,7 @@ func bad6() {
secret := [9]byte{'s', 'e', 'n', 's', 'i', 't', 'i', 'v', 'e'}
// 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[:]))
@@ -240,7 +240,7 @@ func buffer_request(req unsafe.Pointer) [8 + 9]byte {
// will be read, the read will also contain pieces of
// data from `secret`.
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
}
func bad7() {
@@ -253,7 +253,7 @@ func bad7() {
// (notice we read more than the length of harmless);
// the leaking array will not contain letters,
// 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)
@@ -271,7 +271,7 @@ func bad8() {
// Read before secret, overflowing into secret
// (notice we read more than the length of harmless);
// 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)
@@ -289,7 +289,7 @@ func bad9() {
// Read before secret, overflowing into secret
// (notice we read more than the length of harmless);
// 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)

View File

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

View File

@@ -1,181 +1,54 @@
//go:generate depstubber -vendor github.com/golang/glog Level,Verbose Error,ErrorContext,ErrorContextDepth,ErrorContextDepthf,ErrorContextf,ErrorDepth,ErrorDepthf,Errorf,Errorln,Exit,ExitContext,ExitContextDepth,ExitContextDepthf,ExitContextf,ExitDepth,ExitDepthf,Exitf,Exitln,Fatal,FatalContext,FatalContextDepth,FatalContextDepthf,FatalContextf,FatalDepth,FatalDepthf,Fatalf,Fatalln,Info,InfoContext,InfoContextDepth,InfoContextDepthf,InfoContextf,InfoDepth,InfoDepthf,Infof,Infoln,V,VDepth,Warning,WarningContext,WarningContextDepth,WarningContextDepthf,WarningContextf,WarningDepth,WarningDepthf,Warningf,Warningln
//go:generate depstubber -vendor k8s.io/klog Level,Verbose Error,ErrorDepth,Errorf,Errorln,Exit,ExitDepth,Exitf,Exitln,Fatal,FatalDepth,Fatalf,Fatalln,Info,InfoDepth,Infof,Infoln,V,Warning,WarningDepth,Warningf,Warningln
//go:generate depstubber -vendor github.com/golang/glog "" Error,ErrorDepth,Errorf,Errorln,Exit,ExitDepth,Exitf,Exitln,Fatal,FatalDepth,Fatalf,Fatalln,Info,InfoDepth,Infof,Infoln,Warning,WarningDepth,Warningf,Warningln
//go:generate depstubber -vendor k8s.io/klog "" Error,ErrorDepth,Errorf,Errorln,Exit,ExitDepth,Exitf,Exitln,Fatal,FatalDepth,Fatalf,Fatalln,Info,InfoDepth,Infof,Infoln,Warning,WarningDepth,Warningf,Warningln
package main
import (
"context"
"github.com/golang/glog"
"k8s.io/klog"
)
func glogTest(selector int) {
ctx := context.Background()
glog.Error(text) // $ logger=text
glog.ErrorContext(ctx, text) // $ logger=text
glog.ErrorContextDepth(ctx, 0, text) // $ logger=text
glog.ErrorContextDepthf(ctx, 0, fmt, text) // $ logger=fmt logger=text
glog.ErrorContextf(ctx, fmt, text) // $ logger=fmt logger=text
glog.ErrorDepth(0, text) // $ logger=text
glog.ErrorDepthf(0, fmt, text) // $ logger=fmt logger=text
glog.Errorf(fmt, text) // $ logger=fmt logger=text
glog.Errorln(text) // $ logger=text
if selector == 1 {
glog.Exit(text) // $ logger=text
}
if selector == 2 {
glog.ExitContext(ctx, text) // $ logger=text
}
if selector == 3 {
glog.ExitContextDepth(ctx, 0, text) // $ logger=text
}
if selector == 4 {
glog.ExitContextDepthf(ctx, 0, fmt, text) // $ logger=fmt logger=text
}
if selector == 5 {
glog.ExitContextf(ctx, fmt, text) // $ logger=fmt logger=text
}
if selector == 6 {
glog.ExitDepth(0, text) // $ logger=text
}
if selector == 7 {
glog.ExitDepthf(0, fmt, text) // $ logger=fmt logger=text
}
if selector == 8 {
glog.Exitf(fmt, text) // $ logger=fmt logger=text
}
if selector == 9 {
glog.Exitln(text) // $ logger=text
}
if selector == 10 {
glog.Fatal(text) // $ logger=text
}
if selector == 11 {
glog.FatalContext(ctx, text) // $ logger=text
}
if selector == 12 {
glog.FatalContextDepth(ctx, 0, text) // $ logger=text
}
if selector == 13 {
glog.FatalContextDepthf(ctx, 0, fmt, text) // $ logger=fmt logger=text
}
if selector == 14 {
glog.FatalContextf(ctx, fmt, text) // $ logger=fmt logger=text
}
if selector == 15 {
glog.FatalDepth(0, text) // $ logger=text
}
if selector == 16 {
glog.FatalDepthf(0, fmt, text) // $ logger=fmt logger=text
}
if selector == 17 {
glog.Fatalf(fmt, text) // $ logger=fmt logger=text
}
if selector == 18 {
glog.Fatalln(text) // $ logger=text
}
glog.Info(text) // $ logger=text
glog.InfoContext(ctx, text) // $ logger=text
glog.InfoContextDepth(ctx, 0, text) // $ logger=text
glog.InfoContextDepthf(ctx, 0, fmt, text) // $ logger=fmt logger=text
glog.InfoContextf(ctx, fmt, text) // $ logger=fmt logger=text
glog.InfoDepth(0, text) // $ logger=text
glog.InfoDepthf(0, fmt, text) // $ logger=fmt logger=text
glog.Infof(fmt, text) // $ logger=fmt logger=text
glog.Infoln(text) // $ logger=text
glog.Warning(text) // $ logger=text
glog.WarningContext(ctx, text) // $ logger=text
glog.WarningContextDepth(ctx, 0, text) // $ logger=text
glog.WarningContextDepthf(ctx, 0, fmt, text) // $ logger=fmt logger=text
glog.WarningContextf(ctx, fmt, text) // $ logger=fmt logger=text
glog.WarningDepth(0, text) // $ logger=text
glog.WarningDepthf(0, fmt, text) // $ logger=fmt logger=text
glog.Warningf(fmt, text) // $ logger=fmt logger=text
glog.Warningln(text) // $ logger=text
glog.V(0).Info(text) // $ logger=text
glog.V(0).InfoContext(ctx, text) // $ logger=text
glog.V(0).InfoContextDepth(ctx, 0, text) // $ logger=text
glog.V(0).InfoContextDepthf(ctx, 0, fmt, text) // $ logger=fmt logger=text
glog.V(0).InfoContextf(ctx, fmt, text) // $ logger=fmt logger=text
glog.V(0).InfoDepth(0, text) // $ logger=text
glog.V(0).InfoDepthf(0, fmt, text) // $ logger=fmt logger=text
glog.V(0).Infof(fmt, text) // $ logger=fmt logger=text
glog.V(0).Infoln(text) // $ logger=text
glog.VDepth(0, 0).Info(text) // $ logger=text
func glogTest() {
glog.Error(text) // $ logger=text
glog.ErrorDepth(0, text) // $ logger=text
glog.Errorf(fmt, text) // $ logger=fmt logger=text
glog.Errorln(text) // $ logger=text
glog.Exit(text) // $ logger=text
glog.ExitDepth(0, text) // $ logger=text
glog.Exitf(fmt, text) // $ logger=fmt logger=text
glog.Exitln(text) // $ logger=text
glog.Fatal(text) // $ logger=text
glog.FatalDepth(0, text) // $ logger=text
glog.Fatalf(fmt, text) // $ logger=fmt logger=text
glog.Fatalln(text) // $ logger=text
glog.Info(text) // $ logger=text
glog.InfoDepth(0, text) // $ logger=text
glog.Infof(fmt, text) // $ logger=fmt logger=text
glog.Infoln(text) // $ logger=text
glog.Warning(text) // $ logger=text
glog.WarningDepth(0, text) // $ logger=text
glog.Warningf(fmt, text) // $ logger=fmt logger=text
glog.Warningln(text) // $ logger=text
// components corresponding to the format specifier "%T" are not considered vulnerable
glog.ErrorContextDepthf(ctx, 0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.ErrorContextf(ctx, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.ErrorDepthf(0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Errorf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
if selector == 19 {
glog.ExitContextDepthf(ctx, 0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}
if selector == 20 {
glog.ExitContextf(ctx, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}
if selector == 21 {
glog.ExitDepthf(0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}
if selector == 22 {
glog.Exitf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}
if selector == 23 {
glog.FatalContextDepthf(ctx, 0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}
if selector == 24 {
glog.FatalContextf(ctx, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}
if selector == 25 {
glog.FatalDepthf(0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}
if selector == 26 {
glog.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}
glog.InfoContextDepthf(ctx, 0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.InfoContextf(ctx, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.InfoDepthf(0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.WarningContextDepthf(ctx, 0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.WarningContextf(ctx, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.WarningDepthf(0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Warningf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.V(0).InfoContextDepthf(ctx, 0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.V(0).InfoContextf(ctx, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.V(0).InfoDepthf(0, "%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.V(0).Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Errorf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Exitf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Warningf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Error(text) // $ logger=text
klog.ErrorDepth(0, text) // $ logger=text
klog.Errorf(fmt, text) // $ logger=fmt logger=text
klog.Errorln(text) // $ logger=text
if selector == 27 {
klog.Exit(text) // $ logger=text
}
if selector == 28 {
klog.ExitDepth(0, text) // $ logger=text
}
if selector == 29 {
klog.Exitf(fmt, text) // $ logger=fmt logger=text
}
if selector == 30 {
klog.Exitln(text) // $ logger=text
}
if selector == 31 {
klog.Fatal(text) // $ logger=text
}
if selector == 32 {
klog.FatalDepth(0, text) // $ logger=text
}
if selector == 33 {
klog.Fatalf(fmt, text) // $ logger=fmt logger=text
}
if selector == 34 {
klog.Fatalln(text) // $ logger=text
}
klog.Error(text) // $ logger=text
klog.ErrorDepth(0, text) // $ logger=text
klog.Errorf(fmt, text) // $ logger=fmt logger=text
klog.Errorln(text) // $ logger=text
klog.Exit(text) // $ logger=text
klog.ExitDepth(0, text) // $ logger=text
klog.Exitf(fmt, text) // $ logger=fmt logger=text
klog.Exitln(text) // $ logger=text
klog.Fatal(text) // $ logger=text
klog.FatalDepth(0, text) // $ logger=text
klog.Fatalf(fmt, text) // $ logger=fmt logger=text
klog.Fatalln(text) // $ logger=text
klog.Info(text) // $ logger=text
klog.InfoDepth(0, text) // $ logger=text
klog.Infof(fmt, text) // $ logger=fmt logger=text
@@ -184,19 +57,11 @@ func glogTest(selector int) {
klog.WarningDepth(0, text) // $ logger=text
klog.Warningf(fmt, text) // $ logger=fmt logger=text
klog.Warningln(text) // $ logger=text
klog.V(0).Info(text) // $ logger=text
klog.V(0).Infof(fmt, text) // $ logger=fmt logger=text
klog.V(0).Infoln(text) // $ logger=text
// components corresponding to the format specifier "%T" are not considered vulnerable
klog.Errorf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
if selector == 35 {
klog.Exitf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}
if selector == 36 {
klog.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}
klog.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Warningf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.V(0).Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Errorf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Exitf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Warningf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}

View File

@@ -3,7 +3,7 @@ module codeql-go-tests/concepts/loggercall
go 1.15
require (
github.com/golang/glog v1.2.5
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/sirupsen/logrus v1.7.0
k8s.io/klog v1.0.0
)

View File

@@ -6,6 +6,5 @@ const text = "test"
var v []byte
func main() {
glogTest(len(v))
stdlib()
}

View File

@@ -2,125 +2,47 @@
// This is a simple stub for github.com/golang/glog, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/golang/glog (exports: Level,Verbose; functions: Error,ErrorContext,ErrorContextDepth,ErrorContextDepthf,ErrorContextf,ErrorDepth,ErrorDepthf,Errorf,Errorln,Exit,ExitContext,ExitContextDepth,ExitContextDepthf,ExitContextf,ExitDepth,ExitDepthf,Exitf,Exitln,Fatal,FatalContext,FatalContextDepth,FatalContextDepthf,FatalContextf,FatalDepth,FatalDepthf,Fatalf,Fatalln,Info,InfoContext,InfoContextDepth,InfoContextDepthf,InfoContextf,InfoDepth,InfoDepthf,Infof,Infoln,V,VDepth,Warning,WarningContext,WarningContextDepth,WarningContextDepthf,WarningContextf,WarningDepth,WarningDepthf,Warningf,Warningln)
// Source: github.com/golang/glog (exports: ; functions: Error,ErrorDepth,Errorf,Errorln,Exit,ExitDepth,Exitf,Exitln,Fatal,FatalDepth,Fatalf,Fatalln,Info,InfoDepth,Infof,Infoln,Warning,WarningDepth,Warningf,Warningln)
// Package glog is a stub of github.com/golang/glog, generated by depstubber.
package glog
import "context"
type Level int32
type Verbose bool
func Error(_ ...interface{}) {}
func ErrorContext(_ context.Context, _ ...interface{}) {}
func ErrorContextDepth(_ context.Context, _ int, _ ...interface{}) {}
func ErrorContextDepthf(_ context.Context, _ int, _ string, _ ...interface{}) {}
func ErrorContextf(_ context.Context, _ string, _ ...interface{}) {}
func ErrorDepth(_ int, _ ...interface{}) {}
func ErrorDepthf(_ int, _ string, _ ...interface{}) {}
func Errorf(_ string, _ ...interface{}) {}
func Errorln(_ ...interface{}) {}
func Exit(_ ...interface{}) {}
func ExitContext(_ context.Context, _ ...interface{}) {}
func ExitContextDepth(_ context.Context, _ int, _ ...interface{}) {}
func ExitContextDepthf(_ context.Context, _ int, _ string, _ ...interface{}) {}
func ExitContextf(_ context.Context, _ string, _ ...interface{}) {}
func ExitDepth(_ int, _ ...interface{}) {}
func ExitDepthf(_ int, _ string, _ ...interface{}) {}
func Exitf(_ string, _ ...interface{}) {}
func Exitln(_ ...interface{}) {}
func Fatal(_ ...interface{}) {}
func FatalContext(_ context.Context, _ ...interface{}) {}
func FatalContextDepth(_ context.Context, _ int, _ ...interface{}) {}
func FatalContextDepthf(_ context.Context, _ int, _ string, _ ...interface{}) {}
func FatalContextf(_ context.Context, _ string, _ ...interface{}) {}
func FatalDepth(_ int, _ ...interface{}) {}
func FatalDepthf(_ int, _ string, _ ...interface{}) {}
func Fatalf(_ string, _ ...interface{}) {}
func Fatalln(_ ...interface{}) {}
func Info(_ ...interface{}) {}
func InfoContext(_ context.Context, _ ...interface{}) {}
func InfoContextDepth(_ context.Context, _ int, _ ...interface{}) {}
func InfoContextDepthf(_ context.Context, _ int, _ string, _ ...interface{}) {}
func InfoContextf(_ context.Context, _ string, _ ...interface{}) {}
func InfoDepth(_ int, _ ...interface{}) {}
func InfoDepthf(_ int, _ string, _ ...interface{}) {}
func Infof(_ string, _ ...interface{}) {}
func Infoln(_ ...interface{}) {}
func V(_ Level) Verbose { return false }
func VDepth(_ int, _ Level) Verbose { return false }
func Warning(_ ...interface{}) {}
func WarningContext(_ context.Context, _ ...interface{}) {}
func WarningContextDepth(_ context.Context, _ int, _ ...interface{}) {}
func WarningContextDepthf(_ context.Context, _ int, _ string, _ ...interface{}) {}
func WarningContextf(_ context.Context, _ string, _ ...interface{}) {}
func WarningDepth(_ int, _ ...interface{}) {}
func WarningDepthf(_ int, _ string, _ ...interface{}) {}
func Warningf(_ string, _ ...interface{}) {}
func Warningln(_ ...interface{}) {}
func (_ Verbose) Info(_ ...interface{}) {}
func (_ Verbose) InfoContext(_ context.Context, _ ...interface{}) {}
func (_ Verbose) InfoContextDepth(_ context.Context, _ int, _ ...interface{}) {}
func (_ Verbose) InfoContextDepthf(_ context.Context, _ int, _ string, _ ...interface{}) {}
func (_ Verbose) InfoContextf(_ context.Context, _ string, _ ...interface{}) {}
func (_ Verbose) InfoDepth(_ int, _ ...interface{}) {}
func (_ Verbose) InfoDepthf(_ int, _ string, _ ...interface{}) {}
func (_ Verbose) Infof(_ string, _ ...interface{}) {}
func (_ Verbose) Infoln(_ ...interface{}) {}

View File

@@ -2,15 +2,11 @@
// This is a simple stub for k8s.io/klog, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: k8s.io/klog (exports: Level,Verbose; functions: Error,ErrorDepth,Errorf,Errorln,Exit,ExitDepth,Exitf,Exitln,Fatal,FatalDepth,Fatalf,Fatalln,Info,InfoDepth,Infof,Infoln,V,Warning,WarningDepth,Warningf,Warningln)
// Source: k8s.io/klog (exports: ; functions: Error,ErrorDepth,Errorf,Errorln,Exit,ExitDepth,Exitf,Exitln,Fatal,FatalDepth,Fatalf,Fatalln,Info,InfoDepth,Infof,Infoln,Warning,WarningDepth,Warningf,Warningln)
// Package klog is a stub of k8s.io/klog, generated by depstubber.
package klog
type Level int32
type Verbose bool
func Error(_ ...interface{}) {}
func ErrorDepth(_ int, _ ...interface{}) {}
@@ -43,8 +39,6 @@ func Infof(_ string, _ ...interface{}) {}
func Infoln(_ ...interface{}) {}
func V(_ Level) Verbose { return false }
func Warning(_ ...interface{}) {}
func WarningDepth(_ int, _ ...interface{}) {}
@@ -52,9 +46,3 @@ func WarningDepth(_ int, _ ...interface{}) {}
func Warningf(_ string, _ ...interface{}) {}
func Warningln(_ ...interface{}) {}
func (_ Verbose) Info(_ ...interface{}) {}
func (_ Verbose) Infof(_ string, _ ...interface{}) {}
func (_ Verbose) Infoln(_ ...interface{}) {}

View File

@@ -1,4 +1,4 @@
# github.com/golang/glog v1.2.5
# github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
## explicit
github.com/golang/glog
# github.com/sirupsen/logrus v1.7.0

View File

@@ -1,21 +1,11 @@
| file://:0:0:0:0 | Exit | os.Exit |
| file://:0:0:0:0 | Fatal | log.Fatal |
| file://:0:0:0:0 | Fatal | log.Logger.Fatal |
| file://:0:0:0:0 | Fatalf | log.Fatalf |
| file://:0:0:0:0 | Fatalf | log.Logger.Fatalf |
| file://:0:0:0:0 | Fatalln | log.Fatalln |
| file://:0:0:0:0 | Fatalln | log.Logger.Fatalln |
| file://:0:0:0:0 | Panic | log.Logger.Panic |
| file://:0:0:0:0 | Panic | log.Panic |
| file://:0:0:0:0 | Panicf | log.Logger.Panicf |
| file://:0:0:0:0 | Panicf | log.Panicf |
| file://:0:0:0:0 | Panicln | log.Logger.Panicln |
| file://:0:0:0:0 | Panicln | log.Panicln |
| file://:0:0:0:0 | panic | panic |
| noretfunctions.go:8:6:8:12 | isNoRet | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.isNoRet |
| noretfunctions.go:20:6:20:22 | noRetUsesLogFatal | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.noRetUsesLogFatal |
| noretfunctions.go:24:6:24:23 | noRetUsesLogFatalf | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.noRetUsesLogFatalf |
| stmts7.go:10:6:10:15 | canRecover | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.canRecover |
| stmts.go:10:6:10:10 | test5 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.test5 |
| stmts.go:46:6:46:10 | test6 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.test6 |
| stmts.go:112:6:112:10 | test9 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.test9 |
| file://:0:0:0:0 | Exit | package os |
| file://:0:0:0:0 | Fatal | package log |
| file://:0:0:0:0 | Fatalf | package log |
| file://:0:0:0:0 | Fatalln | package log |
| noretfunctions.go:8:6:8:12 | isNoRet | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| noretfunctions.go:20:6:20:22 | noRetUsesLogFatal | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| noretfunctions.go:24:6:24:23 | noRetUsesLogFatalf | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| stmts7.go:10:6:10:15 | canRecover | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| stmts.go:10:6:10:10 | test5 | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| stmts.go:46:6:46:10 | test6 | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| stmts.go:112:6:112:10 | test9 | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |

View File

@@ -2,4 +2,4 @@ import go
from Function f
where not f.mayReturnNormally()
select f, f.getQualifiedName()
select f, f.getPackage()

View File

@@ -9,9 +9,9 @@ import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import utils.test.InlineFlowTest
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>

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"
}
func sink(any) {
func sink(string) {
}
type A struct {
@@ -19,10 +19,6 @@ func functionWithVarArgsParameter(s ...string) string {
return s[1]
}
func functionWithVarArgsOutParameter(in string, out ...*string) {
*out[0] = in
}
func functionWithSliceOfStructsParameter(s []A) string {
return s[1].f
}
@@ -42,12 +38,6 @@ func main() {
sink(functionWithVarArgsParameter(sSlice...)) // $ 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()}}
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
(inp.isParameter(_) and outp.isResult())
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
(inp.isParameter(0) and outp.isResult())
or

View File

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

View File

@@ -8,7 +8,7 @@ func source() string {
return "untrusted data"
}
func sink(any) {
func sink(string) {
}
func main() {
@@ -21,17 +21,10 @@ func main() {
s0 := ""
s1 := source()
sSlice := []string{s0, s1}
sink(test.FunctionWithParameter(sSlice[1])) // $ hasValueFlow="call to FunctionWithParameter"
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"
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)) // $ hasValueFlow="call to FunctionWithVarArgsParameter"
var out1 *string
var out2 *string
test.FunctionWithVarArgsOutParameter(source(), out1, out2)
sink(out1) // $ hasValueFlow="out1"
sink(out2) // $ hasValueFlow="out2"
sink(test.FunctionWithParameter(sSlice[1])) // $ hasValueFlow="call to FunctionWithParameter"
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(s0, s1)) // $ MISSING: hasValueFlow="call to FunctionWithVarArgsParameter"
sliceOfStructs := []test.A{{Field: source()}}
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(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 ""
}
func FunctionWithVarArgsOutParameter(in string, out ...*string) {
}
func FunctionWithSliceOfStructsParameter(s []A) string {
return ""
}

View File

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

View File

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

View File

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

View File

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

View File

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

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