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
285 changed files with 5757 additions and 22772 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +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; * 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
HeuristicLoggerFunction() { * library.
exists(string tp, string name | */
this.hasQualifiedName(_, tp, name) and private class HeuristicLoggerCall extends LoggerCall::Range, DataFlow::CallNode {
this.getReceiverBaseType().getUnderlyingType() instanceof InterfaceType 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 tp.regexpMatch(".*[lL]ogger") and
logFunctionPrefix = 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() } override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() }
} }

View File

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

View File

@@ -28,12 +28,6 @@ module Logrus {
this.(Method).hasQualifiedName(packagePath(), ["Entry", "Logger"], name) 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 { private class StringFormatters extends StringOps::Formatting::Range instanceof LogFunction {

View File

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

View File

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

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 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 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 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 package main
import ( import (
"context"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/klog" "k8s.io/klog"
) )
func glogTest(selector int) { func glogTest() {
ctx := context.Background()
glog.Error(text) // $ logger=text 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.ErrorDepth(0, text) // $ logger=text
glog.ErrorDepthf(0, fmt, text) // $ logger=fmt logger=text
glog.Errorf(fmt, text) // $ logger=fmt logger=text glog.Errorf(fmt, text) // $ logger=fmt logger=text
glog.Errorln(text) // $ logger=text glog.Errorln(text) // $ logger=text
if selector == 1 {
glog.Exit(text) // $ logger=text 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 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 glog.Exitf(fmt, text) // $ logger=fmt logger=text
}
if selector == 9 {
glog.Exitln(text) // $ logger=text glog.Exitln(text) // $ logger=text
}
if selector == 10 {
glog.Fatal(text) // $ logger=text 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 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 glog.Fatalf(fmt, text) // $ logger=fmt logger=text
}
if selector == 18 {
glog.Fatalln(text) // $ logger=text glog.Fatalln(text) // $ logger=text
}
glog.Info(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.InfoDepth(0, text) // $ logger=text
glog.InfoDepthf(0, fmt, text) // $ logger=fmt logger=text
glog.Infof(fmt, text) // $ logger=fmt logger=text glog.Infof(fmt, text) // $ logger=fmt logger=text
glog.Infoln(text) // $ logger=text glog.Infoln(text) // $ logger=text
glog.Warning(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.WarningDepth(0, text) // $ logger=text
glog.WarningDepthf(0, fmt, text) // $ logger=fmt logger=text
glog.Warningf(fmt, text) // $ logger=fmt logger=text glog.Warningf(fmt, text) // $ logger=fmt logger=text
glog.Warningln(text) // $ 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
// components corresponding to the format specifier "%T" are not considered vulnerable // 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 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 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.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.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.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
klog.Error(text) // $ logger=text klog.Error(text) // $ logger=text
klog.ErrorDepth(0, text) // $ logger=text klog.ErrorDepth(0, text) // $ logger=text
klog.Errorf(fmt, text) // $ logger=fmt logger=text klog.Errorf(fmt, text) // $ logger=fmt logger=text
klog.Errorln(text) // $ logger=text klog.Errorln(text) // $ logger=text
if selector == 27 {
klog.Exit(text) // $ logger=text klog.Exit(text) // $ logger=text
}
if selector == 28 {
klog.ExitDepth(0, text) // $ logger=text klog.ExitDepth(0, text) // $ logger=text
}
if selector == 29 {
klog.Exitf(fmt, text) // $ logger=fmt logger=text klog.Exitf(fmt, text) // $ logger=fmt logger=text
}
if selector == 30 {
klog.Exitln(text) // $ logger=text klog.Exitln(text) // $ logger=text
}
if selector == 31 {
klog.Fatal(text) // $ logger=text klog.Fatal(text) // $ logger=text
}
if selector == 32 {
klog.FatalDepth(0, text) // $ logger=text klog.FatalDepth(0, text) // $ logger=text
}
if selector == 33 {
klog.Fatalf(fmt, text) // $ logger=fmt logger=text klog.Fatalf(fmt, text) // $ logger=fmt logger=text
}
if selector == 34 {
klog.Fatalln(text) // $ logger=text klog.Fatalln(text) // $ logger=text
}
klog.Info(text) // $ logger=text klog.Info(text) // $ logger=text
klog.InfoDepth(0, text) // $ logger=text klog.InfoDepth(0, text) // $ logger=text
klog.Infof(fmt, text) // $ logger=fmt 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.WarningDepth(0, text) // $ logger=text
klog.Warningf(fmt, text) // $ logger=fmt logger=text klog.Warningf(fmt, text) // $ logger=fmt logger=text
klog.Warningln(text) // $ 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 // 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 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 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.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.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.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
} }

View File

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

View File

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

View File

@@ -2,125 +2,47 @@
// This is a simple stub for github.com/golang/glog, strictly for use in testing. // 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. // 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 is a stub of github.com/golang/glog, generated by depstubber.
package glog package glog
import "context"
type Level int32
type Verbose bool
func Error(_ ...interface{}) {} 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 ErrorDepth(_ int, _ ...interface{}) {}
func ErrorDepthf(_ int, _ string, _ ...interface{}) {}
func Errorf(_ string, _ ...interface{}) {} func Errorf(_ string, _ ...interface{}) {}
func Errorln(_ ...interface{}) {} func Errorln(_ ...interface{}) {}
func Exit(_ ...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 ExitDepth(_ int, _ ...interface{}) {}
func ExitDepthf(_ int, _ string, _ ...interface{}) {}
func Exitf(_ string, _ ...interface{}) {} func Exitf(_ string, _ ...interface{}) {}
func Exitln(_ ...interface{}) {} func Exitln(_ ...interface{}) {}
func Fatal(_ ...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 FatalDepth(_ int, _ ...interface{}) {}
func FatalDepthf(_ int, _ string, _ ...interface{}) {}
func Fatalf(_ string, _ ...interface{}) {} func Fatalf(_ string, _ ...interface{}) {}
func Fatalln(_ ...interface{}) {} func Fatalln(_ ...interface{}) {}
func Info(_ ...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 InfoDepth(_ int, _ ...interface{}) {}
func InfoDepthf(_ int, _ string, _ ...interface{}) {}
func Infof(_ string, _ ...interface{}) {} func Infof(_ string, _ ...interface{}) {}
func Infoln(_ ...interface{}) {} func Infoln(_ ...interface{}) {}
func V(_ Level) Verbose { return false }
func VDepth(_ int, _ Level) Verbose { return false }
func Warning(_ ...interface{}) {} 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 WarningDepth(_ int, _ ...interface{}) {}
func WarningDepthf(_ int, _ string, _ ...interface{}) {}
func Warningf(_ string, _ ...interface{}) {} func Warningf(_ string, _ ...interface{}) {}
func Warningln(_ ...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. // 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. // 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 is a stub of k8s.io/klog, generated by depstubber.
package klog package klog
type Level int32
type Verbose bool
func Error(_ ...interface{}) {} func Error(_ ...interface{}) {}
func ErrorDepth(_ int, _ ...interface{}) {} func ErrorDepth(_ int, _ ...interface{}) {}
@@ -43,8 +39,6 @@ func Infof(_ string, _ ...interface{}) {}
func Infoln(_ ...interface{}) {} func Infoln(_ ...interface{}) {}
func V(_ Level) Verbose { return false }
func Warning(_ ...interface{}) {} func Warning(_ ...interface{}) {}
func WarningDepth(_ int, _ ...interface{}) {} func WarningDepth(_ int, _ ...interface{}) {}
@@ -52,9 +46,3 @@ func WarningDepth(_ int, _ ...interface{}) {}
func Warningf(_ string, _ ...interface{}) {} func Warningf(_ string, _ ...interface{}) {}
func Warningln(_ ...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 ## explicit
github.com/golang/glog github.com/golang/glog
# github.com/sirupsen/logrus v1.7.0 # 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 | Exit | package os |
| file://:0:0:0:0 | Fatal | log.Fatal | | file://:0:0:0:0 | Fatal | package log |
| file://:0:0:0:0 | Fatal | log.Logger.Fatal | | file://:0:0:0:0 | Fatalf | package log |
| file://:0:0:0:0 | Fatalf | log.Fatalf | | file://:0:0:0:0 | Fatalln | package log |
| file://:0:0:0:0 | Fatalf | log.Logger.Fatalf | | noretfunctions.go:8:6:8:12 | isNoRet | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| file://:0:0:0:0 | Fatalln | log.Fatalln | | noretfunctions.go:20:6:20:22 | noRetUsesLogFatal | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| file://:0:0:0:0 | Fatalln | log.Logger.Fatalln | | noretfunctions.go:24:6:24:23 | noRetUsesLogFatalf | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| file://:0:0:0:0 | Panic | log.Logger.Panic | | stmts7.go:10:6:10:15 | canRecover | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| file://:0:0:0:0 | Panic | log.Panic | | stmts.go:10:6:10:10 | test5 | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| file://:0:0:0:0 | Panicf | log.Logger.Panicf | | stmts.go:46:6:46:10 | test6 | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| file://:0:0:0:0 | Panicf | log.Panicf | | stmts.go:112:6:112:10 | test9 | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph |
| 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 |

View File

@@ -2,4 +2,4 @@ import go
from Function f from Function f
where not f.mayReturnNormally() 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 import utils.test.InlineFlowTest
module Config implements DataFlow::ConfigSig { module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { sourceNode(source, "qltest") } predicate isSource(DataFlow::Node src) { sourceNode(src, "qltest") }
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "qltest") } predicate isSink(DataFlow::Node src) { sinkNode(src, "qltest") }
} }
import ValueFlowTest<Config> import ValueFlowTest<Config>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,6 +15,62 @@ func TaintStepTest_LogNew_B0I0O0(sourceCQL interface{}) interface{} {
return intoWriter414 return intoWriter414
} }
func TaintStepTest_LogLoggerFatal_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface518 := sourceCQL.(interface{})
var intoLogger650 log.Logger
intoLogger650.Fatal(fromInterface518)
return intoLogger650
}
func TaintStepTest_LogLoggerFatalf_B0I0O0(sourceCQL interface{}) interface{} {
fromString784 := sourceCQL.(string)
var intoLogger957 log.Logger
intoLogger957.Fatalf(fromString784, nil)
return intoLogger957
}
func TaintStepTest_LogLoggerFatalf_B0I1O0(sourceCQL interface{}) interface{} {
fromInterface520 := sourceCQL.(interface{})
var intoLogger443 log.Logger
intoLogger443.Fatalf("", fromInterface520)
return intoLogger443
}
func TaintStepTest_LogLoggerFatalln_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface127 := sourceCQL.(interface{})
var intoLogger483 log.Logger
intoLogger483.Fatalln(fromInterface127)
return intoLogger483
}
func TaintStepTest_LogLoggerPanic_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface989 := sourceCQL.(interface{})
var intoLogger982 log.Logger
intoLogger982.Panic(fromInterface989)
return intoLogger982
}
func TaintStepTest_LogLoggerPanicf_B0I0O0(sourceCQL interface{}) interface{} {
fromString417 := sourceCQL.(string)
var intoLogger584 log.Logger
intoLogger584.Panicf(fromString417, nil)
return intoLogger584
}
func TaintStepTest_LogLoggerPanicf_B0I1O0(sourceCQL interface{}) interface{} {
fromInterface991 := sourceCQL.(interface{})
var intoLogger881 log.Logger
intoLogger881.Panicf("", fromInterface991)
return intoLogger881
}
func TaintStepTest_LogLoggerPanicln_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface186 := sourceCQL.(interface{})
var intoLogger284 log.Logger
intoLogger284.Panicln(fromInterface186)
return intoLogger284
}
func TaintStepTest_LogLoggerPrint_B0I0O0(sourceCQL interface{}) interface{} { func TaintStepTest_LogLoggerPrint_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface908 := sourceCQL.(interface{}) fromInterface908 := sourceCQL.(interface{})
var intoLogger137 log.Logger var intoLogger137 log.Logger
@@ -69,6 +125,46 @@ func RunAllTaints_Log() {
out := TaintStepTest_LogNew_B0I0O0(source) out := TaintStepTest_LogNew_B0I0O0(source)
sink(0, out) sink(0, out)
} }
{
source := newSource(1)
out := TaintStepTest_LogLoggerFatal_B0I0O0(source)
sink(1, out)
}
{
source := newSource(2)
out := TaintStepTest_LogLoggerFatalf_B0I0O0(source)
sink(2, out)
}
{
source := newSource(3)
out := TaintStepTest_LogLoggerFatalf_B0I1O0(source)
sink(3, out)
}
{
source := newSource(4)
out := TaintStepTest_LogLoggerFatalln_B0I0O0(source)
sink(4, out)
}
{
source := newSource(5)
out := TaintStepTest_LogLoggerPanic_B0I0O0(source)
sink(5, out)
}
{
source := newSource(6)
out := TaintStepTest_LogLoggerPanicf_B0I0O0(source)
sink(6, out)
}
{
source := newSource(7)
out := TaintStepTest_LogLoggerPanicf_B0I1O0(source)
sink(7, out)
}
{
source := newSource(8)
out := TaintStepTest_LogLoggerPanicln_B0I0O0(source)
sink(8, out)
}
{ {
source := newSource(9) source := newSource(9)
out := TaintStepTest_LogLoggerPrint_B0I0O0(source) out := TaintStepTest_LogLoggerPrint_B0I0O0(source)

View File

@@ -3,9 +3,9 @@ reverseRead
| LogInjection.go:33:14:33:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | LogInjection.go:33:14:33:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| LogInjection.go:34:18:34:20 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | LogInjection.go:34:18:34:20 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| LogInjection.go:35:14:35:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | LogInjection.go:35:14:35:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| LogInjection.go:551:14:551:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | LogInjection.go:447:14:447:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| LogInjection.go:559:14:559:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | LogInjection.go:455:14:455:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| LogInjection.go:567:14:567:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | LogInjection.go:463:14:463:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| LogInjection.go:602:14:602:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | LogInjection.go:498:14:498:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| LogInjection.go:603:14:603:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | LogInjection.go:499:14:499:16 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |
| LogInjection.go:828:12:828:14 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | LogInjection.go:724:12:724:14 | implicit dereference | Origin of readStep is missing a PostUpdateNode. |

View File

@@ -49,22 +49,22 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
log.Printf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password" log.Printf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
log.Println("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" log.Println("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
if testFlag == "1" { if testFlag == "true" {
log.Fatal("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" log.Fatal("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
} }
if testFlag == "2" { if testFlag == "true" {
log.Fatalf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password" log.Fatalf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
} }
if testFlag == "3" { if testFlag == "true" {
log.Fatalln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" log.Fatalln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
} }
if testFlag == "4" { if testFlag == "true" {
log.Panic("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" log.Panic("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
} }
if testFlag == "5" { if testFlag == "true" {
log.Panicf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password" log.Panicf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
} }
if testFlag == "6" { if testFlag == "true" {
log.Panicln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" log.Panicln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
} }
@@ -72,25 +72,13 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
logger.Print("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" logger.Print("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
logger.Printf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password" logger.Printf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
logger.Println("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" logger.Println("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
if testFlag == "7" {
logger.Fatal("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" logger.Fatal("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
}
if testFlag == "8" {
logger.Fatalf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password" logger.Fatalf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
}
if testFlag == "9" {
logger.Fatalln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" logger.Fatalln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
}
if testFlag == "10" {
logger.Panic("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" logger.Panic("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
}
if testFlag == "11" {
logger.Panicf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password" logger.Panicf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
}
if testFlag == "12" {
logger.Panicln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password" logger.Panicln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
} }
}
// k8s.io/klog // k8s.io/klog
{ {
verbose := klog.V(0) verbose := klog.V(0)
@@ -103,25 +91,13 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
klog.Error(username) // $ hasTaintFlow="username" klog.Error(username) // $ hasTaintFlow="username"
klog.Errorf(username) // $ hasTaintFlow="username" klog.Errorf(username) // $ hasTaintFlow="username"
klog.Errorln(username) // $ hasTaintFlow="username" klog.Errorln(username) // $ hasTaintFlow="username"
if testFlag == "77" {
klog.Fatal(username) // $ hasTaintFlow="username" klog.Fatal(username) // $ hasTaintFlow="username"
}
if testFlag == "78" {
klog.Fatalf(username) // $ hasTaintFlow="username" klog.Fatalf(username) // $ hasTaintFlow="username"
}
if testFlag == "79" {
klog.Fatalln(username) // $ hasTaintFlow="username" klog.Fatalln(username) // $ hasTaintFlow="username"
}
if testFlag == "80" {
klog.Exit(username) // $ hasTaintFlow="username" klog.Exit(username) // $ hasTaintFlow="username"
}
if testFlag == "81" {
klog.Exitf(username) // $ hasTaintFlow="username" klog.Exitf(username) // $ hasTaintFlow="username"
}
if testFlag == "82" {
klog.Exitln(username) // $ hasTaintFlow="username" klog.Exitln(username) // $ hasTaintFlow="username"
} }
}
// astaxie/beego // astaxie/beego
{ {
beego.Alert(username) // $ hasTaintFlow="username" beego.Alert(username) // $ hasTaintFlow="username"
@@ -185,30 +161,14 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
glog.ErrorDepth(0, username) // $ hasTaintFlow="username" glog.ErrorDepth(0, username) // $ hasTaintFlow="username"
glog.Errorf(username) // $ hasTaintFlow="username" glog.Errorf(username) // $ hasTaintFlow="username"
glog.Errorln(username) // $ hasTaintFlow="username" glog.Errorln(username) // $ hasTaintFlow="username"
if testFlag == "83" {
glog.Fatal(username) // $ hasTaintFlow="username" glog.Fatal(username) // $ hasTaintFlow="username"
}
if testFlag == "84" {
glog.FatalDepth(0, username) // $ hasTaintFlow="username" glog.FatalDepth(0, username) // $ hasTaintFlow="username"
}
if testFlag == "85" {
glog.Fatalf(username) // $ hasTaintFlow="username" glog.Fatalf(username) // $ hasTaintFlow="username"
}
if testFlag == "86" {
glog.Fatalln(username) // $ hasTaintFlow="username" glog.Fatalln(username) // $ hasTaintFlow="username"
}
if testFlag == "87" {
glog.Exit(username) // $ hasTaintFlow="username" glog.Exit(username) // $ hasTaintFlow="username"
}
if testFlag == "88" {
glog.ExitDepth(0, username) // $ hasTaintFlow="username" glog.ExitDepth(0, username) // $ hasTaintFlow="username"
}
if testFlag == "89" {
glog.Exitf(username) // $ hasTaintFlow="username" glog.Exitf(username) // $ hasTaintFlow="username"
}
if testFlag == "90" {
glog.Exitln(username) // $ hasTaintFlow="username" glog.Exitln(username) // $ hasTaintFlow="username"
}
} }
// sirupsen/logrus // sirupsen/logrus
@@ -227,34 +187,18 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
logrus.Errorf(username, "") // $ hasTaintFlow="username" logrus.Errorf(username, "") // $ hasTaintFlow="username"
logrus.Errorf("", username) // $ hasTaintFlow="username" logrus.Errorf("", username) // $ hasTaintFlow="username"
logrus.Errorln(username) // $ hasTaintFlow="username" logrus.Errorln(username) // $ hasTaintFlow="username"
if testFlag == "13" {
logrus.Fatal(username) // $ hasTaintFlow="username" logrus.Fatal(username) // $ hasTaintFlow="username"
}
if testFlag == "14" {
logrus.Fatalf(username, "") // $ hasTaintFlow="username" logrus.Fatalf(username, "") // $ hasTaintFlow="username"
}
if testFlag == "15" {
logrus.Fatalf("", username) // $ hasTaintFlow="username" logrus.Fatalf("", username) // $ hasTaintFlow="username"
}
if testFlag == "16" {
logrus.Fatalln(username) // $ hasTaintFlow="username" logrus.Fatalln(username) // $ hasTaintFlow="username"
}
logrus.Info(username) // $ hasTaintFlow="username" logrus.Info(username) // $ hasTaintFlow="username"
logrus.Infof(username, "") // $ hasTaintFlow="username" logrus.Infof(username, "") // $ hasTaintFlow="username"
logrus.Infof("", username) // $ hasTaintFlow="username" logrus.Infof("", username) // $ hasTaintFlow="username"
logrus.Infoln(username) // $ hasTaintFlow="username" logrus.Infoln(username) // $ hasTaintFlow="username"
if testFlag == "17" {
logrus.Panic(username) // $ hasTaintFlow="username" logrus.Panic(username) // $ hasTaintFlow="username"
}
if testFlag == "18" {
logrus.Panicf(username, "") // $ hasTaintFlow="username" logrus.Panicf(username, "") // $ hasTaintFlow="username"
}
if testFlag == "19" {
logrus.Panicf("", username) // $ hasTaintFlow="username" logrus.Panicf("", username) // $ hasTaintFlow="username"
}
if testFlag == "20" {
logrus.Panicln(username) // $ hasTaintFlow="username" logrus.Panicln(username) // $ hasTaintFlow="username"
}
logrus.Print(username) // $ hasTaintFlow="username" logrus.Print(username) // $ hasTaintFlow="username"
logrus.Printf(username, "") // $ hasTaintFlow="username" logrus.Printf(username, "") // $ hasTaintFlow="username"
logrus.Printf("", username) // $ hasTaintFlow="username" logrus.Printf("", username) // $ hasTaintFlow="username"
@@ -284,18 +228,10 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
entry.Errorf(username, "") // $ hasTaintFlow="username" entry.Errorf(username, "") // $ hasTaintFlow="username"
entry.Errorf("", username) // $ hasTaintFlow="username" entry.Errorf("", username) // $ hasTaintFlow="username"
entry.Errorln(username) // $ hasTaintFlow="username" entry.Errorln(username) // $ hasTaintFlow="username"
if testFlag == "21" {
entry.Fatal(username) // $ hasTaintFlow="username" entry.Fatal(username) // $ hasTaintFlow="username"
}
if testFlag == "22" {
entry.Fatalf(username, "") // $ hasTaintFlow="username" entry.Fatalf(username, "") // $ hasTaintFlow="username"
}
if testFlag == "23" {
entry.Fatalf("", username) // $ hasTaintFlow="username" entry.Fatalf("", username) // $ hasTaintFlow="username"
}
if testFlag == "24" {
entry.Fatalln(username) // $ hasTaintFlow="username" entry.Fatalln(username) // $ hasTaintFlow="username"
}
entry.Info(username) // $ hasTaintFlow="username" entry.Info(username) // $ hasTaintFlow="username"
entry.Infof(username, "") // $ hasTaintFlow="username" entry.Infof(username, "") // $ hasTaintFlow="username"
entry.Infof("", username) // $ hasTaintFlow="username" entry.Infof("", username) // $ hasTaintFlow="username"
@@ -304,18 +240,10 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
entry.Logf(0, username, "") // $ hasTaintFlow="username" entry.Logf(0, username, "") // $ hasTaintFlow="username"
entry.Logf(0, "", username) // $ hasTaintFlow="username" entry.Logf(0, "", username) // $ hasTaintFlow="username"
entry.Logln(0, username) // $ hasTaintFlow="username" entry.Logln(0, username) // $ hasTaintFlow="username"
if testFlag == "25" {
entry.Panic(username) // $ hasTaintFlow="username" entry.Panic(username) // $ hasTaintFlow="username"
}
if testFlag == "26" {
entry.Panicf(username, "") // $ hasTaintFlow="username" entry.Panicf(username, "") // $ hasTaintFlow="username"
}
if testFlag == "27" {
entry.Panicf("", username) // $ hasTaintFlow="username" entry.Panicf("", username) // $ hasTaintFlow="username"
}
if testFlag == "28" {
entry.Panicln(username) // $ hasTaintFlow="username" entry.Panicln(username) // $ hasTaintFlow="username"
}
entry.Print(username) // $ hasTaintFlow="username" entry.Print(username) // $ hasTaintFlow="username"
entry.Printf(username, "") // $ hasTaintFlow="username" entry.Printf(username, "") // $ hasTaintFlow="username"
entry.Printf("", username) // $ hasTaintFlow="username" entry.Printf("", username) // $ hasTaintFlow="username"
@@ -345,18 +273,10 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
logger.Errorf(username, "") // $ hasTaintFlow="username" logger.Errorf(username, "") // $ hasTaintFlow="username"
logger.Errorf("", username) // $ hasTaintFlow="username" logger.Errorf("", username) // $ hasTaintFlow="username"
logger.Errorln(username) // $ hasTaintFlow="username" logger.Errorln(username) // $ hasTaintFlow="username"
if testFlag == "29" {
logger.Fatal(username) // $ hasTaintFlow="username" logger.Fatal(username) // $ hasTaintFlow="username"
}
if testFlag == "30" {
logger.Fatalf(username, "") // $ hasTaintFlow="username" logger.Fatalf(username, "") // $ hasTaintFlow="username"
}
if testFlag == "31" {
logger.Fatalf("", username) // $ hasTaintFlow="username" logger.Fatalf("", username) // $ hasTaintFlow="username"
}
if testFlag == "32" {
logger.Fatalln(username) // $ hasTaintFlow="username" logger.Fatalln(username) // $ hasTaintFlow="username"
}
logger.Info(username) // $ hasTaintFlow="username" logger.Info(username) // $ hasTaintFlow="username"
logger.Infof(username, "") // $ hasTaintFlow="username" logger.Infof(username, "") // $ hasTaintFlow="username"
logger.Infof("", username) // $ hasTaintFlow="username" logger.Infof("", username) // $ hasTaintFlow="username"
@@ -365,18 +285,10 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
logger.Logf(0, username, "") // $ hasTaintFlow="username" logger.Logf(0, username, "") // $ hasTaintFlow="username"
logger.Logf(0, "", username) // $ hasTaintFlow="username" logger.Logf(0, "", username) // $ hasTaintFlow="username"
logger.Logln(0, username) // $ hasTaintFlow="username" logger.Logln(0, username) // $ hasTaintFlow="username"
if testFlag == "33" {
logger.Panic(username) // $ hasTaintFlow="username" logger.Panic(username) // $ hasTaintFlow="username"
}
if testFlag == "34" {
logger.Panicf(username, "") // $ hasTaintFlow="username" logger.Panicf(username, "") // $ hasTaintFlow="username"
}
if testFlag == "35" {
logger.Panicf("", username) // $ hasTaintFlow="username" logger.Panicf("", username) // $ hasTaintFlow="username"
}
if testFlag == "36" {
logger.Panicln(username) // $ hasTaintFlow="username" logger.Panicln(username) // $ hasTaintFlow="username"
}
logger.Print(username) // $ hasTaintFlow="username" logger.Print(username) // $ hasTaintFlow="username"
logger.Printf(username, "") // $ hasTaintFlow="username" logger.Printf(username, "") // $ hasTaintFlow="username"
logger.Printf("", username) // $ hasTaintFlow="username" logger.Printf("", username) // $ hasTaintFlow="username"
@@ -407,34 +319,18 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
fieldlogger.Errorf(username, "") // $ hasTaintFlow="username" fieldlogger.Errorf(username, "") // $ hasTaintFlow="username"
fieldlogger.Errorf("", username) // $ hasTaintFlow="username" fieldlogger.Errorf("", username) // $ hasTaintFlow="username"
fieldlogger.Errorln(username) // $ hasTaintFlow="username" fieldlogger.Errorln(username) // $ hasTaintFlow="username"
if testFlag == "37" {
fieldlogger.Fatal(username) // $ hasTaintFlow="username" fieldlogger.Fatal(username) // $ hasTaintFlow="username"
}
if testFlag == "38" {
fieldlogger.Fatalf(username, "") // $ hasTaintFlow="username" fieldlogger.Fatalf(username, "") // $ hasTaintFlow="username"
}
if testFlag == "39" {
fieldlogger.Fatalf("", username) // $ hasTaintFlow="username" fieldlogger.Fatalf("", username) // $ hasTaintFlow="username"
}
if testFlag == "40" {
fieldlogger.Fatalln(username) // $ hasTaintFlow="username" fieldlogger.Fatalln(username) // $ hasTaintFlow="username"
}
fieldlogger.Info(username) // $ hasTaintFlow="username" fieldlogger.Info(username) // $ hasTaintFlow="username"
fieldlogger.Infof(username, "") // $ hasTaintFlow="username" fieldlogger.Infof(username, "") // $ hasTaintFlow="username"
fieldlogger.Infof("", username) // $ hasTaintFlow="username" fieldlogger.Infof("", username) // $ hasTaintFlow="username"
fieldlogger.Infoln(username) // $ hasTaintFlow="username" fieldlogger.Infoln(username) // $ hasTaintFlow="username"
if testFlag == "41" {
fieldlogger.Panic(username) // $ hasTaintFlow="username" fieldlogger.Panic(username) // $ hasTaintFlow="username"
}
if testFlag == "42" {
fieldlogger.Panicf(username, "") // $ hasTaintFlow="username" fieldlogger.Panicf(username, "") // $ hasTaintFlow="username"
}
if testFlag == "43" {
fieldlogger.Panicf("", username) // $ hasTaintFlow="username" fieldlogger.Panicf("", username) // $ hasTaintFlow="username"
}
if testFlag == "44" {
fieldlogger.Panicln(username) // $ hasTaintFlow="username" fieldlogger.Panicln(username) // $ hasTaintFlow="username"
}
fieldlogger.Print(username) // $ hasTaintFlow="username" fieldlogger.Print(username) // $ hasTaintFlow="username"
fieldlogger.Printf(username, "") // $ hasTaintFlow="username" fieldlogger.Printf(username, "") // $ hasTaintFlow="username"
fieldlogger.Printf("", username) // $ hasTaintFlow="username" fieldlogger.Printf("", username) // $ hasTaintFlow="username"
@@ -470,11 +366,11 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
logger.DPanic(username) // $ hasTaintFlow="username" logger.DPanic(username) // $ hasTaintFlow="username"
logger.Debug(username) // $ hasTaintFlow="username" logger.Debug(username) // $ hasTaintFlow="username"
logger.Error(username) // $ hasTaintFlow="username" logger.Error(username) // $ hasTaintFlow="username"
if testFlag == "45" { if testFlag == " true" {
logger.Fatal(username) // $ hasTaintFlow="username" logger.Fatal(username) // $ hasTaintFlow="username"
} }
logger.Info(username) // $ hasTaintFlow="username" logger.Info(username) // $ hasTaintFlow="username"
if testFlag == "46" { if testFlag == " true" {
logger.Panic(username) // $ hasTaintFlow="username" logger.Panic(username) // $ hasTaintFlow="username"
} }
logger.Warn(username) // $ hasTaintFlow="username" logger.Warn(username) // $ hasTaintFlow="username"
@@ -486,33 +382,33 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
sLogger.DPanic(username) // $ hasTaintFlow="username" sLogger.DPanic(username) // $ hasTaintFlow="username"
sLogger.Debug(username) // $ hasTaintFlow="username" sLogger.Debug(username) // $ hasTaintFlow="username"
sLogger.Error(username) // $ hasTaintFlow="username" sLogger.Error(username) // $ hasTaintFlow="username"
if testFlag == "47" { if testFlag == " true" {
sLogger.Fatal(username) // $ hasTaintFlow="username" sLogger.Fatal(username) // $ hasTaintFlow="username"
} }
sLogger.Info(username) // $ hasTaintFlow="username" sLogger.Info(username) // $ hasTaintFlow="username"
if testFlag == "48" { if testFlag == " true" {
sLogger.Panic(username) // $ hasTaintFlow="username" sLogger.Panic(username) // $ hasTaintFlow="username"
} }
sLogger.Warn(username) // $ hasTaintFlow="username" sLogger.Warn(username) // $ hasTaintFlow="username"
sLogger.DPanicf(username) // $ hasTaintFlow="username" sLogger.DPanicf(username) // $ hasTaintFlow="username"
sLogger.Debugf(username) // $ hasTaintFlow="username" sLogger.Debugf(username) // $ hasTaintFlow="username"
sLogger.Errorf(username) // $ hasTaintFlow="username" sLogger.Errorf(username) // $ hasTaintFlow="username"
if testFlag == "49" { if testFlag == " true" {
sLogger.Fatalf(username) // $ hasTaintFlow="username" sLogger.Fatalf(username) // $ hasTaintFlow="username"
} }
sLogger.Infof(username) // $ hasTaintFlow="username" sLogger.Infof(username) // $ hasTaintFlow="username"
if testFlag == "50" { if testFlag == " true" {
sLogger.Panicf(username) // $ hasTaintFlow="username" sLogger.Panicf(username) // $ hasTaintFlow="username"
} }
sLogger.Warnf(username) // $ hasTaintFlow="username" sLogger.Warnf(username) // $ hasTaintFlow="username"
sLogger.DPanicw(username) // $ hasTaintFlow="username" sLogger.DPanicw(username) // $ hasTaintFlow="username"
sLogger.Debugw(username) // $ hasTaintFlow="username" sLogger.Debugw(username) // $ hasTaintFlow="username"
sLogger.Errorw(username) // $ hasTaintFlow="username" sLogger.Errorw(username) // $ hasTaintFlow="username"
if testFlag == "51" { if testFlag == " true" {
sLogger.Fatalw(username) // $ hasTaintFlow="username" sLogger.Fatalw(username) // $ hasTaintFlow="username"
} }
sLogger.Infow(username) // $ hasTaintFlow="username" sLogger.Infow(username) // $ hasTaintFlow="username"
if testFlag == "52" { if testFlag == " true" {
sLogger.Panicw(username) // $ hasTaintFlow="username" sLogger.Panicw(username) // $ hasTaintFlow="username"
} }
sLogger.Warnw(username) // $ hasTaintFlow="username" sLogger.Warnw(username) // $ hasTaintFlow="username"
@@ -619,10 +515,10 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
verbose.Infof("user %q logged in.\n", username) verbose.Infof("user %q logged in.\n", username)
klog.Infof("user %q logged in.\n", username) klog.Infof("user %q logged in.\n", username)
klog.Errorf("user %q logged in.\n", username) klog.Errorf("user %q logged in.\n", username)
if testFlag == "53" { if testFlag == " true" {
klog.Fatalf("user %q logged in.\n", username) klog.Fatalf("user %q logged in.\n", username)
} }
if testFlag == "54" { if testFlag == " true" {
klog.Exitf("user %q logged in.\n", username) klog.Exitf("user %q logged in.\n", username)
} }
} }
@@ -638,10 +534,10 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
glog.Infof("user %q logged in.\n", username) glog.Infof("user %q logged in.\n", username)
glog.Errorf("user %q logged in.\n", username) glog.Errorf("user %q logged in.\n", username)
if testFlag == "55" { if testFlag == " true" {
glog.Fatalf("user %q logged in.\n", username) glog.Fatalf("user %q logged in.\n", username)
} }
if testFlag == "56" { if testFlag == " true" {
glog.Exitf("user %q logged in.\n", username) glog.Exitf("user %q logged in.\n", username)
} }
} }
@@ -649,11 +545,11 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
{ {
logrus.Debugf("user %q logged in.\n", username) logrus.Debugf("user %q logged in.\n", username)
logrus.Errorf("user %q logged in.\n", username) logrus.Errorf("user %q logged in.\n", username)
if testFlag == "57" { if testFlag == " true" {
logrus.Fatalf("user %q logged in.\n", username) logrus.Fatalf("user %q logged in.\n", username)
} }
logrus.Infof("user %q logged in.\n", username) logrus.Infof("user %q logged in.\n", username)
if testFlag == "58" { if testFlag == " true" {
logrus.Panicf("user %q logged in.\n", username) logrus.Panicf("user %q logged in.\n", username)
} }
logrus.Printf("user %q logged in.\n", username) logrus.Printf("user %q logged in.\n", username)
@@ -665,12 +561,12 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
entry := logrus.WithFields(fields) entry := logrus.WithFields(fields)
entry.Debugf("user %q logged in.\n", username) entry.Debugf("user %q logged in.\n", username)
entry.Errorf("user %q logged in.\n", username) entry.Errorf("user %q logged in.\n", username)
if testFlag == "59" { if testFlag == " true" {
entry.Fatalf("user %q logged in.\n", username) entry.Fatalf("user %q logged in.\n", username)
} }
entry.Infof("user %q logged in.\n", username) entry.Infof("user %q logged in.\n", username)
entry.Logf(0, "user %q logged in.\n", username) entry.Logf(0, "user %q logged in.\n", username)
if testFlag == "60" { if testFlag == " true" {
entry.Panicf("user %q logged in.\n", username) entry.Panicf("user %q logged in.\n", username)
} }
entry.Printf("user %q logged in.\n", username) entry.Printf("user %q logged in.\n", username)
@@ -681,12 +577,12 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
logger := entry.Logger logger := entry.Logger
logger.Debugf("user %q logged in.\n", username) logger.Debugf("user %q logged in.\n", username)
logger.Errorf("user %q logged in.\n", username) logger.Errorf("user %q logged in.\n", username)
if testFlag == "61" { if testFlag == " true" {
logger.Fatalf("user %q logged in.\n", username) logger.Fatalf("user %q logged in.\n", username)
} }
logger.Infof("user %q logged in.\n", username) logger.Infof("user %q logged in.\n", username)
logger.Logf(0, "user %q logged in.\n", username) logger.Logf(0, "user %q logged in.\n", username)
if testFlag == "62" { if testFlag == " true" {
logger.Panicf("user %q logged in.\n", username) logger.Panicf("user %q logged in.\n", username)
} }
logger.Printf("user %q logged in.\n", username) logger.Printf("user %q logged in.\n", username)
@@ -707,11 +603,11 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
sLogger.DPanicf("user %q logged in.\n", username) sLogger.DPanicf("user %q logged in.\n", username)
sLogger.Debugf("user %q logged in.\n", username) sLogger.Debugf("user %q logged in.\n", username)
sLogger.Errorf("user %q logged in.\n", username) sLogger.Errorf("user %q logged in.\n", username)
if testFlag == "63" { if testFlag == " true" {
sLogger.Fatalf("user %q logged in.\n", username) sLogger.Fatalf("user %q logged in.\n", username)
} }
sLogger.Infof("user %q logged in.\n", username) sLogger.Infof("user %q logged in.\n", username)
if testFlag == "64" { if testFlag == " true" {
sLogger.Panicf("user %q logged in.\n", username) sLogger.Panicf("user %q logged in.\n", username)
} }
sLogger.Warnf("user %q logged in.\n", username) sLogger.Warnf("user %q logged in.\n", username)
@@ -724,10 +620,10 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
verbose.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username" verbose.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
klog.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username" klog.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
klog.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username" klog.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == "65" { if testFlag == " true" {
klog.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username" klog.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
if testFlag == "66" { if testFlag == " true" {
klog.Exitf("user %#q logged in.\n", username) // $ hasTaintFlow="username" klog.Exitf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
} }
@@ -743,10 +639,10 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
glog.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username" glog.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
glog.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username" glog.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == "67" { if testFlag == " true" {
glog.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username" glog.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
if testFlag == "68" { if testFlag == " true" {
glog.Exitf("user %#q logged in.\n", username) // $ hasTaintFlow="username" glog.Exitf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
} }
@@ -754,11 +650,11 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
{ {
logrus.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username" logrus.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logrus.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username" logrus.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == "69" { if testFlag == " true" {
logrus.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username" logrus.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
logrus.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username" logrus.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == "70" { if testFlag == " true" {
logrus.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username" logrus.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
logrus.Printf("user %#q logged in.\n", username) // $ hasTaintFlow="username" logrus.Printf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
@@ -770,12 +666,12 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
entry := logrus.WithFields(fields) entry := logrus.WithFields(fields)
entry.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username" entry.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username" entry.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == "71" { if testFlag == " true" {
entry.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username" entry.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
entry.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username" entry.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Logf(0, "user %#q logged in.\n", username) // $ hasTaintFlow="username" entry.Logf(0, "user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == "72" { if testFlag == " true" {
entry.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username" entry.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
entry.Printf("user %#q logged in.\n", username) // $ hasTaintFlow="username" entry.Printf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
@@ -786,12 +682,12 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
logger := entry.Logger logger := entry.Logger
logger.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username" logger.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username" logger.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == "73" { if testFlag == " true" {
logger.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username" logger.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
logger.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username" logger.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Logf(0, "user %#q logged in.\n", username) // $ hasTaintFlow="username" logger.Logf(0, "user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == "74" { if testFlag == " true" {
logger.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username" logger.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
logger.Printf("user %#q logged in.\n", username) // $ hasTaintFlow="username" logger.Printf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
@@ -812,11 +708,11 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
sLogger.DPanicf("user %#q logged in.\n", username) // $ hasTaintFlow="username" sLogger.DPanicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
sLogger.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username" sLogger.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
sLogger.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username" sLogger.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == "75" { if testFlag == " true" {
sLogger.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username" sLogger.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
sLogger.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username" sLogger.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == "76" { if testFlag == " true" {
sLogger.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username" sLogger.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
} }
sLogger.Warnf("user %#q logged in.\n", username) // $ hasTaintFlow="username" sLogger.Warnf("user %#q logged in.\n", username) // $ hasTaintFlow="username"

View File

@@ -37,22 +37,22 @@
| passwords.go:26:14:26:23 | selection of password | passwords.go:26:14:26:23 | selection of password | passwords.go:26:14:26:23 | selection of password | $@ flows to a logging call. | passwords.go:26:14:26:23 | selection of password | Sensitive data returned by an access to password | | passwords.go:26:14:26:23 | selection of password | passwords.go:26:14:26:23 | selection of password | passwords.go:26:14:26:23 | selection of password | $@ flows to a logging call. | passwords.go:26:14:26:23 | selection of password | Sensitive data returned by an access to password |
| passwords.go:27:14:27:26 | call to getPassword | passwords.go:27:14:27:26 | call to getPassword | passwords.go:27:14:27:26 | call to getPassword | $@ flows to a logging call. | passwords.go:27:14:27:26 | call to getPassword | Sensitive data returned by a call to getPassword | | passwords.go:27:14:27:26 | call to getPassword | passwords.go:27:14:27:26 | call to getPassword | passwords.go:27:14:27:26 | call to getPassword | $@ flows to a logging call. | passwords.go:27:14:27:26 | call to getPassword | Sensitive data returned by a call to getPassword |
| passwords.go:28:14:28:28 | call to getPassword | passwords.go:28:14:28:28 | call to getPassword | passwords.go:28:14:28:28 | call to getPassword | $@ flows to a logging call. | passwords.go:28:14:28:28 | call to getPassword | Sensitive data returned by a call to getPassword | | passwords.go:28:14:28:28 | call to getPassword | passwords.go:28:14:28:28 | call to getPassword | passwords.go:28:14:28:28 | call to getPassword | $@ flows to a logging call. | passwords.go:28:14:28:28 | call to getPassword | Sensitive data returned by a call to getPassword |
| passwords.go:33:13:33:20 | password | passwords.go:21:2:21:9 | definition of password | passwords.go:33:13:33:20 | password | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | | passwords.go:32:12:32:19 | password | passwords.go:21:2:21:9 | definition of password | passwords.go:32:12:32:19 | password | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password |
| passwords.go:36:14:36:35 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:36:14:36:35 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | | passwords.go:34:14:34:35 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:34:14:34:35 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password |
| passwords.go:41:14:41:17 | obj1 | passwords.go:39:13:39:13 | x | passwords.go:41:14:41:17 | obj1 | $@ flows to a logging call. | passwords.go:39:13:39:13 | x | Sensitive data returned by an access to password | | passwords.go:39:14:39:17 | obj1 | passwords.go:37:13:37:13 | x | passwords.go:39:14:39:17 | obj1 | $@ flows to a logging call. | passwords.go:37:13:37:13 | x | Sensitive data returned by an access to password |
| passwords.go:46:14:46:17 | obj2 | passwords.go:21:2:21:9 | definition of password | passwords.go:46:14:46:17 | obj2 | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | | passwords.go:44:14:44:17 | obj2 | passwords.go:21:2:21:9 | definition of password | passwords.go:44:14:44:17 | obj2 | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password |
| passwords.go:53:14:53:27 | fixed_password | passwords.go:52:2:52:15 | definition of fixed_password | passwords.go:53:14:53:27 | fixed_password | $@ flows to a logging call. | passwords.go:52:2:52:15 | definition of fixed_password | Sensitive data returned by an access to fixed_password | | passwords.go:51:14:51:27 | fixed_password | passwords.go:50:2:50:15 | definition of fixed_password | passwords.go:51:14:51:27 | fixed_password | $@ flows to a logging call. | passwords.go:50:2:50:15 | definition of fixed_password | Sensitive data returned by an access to fixed_password |
| passwords.go:91:14:91:26 | utilityObject | passwords.go:89:16:89:36 | call to make | passwords.go:91:14:91:26 | utilityObject | $@ flows to a logging call. | passwords.go:89:16:89:36 | call to make | Sensitive data returned by an access to passwordSet | | passwords.go:89:14:89:26 | utilityObject | passwords.go:87:16:87:36 | call to make | passwords.go:89:14:89:26 | utilityObject | $@ flows to a logging call. | passwords.go:87:16:87:36 | call to make | Sensitive data returned by an access to passwordSet |
| passwords.go:94:23:94:28 | secret | passwords.go:21:2:21:9 | definition of password | passwords.go:94:23:94:28 | secret | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | | passwords.go:92:23:92:28 | secret | passwords.go:21:2:21:9 | definition of password | passwords.go:92:23:92:28 | secret | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password |
| passwords.go:104:15:104:40 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:104:15:104:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | | passwords.go:102:15:102:40 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:102:15:102:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password |
| passwords.go:110:16:110:41 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:110:16:110:41 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | | passwords.go:108:16:108:41 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:108:16:108:41 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password |
| passwords.go:115:15:115:40 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:115:15:115:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | | passwords.go:113:15:113:40 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:113:15:113:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password |
| passwords.go:119:14:119:45 | ...+... | passwords.go:118:6:118:14 | definition of password1 | passwords.go:119:14:119:45 | ...+... | $@ flows to a logging call. | passwords.go:118:6:118:14 | definition of password1 | Sensitive data returned by an access to password1 | | passwords.go:117:14:117:45 | ...+... | passwords.go:116:6:116:14 | definition of password1 | passwords.go:117:14:117:45 | ...+... | $@ flows to a logging call. | passwords.go:116:6:116:14 | definition of password1 | Sensitive data returned by an access to password1 |
| passwords.go:129:14:129:19 | config | passwords.go:21:2:21:9 | definition of password | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | | passwords.go:127:14:127:19 | config | passwords.go:21:2:21:9 | definition of password | passwords.go:127:14:127:19 | config | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password |
| passwords.go:129:14:129:19 | config | passwords.go:123:13:123:14 | x3 | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:123:13:123:14 | x3 | Sensitive data returned by an access to password | | passwords.go:127:14:127:19 | config | passwords.go:121:13:121:14 | x3 | passwords.go:127:14:127:19 | config | $@ flows to a logging call. | passwords.go:121:13:121:14 | x3 | Sensitive data returned by an access to password |
| passwords.go:129:14:129:19 | config | passwords.go:126:13:126:25 | call to getPassword | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:126:13:126:25 | call to getPassword | Sensitive data returned by a call to getPassword | | passwords.go:127:14:127:19 | config | passwords.go:124:13:124:25 | call to getPassword | passwords.go:127:14:127:19 | config | $@ flows to a logging call. | passwords.go:124:13:124:25 | call to getPassword | Sensitive data returned by a call to getPassword |
| passwords.go:130:14:130:21 | selection of x | passwords.go:21:2:21:9 | definition of password | passwords.go:130:14:130:21 | selection of x | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | | passwords.go:128:14:128:21 | selection of x | passwords.go:21:2:21:9 | definition of password | passwords.go:128:14:128:21 | selection of x | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password |
| passwords.go:131:14:131:21 | selection of y | passwords.go:126:13:126:25 | call to getPassword | passwords.go:131:14:131:21 | selection of y | $@ flows to a logging call. | passwords.go:126:13:126:25 | call to getPassword | Sensitive data returned by a call to getPassword | | passwords.go:129:14:129:21 | selection of y | passwords.go:124:13:124:25 | call to getPassword | passwords.go:129:14:129:21 | selection of y | $@ flows to a logging call. | passwords.go:124:13:124:25 | call to getPassword | Sensitive data returned by a call to getPassword |
| protobuf.go:14:14:14:35 | call to GetDescription | protobuf.go:9:2:9:9 | definition of password | protobuf.go:14:14:14:35 | call to GetDescription | $@ flows to a logging call. | protobuf.go:9:2:9:9 | definition of password | Sensitive data returned by an access to password | | protobuf.go:14:14:14:35 | call to GetDescription | protobuf.go:9:2:9:9 | definition of password | protobuf.go:14:14:14:35 | call to GetDescription | $@ flows to a logging call. | protobuf.go:9:2:9:9 | definition of password | Sensitive data returned by an access to password |
edges edges
| klog.go:21:3:26:3 | range statement[1] | klog.go:22:27:22:33 | headers | provenance | | | klog.go:21:3:26:3 | range statement[1] | klog.go:22:27:22:33 | headers | provenance | |
@@ -82,15 +82,95 @@ edges
| main.go:53:11:53:18 | password | main.go:54:12:54:19 | password | provenance | | | main.go:53:11:53:18 | password | main.go:54:12:54:19 | password | provenance | |
| main.go:53:11:53:18 | password | main.go:54:12:54:19 | password | provenance | | | main.go:53:11:53:18 | password | main.go:54:12:54:19 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:56:11:56:18 | password | provenance | | | main.go:54:12:54:19 | password | main.go:56:11:56:18 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:56:11:56:18 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:59:18:59:25 | password | provenance | | | main.go:54:12:54:19 | password | main.go:59:18:59:25 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:59:18:59:25 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:62:12:62:19 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:62:12:62:19 | password | provenance | Sink:MaD:7 | | main.go:54:12:54:19 | password | main.go:62:12:62:19 | password | provenance | Sink:MaD:7 |
| main.go:54:12:54:19 | password | main.go:65:13:65:20 | password | provenance | | | main.go:54:12:54:19 | password | main.go:65:13:65:20 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:65:13:65:20 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:68:11:68:18 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:68:11:68:18 | password | provenance | | | main.go:54:12:54:19 | password | main.go:68:11:68:18 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:71:18:71:25 | password | provenance | | | main.go:54:12:54:19 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:74:12:74:19 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:74:12:74:19 | password | provenance | Sink:MaD:9 | | main.go:54:12:54:19 | password | main.go:74:12:74:19 | password | provenance | Sink:MaD:9 |
| main.go:54:12:54:19 | password | main.go:77:13:77:20 | password | provenance | | | main.go:54:12:54:19 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:54:12:54:19 | password | main.go:79:14:79:21 | password | provenance | Sink:MaD:8 | | main.go:54:12:54:19 | password | main.go:79:14:79:21 | password | provenance | Sink:MaD:8 |
| main.go:54:12:54:19 | password | main.go:80:17:80:24 | password | provenance | | | main.go:54:12:54:19 | password | main.go:80:17:80:24 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:59:18:59:25 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:59:18:59:25 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:62:12:62:19 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:62:12:62:19 | password | provenance | Sink:MaD:7 |
| main.go:56:11:56:18 | password | main.go:65:13:65:20 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:65:13:65:20 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:68:11:68:18 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:68:11:68:18 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:74:12:74:19 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:74:12:74:19 | password | provenance | Sink:MaD:9 |
| main.go:56:11:56:18 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:56:11:56:18 | password | main.go:79:14:79:21 | password | provenance | Sink:MaD:8 |
| main.go:56:11:56:18 | password | main.go:80:17:80:24 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:62:12:62:19 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:62:12:62:19 | password | provenance | Sink:MaD:7 |
| main.go:59:18:59:25 | password | main.go:65:13:65:20 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:65:13:65:20 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:68:11:68:18 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:68:11:68:18 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:74:12:74:19 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:74:12:74:19 | password | provenance | Sink:MaD:9 |
| main.go:59:18:59:25 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:59:18:59:25 | password | main.go:79:14:79:21 | password | provenance | Sink:MaD:8 |
| main.go:59:18:59:25 | password | main.go:80:17:80:24 | password | provenance | |
| main.go:62:12:62:19 | password | main.go:65:13:65:20 | password | provenance | |
| main.go:62:12:62:19 | password | main.go:65:13:65:20 | password | provenance | |
| main.go:62:12:62:19 | password | main.go:68:11:68:18 | password | provenance | |
| main.go:62:12:62:19 | password | main.go:68:11:68:18 | password | provenance | |
| main.go:62:12:62:19 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:62:12:62:19 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:62:12:62:19 | password | main.go:74:12:74:19 | password | provenance | |
| main.go:62:12:62:19 | password | main.go:74:12:74:19 | password | provenance | Sink:MaD:9 |
| main.go:62:12:62:19 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:62:12:62:19 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:62:12:62:19 | password | main.go:79:14:79:21 | password | provenance | Sink:MaD:8 |
| main.go:62:12:62:19 | password | main.go:80:17:80:24 | password | provenance | |
| main.go:65:13:65:20 | password | main.go:68:11:68:18 | password | provenance | |
| main.go:65:13:65:20 | password | main.go:68:11:68:18 | password | provenance | |
| main.go:65:13:65:20 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:65:13:65:20 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:65:13:65:20 | password | main.go:74:12:74:19 | password | provenance | |
| main.go:65:13:65:20 | password | main.go:74:12:74:19 | password | provenance | Sink:MaD:9 |
| main.go:65:13:65:20 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:65:13:65:20 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:65:13:65:20 | password | main.go:79:14:79:21 | password | provenance | Sink:MaD:8 |
| main.go:65:13:65:20 | password | main.go:80:17:80:24 | password | provenance | |
| main.go:68:11:68:18 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:68:11:68:18 | password | main.go:71:18:71:25 | password | provenance | |
| main.go:68:11:68:18 | password | main.go:74:12:74:19 | password | provenance | |
| main.go:68:11:68:18 | password | main.go:74:12:74:19 | password | provenance | Sink:MaD:9 |
| main.go:68:11:68:18 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:68:11:68:18 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:68:11:68:18 | password | main.go:79:14:79:21 | password | provenance | Sink:MaD:8 |
| main.go:68:11:68:18 | password | main.go:80:17:80:24 | password | provenance | |
| main.go:71:18:71:25 | password | main.go:74:12:74:19 | password | provenance | |
| main.go:71:18:71:25 | password | main.go:74:12:74:19 | password | provenance | Sink:MaD:9 |
| main.go:71:18:71:25 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:71:18:71:25 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:71:18:71:25 | password | main.go:79:14:79:21 | password | provenance | Sink:MaD:8 |
| main.go:71:18:71:25 | password | main.go:80:17:80:24 | password | provenance | |
| main.go:74:12:74:19 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:74:12:74:19 | password | main.go:77:13:77:20 | password | provenance | |
| main.go:74:12:74:19 | password | main.go:79:14:79:21 | password | provenance | Sink:MaD:8 |
| main.go:74:12:74:19 | password | main.go:80:17:80:24 | password | provenance | |
| main.go:77:13:77:20 | password | main.go:79:14:79:21 | password | provenance | Sink:MaD:8 |
| main.go:77:13:77:20 | password | main.go:80:17:80:24 | password | provenance | |
| main.go:80:17:80:24 | password | main.go:82:12:82:19 | password | provenance | | | main.go:80:17:80:24 | password | main.go:82:12:82:19 | password | provenance | |
| main.go:80:17:80:24 | password | main.go:83:17:83:24 | password | provenance | | | main.go:80:17:80:24 | password | main.go:83:17:83:24 | password | provenance | |
| main.go:80:17:80:24 | password | main.go:86:19:86:26 | password | provenance | | | main.go:80:17:80:24 | password | main.go:86:19:86:26 | password | provenance | |
@@ -102,46 +182,46 @@ edges
| passwords.go:8:12:8:12 | definition of x | passwords.go:9:14:9:14 | x | provenance | | | passwords.go:8:12:8:12 | definition of x | passwords.go:9:14:9:14 | x | provenance | |
| passwords.go:21:2:21:9 | definition of password | passwords.go:25:14:25:21 | password | provenance | | | passwords.go:21:2:21:9 | definition of password | passwords.go:25:14:25:21 | password | provenance | |
| passwords.go:21:2:21:9 | definition of password | passwords.go:30:8:30:15 | password | provenance | | | passwords.go:21:2:21:9 | definition of password | passwords.go:30:8:30:15 | password | provenance | |
| passwords.go:21:2:21:9 | definition of password | passwords.go:33:13:33:20 | password | provenance | | | passwords.go:21:2:21:9 | definition of password | passwords.go:32:12:32:19 | password | provenance | |
| passwords.go:21:2:21:9 | definition of password | passwords.go:36:28:36:35 | password | provenance | | | passwords.go:21:2:21:9 | definition of password | passwords.go:34:28:34:35 | password | provenance | |
| passwords.go:30:8:30:15 | password | passwords.go:8:12:8:12 | definition of x | provenance | | | passwords.go:30:8:30:15 | password | passwords.go:8:12:8:12 | definition of x | provenance | |
| passwords.go:36:28:36:35 | password | passwords.go:36:14:36:35 | ...+... | provenance | Config | | passwords.go:34:28:34:35 | password | passwords.go:34:14:34:35 | ...+... | provenance | Config |
| passwords.go:36:28:36:35 | password | passwords.go:44:6:44:13 | password | provenance | | | passwords.go:34:28:34:35 | password | passwords.go:42:6:42:13 | password | provenance | |
| passwords.go:38:10:40:2 | struct literal | passwords.go:41:14:41:17 | obj1 | provenance | | | passwords.go:36:10:38:2 | struct literal | passwords.go:39:14:39:17 | obj1 | provenance | |
| passwords.go:39:13:39:13 | x | passwords.go:38:10:40:2 | struct literal | provenance | Config | | passwords.go:37:13:37:13 | x | passwords.go:36:10:38:2 | struct literal | provenance | Config |
| passwords.go:43:10:45:2 | struct literal | passwords.go:46:14:46:17 | obj2 | provenance | | | passwords.go:41:10:43:2 | struct literal | passwords.go:44:14:44:17 | obj2 | provenance | |
| passwords.go:44:6:44:13 | password | passwords.go:43:10:45:2 | struct literal | provenance | Config | | passwords.go:42:6:42:13 | password | passwords.go:41:10:43:2 | struct literal | provenance | Config |
| passwords.go:44:6:44:13 | password | passwords.go:50:11:50:18 | password | provenance | | | passwords.go:42:6:42:13 | password | passwords.go:48:11:48:18 | password | provenance | |
| passwords.go:50:11:50:18 | password | passwords.go:94:23:94:28 | secret | provenance | | | passwords.go:48:11:48:18 | password | passwords.go:92:23:92:28 | secret | provenance | |
| passwords.go:50:11:50:18 | password | passwords.go:104:33:104:40 | password | provenance | | | passwords.go:48:11:48:18 | password | passwords.go:102:33:102:40 | password | provenance | |
| passwords.go:50:11:50:18 | password | passwords.go:110:34:110:41 | password | provenance | | | passwords.go:48:11:48:18 | password | passwords.go:108:34:108:41 | password | provenance | |
| passwords.go:50:11:50:18 | password | passwords.go:115:33:115:40 | password | provenance | | | passwords.go:48:11:48:18 | password | passwords.go:113:33:113:40 | password | provenance | |
| passwords.go:50:11:50:18 | password | passwords.go:125:13:125:20 | password | provenance | | | passwords.go:48:11:48:18 | password | passwords.go:123:13:123:20 | password | provenance | |
| passwords.go:52:2:52:15 | definition of fixed_password | passwords.go:53:14:53:27 | fixed_password | provenance | | | passwords.go:50:2:50:15 | definition of fixed_password | passwords.go:51:14:51:27 | fixed_password | provenance | |
| passwords.go:88:19:90:2 | struct literal | passwords.go:91:14:91:26 | utilityObject | provenance | | | passwords.go:86:19:88:2 | struct literal | passwords.go:89:14:89:26 | utilityObject | provenance | |
| passwords.go:89:16:89:36 | call to make | passwords.go:88:19:90:2 | struct literal | provenance | Config | | passwords.go:87:16:87:36 | call to make | passwords.go:86:19:88:2 | struct literal | provenance | Config |
| passwords.go:104:33:104:40 | password | passwords.go:104:15:104:40 | ...+... | provenance | Config | | passwords.go:102:33:102:40 | password | passwords.go:102:15:102:40 | ...+... | provenance | Config |
| passwords.go:104:33:104:40 | password | passwords.go:110:34:110:41 | password | provenance | | | passwords.go:102:33:102:40 | password | passwords.go:108:34:108:41 | password | provenance | |
| passwords.go:104:33:104:40 | password | passwords.go:115:33:115:40 | password | provenance | | | passwords.go:102:33:102:40 | password | passwords.go:113:33:113:40 | password | provenance | |
| passwords.go:104:33:104:40 | password | passwords.go:125:13:125:20 | password | provenance | | | passwords.go:102:33:102:40 | password | passwords.go:123:13:123:20 | password | provenance | |
| passwords.go:110:34:110:41 | password | passwords.go:110:16:110:41 | ...+... | provenance | Config | | passwords.go:108:34:108:41 | password | passwords.go:108:16:108:41 | ...+... | provenance | Config |
| passwords.go:110:34:110:41 | password | passwords.go:115:33:115:40 | password | provenance | | | passwords.go:108:34:108:41 | password | passwords.go:113:33:113:40 | password | provenance | |
| passwords.go:110:34:110:41 | password | passwords.go:125:13:125:20 | password | provenance | | | passwords.go:108:34:108:41 | password | passwords.go:123:13:123:20 | password | provenance | |
| passwords.go:115:33:115:40 | password | passwords.go:115:15:115:40 | ...+... | provenance | Config | | passwords.go:113:33:113:40 | password | passwords.go:113:15:113:40 | ...+... | provenance | Config |
| passwords.go:115:33:115:40 | password | passwords.go:125:13:125:20 | password | provenance | | | passwords.go:113:33:113:40 | password | passwords.go:123:13:123:20 | password | provenance | |
| passwords.go:118:6:118:14 | definition of password1 | passwords.go:119:28:119:36 | password1 | provenance | | | passwords.go:116:6:116:14 | definition of password1 | passwords.go:117:28:117:36 | password1 | provenance | |
| passwords.go:119:28:119:36 | password1 | passwords.go:119:28:119:45 | call to String | provenance | Config | | passwords.go:117:28:117:36 | password1 | passwords.go:117:28:117:45 | call to String | provenance | Config |
| passwords.go:119:28:119:45 | call to String | passwords.go:119:14:119:45 | ...+... | provenance | Config | | passwords.go:117:28:117:45 | call to String | passwords.go:117:14:117:45 | ...+... | provenance | Config |
| passwords.go:122:12:127:2 | struct literal | passwords.go:129:14:129:19 | config | provenance | | | passwords.go:120:12:125:2 | struct literal | passwords.go:127:14:127:19 | config | provenance | |
| passwords.go:122:12:127:2 | struct literal [x] | passwords.go:130:14:130:19 | config [x] | provenance | | | passwords.go:120:12:125:2 | struct literal [x] | passwords.go:128:14:128:19 | config [x] | provenance | |
| passwords.go:122:12:127:2 | struct literal [y] | passwords.go:131:14:131:19 | config [y] | provenance | | | passwords.go:120:12:125:2 | struct literal [y] | passwords.go:129:14:129:19 | config [y] | provenance | |
| passwords.go:123:13:123:14 | x3 | passwords.go:122:12:127:2 | struct literal | provenance | Config | | passwords.go:121:13:121:14 | x3 | passwords.go:120:12:125:2 | struct literal | provenance | Config |
| passwords.go:125:13:125:20 | password | passwords.go:122:12:127:2 | struct literal | provenance | Config | | passwords.go:123:13:123:20 | password | passwords.go:120:12:125:2 | struct literal | provenance | Config |
| passwords.go:125:13:125:20 | password | passwords.go:122:12:127:2 | struct literal [x] | provenance | | | passwords.go:123:13:123:20 | password | passwords.go:120:12:125:2 | struct literal [x] | provenance | |
| passwords.go:126:13:126:25 | call to getPassword | passwords.go:122:12:127:2 | struct literal | provenance | Config | | passwords.go:124:13:124:25 | call to getPassword | passwords.go:120:12:125:2 | struct literal | provenance | Config |
| passwords.go:126:13:126:25 | call to getPassword | passwords.go:122:12:127:2 | struct literal [y] | provenance | | | passwords.go:124:13:124:25 | call to getPassword | passwords.go:120:12:125:2 | struct literal [y] | provenance | |
| passwords.go:130:14:130:19 | config [x] | passwords.go:130:14:130:21 | selection of x | provenance | | | passwords.go:128:14:128:19 | config [x] | passwords.go:128:14:128:21 | selection of x | provenance | |
| passwords.go:131:14:131:19 | config [y] | passwords.go:131:14:131:21 | selection of y | provenance | | | passwords.go:129:14:129:19 | config [y] | passwords.go:129:14:129:21 | selection of y | provenance | |
| protobuf.go:9:2:9:9 | definition of password | protobuf.go:12:22:12:29 | password | provenance | | | protobuf.go:9:2:9:9 | definition of password | protobuf.go:12:22:12:29 | password | provenance | |
| protobuf.go:12:2:12:6 | implicit dereference [postupdate] [Description] | protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | provenance | | | protobuf.go:12:2:12:6 | implicit dereference [postupdate] [Description] | protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | provenance | |
| protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | protobuf.go:14:14:14:18 | query [pointer, Description] | provenance | | | protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | protobuf.go:14:14:14:18 | query [pointer, Description] | provenance | |
@@ -194,12 +274,20 @@ nodes
| main.go:54:12:54:19 | password | semmle.label | password | | main.go:54:12:54:19 | password | semmle.label | password |
| main.go:54:12:54:19 | password | semmle.label | password | | main.go:54:12:54:19 | password | semmle.label | password |
| main.go:56:11:56:18 | password | semmle.label | password | | main.go:56:11:56:18 | password | semmle.label | password |
| main.go:56:11:56:18 | password | semmle.label | password |
| main.go:59:18:59:25 | password | semmle.label | password |
| main.go:59:18:59:25 | password | semmle.label | password | | main.go:59:18:59:25 | password | semmle.label | password |
| main.go:62:12:62:19 | password | semmle.label | password | | main.go:62:12:62:19 | password | semmle.label | password |
| main.go:62:12:62:19 | password | semmle.label | password |
| main.go:65:13:65:20 | password | semmle.label | password |
| main.go:65:13:65:20 | password | semmle.label | password | | main.go:65:13:65:20 | password | semmle.label | password |
| main.go:68:11:68:18 | password | semmle.label | password | | main.go:68:11:68:18 | password | semmle.label | password |
| main.go:68:11:68:18 | password | semmle.label | password |
| main.go:71:18:71:25 | password | semmle.label | password |
| main.go:71:18:71:25 | password | semmle.label | password | | main.go:71:18:71:25 | password | semmle.label | password |
| main.go:74:12:74:19 | password | semmle.label | password | | main.go:74:12:74:19 | password | semmle.label | password |
| main.go:74:12:74:19 | password | semmle.label | password |
| main.go:77:13:77:20 | password | semmle.label | password |
| main.go:77:13:77:20 | password | semmle.label | password | | main.go:77:13:77:20 | password | semmle.label | password |
| main.go:79:14:79:21 | password | semmle.label | password | | main.go:79:14:79:21 | password | semmle.label | password |
| main.go:80:17:80:24 | password | semmle.label | password | | main.go:80:17:80:24 | password | semmle.label | password |
@@ -220,43 +308,43 @@ nodes
| passwords.go:27:14:27:26 | call to getPassword | semmle.label | call to getPassword | | passwords.go:27:14:27:26 | call to getPassword | semmle.label | call to getPassword |
| passwords.go:28:14:28:28 | call to getPassword | semmle.label | call to getPassword | | passwords.go:28:14:28:28 | call to getPassword | semmle.label | call to getPassword |
| passwords.go:30:8:30:15 | password | semmle.label | password | | passwords.go:30:8:30:15 | password | semmle.label | password |
| passwords.go:33:13:33:20 | password | semmle.label | password | | passwords.go:32:12:32:19 | password | semmle.label | password |
| passwords.go:36:14:36:35 | ...+... | semmle.label | ...+... | | passwords.go:34:14:34:35 | ...+... | semmle.label | ...+... |
| passwords.go:36:28:36:35 | password | semmle.label | password | | passwords.go:34:28:34:35 | password | semmle.label | password |
| passwords.go:38:10:40:2 | struct literal | semmle.label | struct literal | | passwords.go:36:10:38:2 | struct literal | semmle.label | struct literal |
| passwords.go:39:13:39:13 | x | semmle.label | x | | passwords.go:37:13:37:13 | x | semmle.label | x |
| passwords.go:41:14:41:17 | obj1 | semmle.label | obj1 | | passwords.go:39:14:39:17 | obj1 | semmle.label | obj1 |
| passwords.go:43:10:45:2 | struct literal | semmle.label | struct literal | | passwords.go:41:10:43:2 | struct literal | semmle.label | struct literal |
| passwords.go:44:6:44:13 | password | semmle.label | password | | passwords.go:42:6:42:13 | password | semmle.label | password |
| passwords.go:46:14:46:17 | obj2 | semmle.label | obj2 | | passwords.go:44:14:44:17 | obj2 | semmle.label | obj2 |
| passwords.go:50:11:50:18 | password | semmle.label | password | | passwords.go:48:11:48:18 | password | semmle.label | password |
| passwords.go:52:2:52:15 | definition of fixed_password | semmle.label | definition of fixed_password | | passwords.go:50:2:50:15 | definition of fixed_password | semmle.label | definition of fixed_password |
| passwords.go:53:14:53:27 | fixed_password | semmle.label | fixed_password | | passwords.go:51:14:51:27 | fixed_password | semmle.label | fixed_password |
| passwords.go:88:19:90:2 | struct literal | semmle.label | struct literal | | passwords.go:86:19:88:2 | struct literal | semmle.label | struct literal |
| passwords.go:89:16:89:36 | call to make | semmle.label | call to make | | passwords.go:87:16:87:36 | call to make | semmle.label | call to make |
| passwords.go:91:14:91:26 | utilityObject | semmle.label | utilityObject | | passwords.go:89:14:89:26 | utilityObject | semmle.label | utilityObject |
| passwords.go:94:23:94:28 | secret | semmle.label | secret | | passwords.go:92:23:92:28 | secret | semmle.label | secret |
| passwords.go:104:15:104:40 | ...+... | semmle.label | ...+... | | passwords.go:102:15:102:40 | ...+... | semmle.label | ...+... |
| passwords.go:104:33:104:40 | password | semmle.label | password | | passwords.go:102:33:102:40 | password | semmle.label | password |
| passwords.go:110:16:110:41 | ...+... | semmle.label | ...+... | | passwords.go:108:16:108:41 | ...+... | semmle.label | ...+... |
| passwords.go:110:34:110:41 | password | semmle.label | password | | passwords.go:108:34:108:41 | password | semmle.label | password |
| passwords.go:115:15:115:40 | ...+... | semmle.label | ...+... | | passwords.go:113:15:113:40 | ...+... | semmle.label | ...+... |
| passwords.go:115:33:115:40 | password | semmle.label | password | | passwords.go:113:33:113:40 | password | semmle.label | password |
| passwords.go:118:6:118:14 | definition of password1 | semmle.label | definition of password1 | | passwords.go:116:6:116:14 | definition of password1 | semmle.label | definition of password1 |
| passwords.go:119:14:119:45 | ...+... | semmle.label | ...+... | | passwords.go:117:14:117:45 | ...+... | semmle.label | ...+... |
| passwords.go:119:28:119:36 | password1 | semmle.label | password1 | | passwords.go:117:28:117:36 | password1 | semmle.label | password1 |
| passwords.go:119:28:119:45 | call to String | semmle.label | call to String | | passwords.go:117:28:117:45 | call to String | semmle.label | call to String |
| passwords.go:122:12:127:2 | struct literal | semmle.label | struct literal | | passwords.go:120:12:125:2 | struct literal | semmle.label | struct literal |
| passwords.go:122:12:127:2 | struct literal [x] | semmle.label | struct literal [x] | | passwords.go:120:12:125:2 | struct literal [x] | semmle.label | struct literal [x] |
| passwords.go:122:12:127:2 | struct literal [y] | semmle.label | struct literal [y] | | passwords.go:120:12:125:2 | struct literal [y] | semmle.label | struct literal [y] |
| passwords.go:123:13:123:14 | x3 | semmle.label | x3 | | passwords.go:121:13:121:14 | x3 | semmle.label | x3 |
| passwords.go:125:13:125:20 | password | semmle.label | password | | passwords.go:123:13:123:20 | password | semmle.label | password |
| passwords.go:126:13:126:25 | call to getPassword | semmle.label | call to getPassword | | passwords.go:124:13:124:25 | call to getPassword | semmle.label | call to getPassword |
| passwords.go:129:14:129:19 | config | semmle.label | config | | passwords.go:127:14:127:19 | config | semmle.label | config |
| passwords.go:130:14:130:19 | config [x] | semmle.label | config [x] | | passwords.go:128:14:128:19 | config [x] | semmle.label | config [x] |
| passwords.go:130:14:130:21 | selection of x | semmle.label | selection of x | | passwords.go:128:14:128:21 | selection of x | semmle.label | selection of x |
| passwords.go:131:14:131:19 | config [y] | semmle.label | config [y] | | passwords.go:129:14:129:19 | config [y] | semmle.label | config [y] |
| passwords.go:131:14:131:21 | selection of y | semmle.label | selection of y | | passwords.go:129:14:129:21 | selection of y | semmle.label | selection of y |
| protobuf.go:9:2:9:9 | definition of password | semmle.label | definition of password | | protobuf.go:9:2:9:9 | definition of password | semmle.label | definition of password |
| protobuf.go:12:2:12:6 | implicit dereference [postupdate] [Description] | semmle.label | implicit dereference [postupdate] [Description] | | protobuf.go:12:2:12:6 | implicit dereference [postupdate] [Description] | semmle.label | implicit dereference [postupdate] [Description] |
| protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | semmle.label | query [postupdate] [pointer, Description] | | protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | semmle.label | query [postupdate] [pointer, Description] |

View File

@@ -16,7 +16,7 @@ func redact(kind, value string) string {
return value return value
} }
func test(selector int) { func test() {
name := "user" name := "user"
password := "P@ssw0rd" // $ Source password := "P@ssw0rd" // $ Source
x := "horsebatterystapleincorrect" x := "horsebatterystapleincorrect"
@@ -29,9 +29,7 @@ func test(selector int) {
myLog(password) myLog(password)
if selector == 1 {
log.Panic(password) // $ Alert log.Panic(password) // $ Alert
}
log.Println(name + ", " + password) // $ Alert log.Println(name + ", " + password) // $ Alert

View File

@@ -194,7 +194,7 @@ org.apache.hc.core5.http,73,2,45,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,72,,,,,,,,,,,
org.apache.hc.core5.net,,,18,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18, org.apache.hc.core5.net,,,18,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,
org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6 org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6
org.apache.hive.hcatalog.templeton,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,, org.apache.hive.hcatalog.templeton,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,
org.apache.http,53,3,117,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,51,,,,,,,,,,,,,,,,3,108,9 org.apache.http,48,3,95,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,46,,,,,,,,,,,,,,,,3,86,9
org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,57, org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,57,
org.apache.ibatis.mapping,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, org.apache.ibatis.mapping,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,
org.apache.log4j,11,,,,,,,,,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, org.apache.log4j,11,,,,,,,,,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1 package sink source summary sink:bean-validation sink:command-injection sink:credentials-key sink:credentials-password sink:credentials-username sink:encryption-iv sink:encryption-salt sink:environment-injection sink:file-content-store sink:fragment-injection sink:groovy-injection sink:hostname-verification sink:html-injection sink:information-leak sink:intent-redirection sink:jexl-injection sink:jndi-injection sink:js-injection sink:ldap-injection sink:log-injection sink:mvel-injection sink:notification sink:ognl-injection sink:path-injection sink:path-injection[read] sink:pending-intents sink:regex-use sink:regex-use[-1] sink:regex-use[0] sink:regex-use[] sink:regex-use[f-1] sink:regex-use[f1] sink:regex-use[f] sink:request-forgery sink:response-splitting sink:sql-injection sink:template-injection sink:trust-boundary-violation sink:unsafe-deserialization sink:url-forward sink:url-redirection sink:xpath-injection sink:xslt-injection source:android-external-storage-dir source:commandargs source:contentprovider source:database source:environment source:file source:remote summary:taint summary:value
194 org.apache.hc.core5.net 18 18
195 org.apache.hc.core5.util 24 18 6
196 org.apache.hive.hcatalog.templeton 1 1
197 org.apache.http 53 48 3 117 95 2 51 46 3 108 86 9
198 org.apache.ibatis.jdbc 6 57 6 57
199 org.apache.ibatis.mapping 1 1
200 org.apache.log4j 11 11

View File

@@ -13,7 +13,7 @@ Java framework & library support
`Apache Commons IO <https://commons.apache.org/proper/commons-io/>`_,``org.apache.commons.io``,,570,124,105,,,,,15 `Apache Commons IO <https://commons.apache.org/proper/commons-io/>`_,``org.apache.commons.io``,,570,124,105,,,,,15
`Apache Commons Lang <https://commons.apache.org/proper/commons-lang/>`_,``org.apache.commons.lang3``,,425,7,,,,,, `Apache Commons Lang <https://commons.apache.org/proper/commons-lang/>`_,``org.apache.commons.lang3``,,425,7,,,,,,
`Apache Commons Text <https://commons.apache.org/proper/commons-text/>`_,``org.apache.commons.text``,,272,,,,,,, `Apache Commons Text <https://commons.apache.org/proper/commons-text/>`_,``org.apache.commons.text``,,272,,,,,,,
`Apache HttpComponents <https://hc.apache.org/>`_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,205,127,,3,,,,124 `Apache HttpComponents <https://hc.apache.org/>`_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,183,122,,3,,,,119
`Apache Log4j 2 <https://logging.apache.org/log4j/2.0/>`_,``org.apache.logging.log4j``,,8,359,,,,,, `Apache Log4j 2 <https://logging.apache.org/log4j/2.0/>`_,``org.apache.logging.log4j``,,8,359,,,,,,
`Apache Struts <https://struts.apache.org/>`_,"``org.apache.struts2``, ``org.apache.struts.beanvalidation.validation.interceptor``",,3877,14,,,,,, `Apache Struts <https://struts.apache.org/>`_,"``org.apache.struts2``, ``org.apache.struts.beanvalidation.validation.interceptor``",,3877,14,,,,,,
`Apache Velocity <https://velocity.apache.org/>`_,"``org.apache.velocity.app``, ``org.apache.velocity.runtime``",,,8,,,,,, `Apache Velocity <https://velocity.apache.org/>`_,"``org.apache.velocity.app``, ``org.apache.velocity.runtime``",,,8,,,,,,
@@ -41,5 +41,5 @@ Java framework & library support
`Thymeleaf <https://www.thymeleaf.org/>`_,``org.thymeleaf``,,2,2,,,,,, `Thymeleaf <https://www.thymeleaf.org/>`_,``org.thymeleaf``,,2,2,,,,,,
`jOOQ <https://www.jooq.org/>`_,``org.jooq``,,,1,,,1,,, `jOOQ <https://www.jooq.org/>`_,``org.jooq``,,,1,,,1,,,
Others,"``actions.osgi``, ``antlr``, ``ch.ethz.ssh2``, ``cn.hutool.core.codec``, ``com.alibaba.com.caucho.hessian.io``, ``com.alibaba.druid.sql``, ``com.alibaba.fastjson2``, ``com.amazonaws.auth``, ``com.auth0.jwt.algorithms``, ``com.azure.identity``, ``com.caucho.burlap.io``, ``com.caucho.hessian.io``, ``com.cedarsoftware.util.io``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.esotericsoftware.yamlbeans``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.microsoft.sqlserver.jdbc``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2``, ``com.sshtools.j2ssh.authentication``, ``com.sun.crypto.provider``, ``com.sun.jndi.ldap``, ``com.sun.net.httpserver``, ``com.sun.net.ssl``, ``com.sun.rowset``, ``com.sun.security.auth.module``, ``com.sun.security.ntlm``, ``com.sun.security.sasl.digest``, ``com.thoughtworks.xstream``, ``com.trilead.ssh2``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``hudson``, ``io.jsonwebtoken``, ``io.undertow.server.handlers.resource``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``liquibase.database.jvm``, ``liquibase.statement.core``, ``net.lingala.zip4j``, ``net.schmizz.sshj``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.avro``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.exec``, ``org.apache.commons.fileupload``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.lang``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.cxf.catalog``, ``org.apache.cxf.common.classloader``, ``org.apache.cxf.common.jaxb``, ``org.apache.cxf.common.logging``, ``org.apache.cxf.configuration.jsse``, ``org.apache.cxf.helpers``, ``org.apache.cxf.resource``, ``org.apache.cxf.staxutils``, ``org.apache.cxf.tools.corba.utils``, ``org.apache.cxf.tools.util``, ``org.apache.cxf.transform``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hadoop.hive.ql.exec``, ``org.apache.hadoop.hive.ql.metadata``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.ibatis.mapping``, ``org.apache.log4j``, ``org.apache.shiro.authc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.shiro.mgt``, ``org.apache.sshd.client.session``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.codehaus.cargo.container.installer``, ``org.dom4j``, ``org.exolab.castor.xml``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.gradle.api.file``, ``org.ho.yaml``, ``org.influxdb``, ``org.jabsorb``, ``org.jboss.vfs``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.keycloak.models.map.storage``, ``org.kohsuke.stapler``, ``org.lastaflute.web``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.owasp.esapi``, ``org.pac4j.jwt.config.encryption``, ``org.pac4j.jwt.config.signature``, ``org.scijava.log``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``software.amazon.awssdk.transfer.s3.model``, ``sun.jvmstat.perfdata.monitor.protocol.local``, ``sun.jvmstat.perfdata.monitor.protocol.rmi``, ``sun.misc``, ``sun.net.ftp``, ``sun.net.www.protocol.http``, ``sun.security.acl``, ``sun.security.jgss.krb5``, ``sun.security.krb5``, ``sun.security.pkcs``, ``sun.security.pkcs11``, ``sun.security.provider``, ``sun.security.ssl``, ``sun.security.x509``, ``sun.tools.jconsole``",127,6034,775,148,6,14,18,,186 Others,"``actions.osgi``, ``antlr``, ``ch.ethz.ssh2``, ``cn.hutool.core.codec``, ``com.alibaba.com.caucho.hessian.io``, ``com.alibaba.druid.sql``, ``com.alibaba.fastjson2``, ``com.amazonaws.auth``, ``com.auth0.jwt.algorithms``, ``com.azure.identity``, ``com.caucho.burlap.io``, ``com.caucho.hessian.io``, ``com.cedarsoftware.util.io``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.esotericsoftware.yamlbeans``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.microsoft.sqlserver.jdbc``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2``, ``com.sshtools.j2ssh.authentication``, ``com.sun.crypto.provider``, ``com.sun.jndi.ldap``, ``com.sun.net.httpserver``, ``com.sun.net.ssl``, ``com.sun.rowset``, ``com.sun.security.auth.module``, ``com.sun.security.ntlm``, ``com.sun.security.sasl.digest``, ``com.thoughtworks.xstream``, ``com.trilead.ssh2``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``hudson``, ``io.jsonwebtoken``, ``io.undertow.server.handlers.resource``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``liquibase.database.jvm``, ``liquibase.statement.core``, ``net.lingala.zip4j``, ``net.schmizz.sshj``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.avro``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.exec``, ``org.apache.commons.fileupload``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.lang``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.cxf.catalog``, ``org.apache.cxf.common.classloader``, ``org.apache.cxf.common.jaxb``, ``org.apache.cxf.common.logging``, ``org.apache.cxf.configuration.jsse``, ``org.apache.cxf.helpers``, ``org.apache.cxf.resource``, ``org.apache.cxf.staxutils``, ``org.apache.cxf.tools.corba.utils``, ``org.apache.cxf.tools.util``, ``org.apache.cxf.transform``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hadoop.hive.ql.exec``, ``org.apache.hadoop.hive.ql.metadata``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.ibatis.mapping``, ``org.apache.log4j``, ``org.apache.shiro.authc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.shiro.mgt``, ``org.apache.sshd.client.session``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.codehaus.cargo.container.installer``, ``org.dom4j``, ``org.exolab.castor.xml``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.gradle.api.file``, ``org.ho.yaml``, ``org.influxdb``, ``org.jabsorb``, ``org.jboss.vfs``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.keycloak.models.map.storage``, ``org.kohsuke.stapler``, ``org.lastaflute.web``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.owasp.esapi``, ``org.pac4j.jwt.config.encryption``, ``org.pac4j.jwt.config.signature``, ``org.scijava.log``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``software.amazon.awssdk.transfer.s3.model``, ``sun.jvmstat.perfdata.monitor.protocol.local``, ``sun.jvmstat.perfdata.monitor.protocol.rmi``, ``sun.misc``, ``sun.net.ftp``, ``sun.net.www.protocol.http``, ``sun.security.acl``, ``sun.security.jgss.krb5``, ``sun.security.krb5``, ``sun.security.pkcs``, ``sun.security.pkcs11``, ``sun.security.provider``, ``sun.security.ssl``, ``sun.security.x509``, ``sun.tools.jconsole``",127,6034,775,148,6,14,18,,186
Totals,,382,26403,2707,421,16,137,33,1,415 Totals,,382,26381,2702,421,16,137,33,1,410

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Improved modeling of Apache HttpClient `execute` method sinks for `java/ssrf` and `java/non-https-url`.

View File

@@ -11,7 +11,7 @@ extensions:
- ["org.apache.http.client.methods", "HttpPost", False, "HttpPost", "", "", "Argument[0]", "request-forgery", "manual"] - ["org.apache.http.client.methods", "HttpPost", False, "HttpPost", "", "", "Argument[0]", "request-forgery", "manual"]
- ["org.apache.http.client.methods", "HttpPut", False, "HttpPut", "", "", "Argument[0]", "request-forgery", "manual"] - ["org.apache.http.client.methods", "HttpPut", False, "HttpPut", "", "", "Argument[0]", "request-forgery", "manual"]
- ["org.apache.http.client.methods", "HttpRequestBase", True, "setURI", "", "", "Argument[0]", "request-forgery", "manual"] - ["org.apache.http.client.methods", "HttpRequestBase", True, "setURI", "", "", "Argument[0]", "request-forgery", "manual"]
- ["org.apache.http.client.methods", "HttpRequestWrapper", True, "setURI", "(URI)", "", "Argument[0]", "request-forgery", "ai-manual"] - ["org.apache.http.client.methods", "HttpRequestWrapper", True, "setURI", "(URI)", "", "Argument[0]", "request-forgery", "hq-manual"]
- ["org.apache.http.client.methods", "HttpTrace", False, "HttpTrace", "", "", "Argument[0]", "request-forgery", "manual"] - ["org.apache.http.client.methods", "HttpTrace", False, "HttpTrace", "", "", "Argument[0]", "request-forgery", "manual"]
- ["org.apache.http.client.methods", "RequestBuilder", False, "delete", "", "", "Argument[0]", "request-forgery", "manual"] - ["org.apache.http.client.methods", "RequestBuilder", False, "delete", "", "", "Argument[0]", "request-forgery", "manual"]
- ["org.apache.http.client.methods", "RequestBuilder", False, "get", "", "", "Argument[0]", "request-forgery", "manual"] - ["org.apache.http.client.methods", "RequestBuilder", False, "get", "", "", "Argument[0]", "request-forgery", "manual"]
@@ -22,29 +22,3 @@ extensions:
- ["org.apache.http.client.methods", "RequestBuilder", False, "put", "", "", "Argument[0]", "request-forgery", "manual"] - ["org.apache.http.client.methods", "RequestBuilder", False, "put", "", "", "Argument[0]", "request-forgery", "manual"]
- ["org.apache.http.client.methods", "RequestBuilder", False, "setUri", "", "", "Argument[0]", "request-forgery", "manual"] - ["org.apache.http.client.methods", "RequestBuilder", False, "setUri", "", "", "Argument[0]", "request-forgery", "manual"]
- ["org.apache.http.client.methods", "RequestBuilder", False, "trace", "", "", "Argument[0]", "request-forgery", "manual"] - ["org.apache.http.client.methods", "RequestBuilder", False, "trace", "", "", "Argument[0]", "request-forgery", "manual"]
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["org.apache.http.client.methods", "RequestBuilder", True, "build", "()", "", "Argument[this]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "delete", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "delete", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "get", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "get", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "getUri", "()", "", "Argument[this]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "head", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "head", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "options", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "options", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "patch", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "patch", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "post", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "post", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "put", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "put", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "setUri", "(String)", "", "Argument[0]", "Argument[this]", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "setUri", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "setUri", "(URI)", "", "Argument[0]", "Argument[this]", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "setUri", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "trace", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["org.apache.http.client.methods", "RequestBuilder", True, "trace", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]

View File

@@ -3,11 +3,6 @@ extensions:
pack: codeql/java-all pack: codeql/java-all
extensible: sinkModel extensible: sinkModel
data: data:
- ["org.apache.http.client", "HttpClient", True, "execute", "(HttpHost,HttpRequest)", "", "Argument[0]", "request-forgery", "ai-manual"]
- ["org.apache.http.client", "HttpClient", True, "execute", "(HttpHost,HttpRequest,HttpContext)", "", "Argument[0]", "request-forgery", "ai-manual"]
- ["org.apache.http.client", "HttpClient", True, "execute", "(HttpHost,HttpRequest,ResponseHandler)", "", "Argument[0]", "request-forgery", "ai-manual"]
- ["org.apache.http.client", "HttpClient", True, "execute", "(HttpHost,HttpRequest,ResponseHandler,HttpContext)", "", "Argument[0]", "request-forgery", "ai-manual"]
- ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest)", "", "Argument[0]", "request-forgery", "ai-manual"]
- ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest,HttpContext)", "", "Argument[0]", "request-forgery", "ai-manual"] - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest,HttpContext)", "", "Argument[0]", "request-forgery", "ai-manual"]
- ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest,ResponseHandler)", "", "Argument[0]", "request-forgery", "ai-manual"]
- ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest,ResponseHandler,HttpContext)", "", "Argument[0]", "request-forgery", "ai-manual"] - ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest,ResponseHandler,HttpContext)", "", "Argument[0]", "request-forgery", "ai-manual"]
- ["org.apache.http.client", "HttpClient", True, "execute", "(HttpUriRequest)", "", "Argument[0]", "request-forgery", "ai-manual"]

View File

@@ -4,33 +4,67 @@
overlay[local?] overlay[local?]
module; module;
private import java as J private import internal.rangeanalysis.BoundSpecific
private import semmle.code.java.dataflow.SSA
private import semmle.code.java.dataflow.RangeUtils as RU
private import codeql.rangeanalysis.Bound as SharedBound
private module BoundDefs implements SharedBound::BoundDefinitions<J::Location> { private newtype TBound =
class SsaVariable extends Ssa::SsaDefinition { TBoundZero() or
/** Gets a use of this variable. */ TBoundSsa(SsaVariable v) { v.getSourceVariable().getType() instanceof IntegralType } or
Expr getAUse() { result = super.getARead() } TBoundExpr(Expr e) {
interestingExprBound(e) and
not exists(SsaVariable v | e = v.getAUse())
} }
class SsaSourceVariable = Ssa::SourceVariable; /**
* 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 Type = J::Type; /** Gets an expression that equals this bound plus `delta`. */
abstract Expr getExpr(int delta);
class Expr = J::Expr; /** Gets an expression that equals this bound. */
Expr getExpr() { result = this.getExpr(0) }
class IntegralType = J::IntegralType; /** Gets the location of this bound. */
abstract Location getLocation();
class ConstantIntegerExpr = RU::ConstantIntegerExpr;
/** Holds if `e` is a bound expression and it is not an SSA variable read. */
predicate interestingExprBound(Expr e) {
e.(J::FieldRead).getField() instanceof J::ArrayLengthField
}
} }
module BoundImpl = SharedBound::Bound<J::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,27 @@
/**
* Provides Java-specific definitions for bounds.
*/
overlay[local?]
module;
private import java as J
private import semmle.code.java.dataflow.SSA as Ssa
private import semmle.code.java.dataflow.RangeUtils as RU
class SsaVariable extends Ssa::SsaDefinition {
/** Gets a use of this variable. */
Expr getAUse() { result = super.getARead() }
}
class Expr = J::Expr;
class Location = J::Location;
class IntegralType = J::IntegralType;
class ConstantIntegerExpr = RU::ConstantIntegerExpr;
/** Holds if `e` is a bound expression and it is not an SSA variable read. */
predicate interestingExprBound(Expr e) {
e.(J::FieldRead).getField() instanceof J::ArrayLengthField
}

View File

@@ -1,45 +0,0 @@
import java.io.IOException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.protocol.HttpContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ApacheHttpClientExecuteSSRF extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String source = request.getParameter("host"); // $ Source
HttpHost host = new HttpHost(source);
HttpRequest req = new BasicHttpRequest("GET", "/");
HttpUriRequest uriReq = RequestBuilder.get(source).build(); // $ Alert
HttpContext context = null;
HttpClient client = HttpClients.createDefault();
ResponseHandler<Object> handler = null;
client.execute(host, req); // $ Alert
client.execute(host, req, context); // $ Alert
client.execute(host, req, handler); // $ Alert
client.execute(host, req, handler, context); // $ Alert
client.execute(uriReq); // $ Alert
client.execute(uriReq, context); // $ Alert
client.execute(uriReq, handler); // $ Alert
client.execute(uriReq, handler, context); // $ Alert
} catch (Exception e) {
// TODO: handle exception
}
}
}

View File

@@ -1 +1 @@
//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/javax-validation-constraints:${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/apache-http-4.4.13/:${testdir}/../../../stubs/apache-http-client-4.4.13:${testdir}/../../../stubs/projectreactor-3.4.3/:${testdir}/../../../stubs/postgresql-42.3.3/:${testdir}/../../../stubs/HikariCP-3.4.5/:${testdir}/../../../stubs/spring-jdbc-5.3.8/:${testdir}/../../../stubs/jdbi3-core-3.27.2/:${testdir}/../../../stubs/cargo:${testdir}/../../../stubs/javafx-web:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/stapler-1.263:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/apache-http-5:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jaxws-api-2.0:${testdir}/../../../stubs/apache-cxf //semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/javax-validation-constraints:${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/apache-http-4.4.13/:${testdir}/../../../stubs/projectreactor-3.4.3/:${testdir}/../../../stubs/postgresql-42.3.3/:${testdir}/../../../stubs/HikariCP-3.4.5/:${testdir}/../../../stubs/spring-jdbc-5.3.8/:${testdir}/../../../stubs/jdbi3-core-3.27.2/:${testdir}/../../../stubs/cargo:${testdir}/../../../stubs/javafx-web:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/stapler-1.263:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/apache-http-5:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jaxws-api-2.0:${testdir}/../../../stubs/apache-cxf

View File

@@ -1,23 +0,0 @@
// Generated automatically from org.apache.http.client.HttpClient for testing purposes
package org.apache.http.client;
import java.io.IOException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.protocol.HttpContext;
public interface HttpClient {
HttpResponse execute(HttpHost target, HttpRequest request) throws IOException;
HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException;
<T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler) throws IOException;
<T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context)
throws IOException;
HttpResponse execute(HttpUriRequest request) throws IOException;
HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException;
<T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler) throws IOException;
<T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context)
throws IOException;
}

View File

@@ -1,9 +0,0 @@
// Generated automatically from org.apache.http.client.ResponseHandler for testing purposes
package org.apache.http.client;
import org.apache.http.HttpResponse;
public interface ResponseHandler<T> {
T handleResponse(HttpResponse response);
}

View File

@@ -1,7 +0,0 @@
package org.apache.http.impl.client;
import org.apache.http.client.HttpClient;
public abstract class CloseableHttpClient implements HttpClient {
}

View File

@@ -1,10 +0,0 @@
// Generated automatically from org.apache.http.client.HttpClient for testing purposes
package org.apache.http.impl.client;
import java.io.IOException;
import org.apache.http.impl.client.CloseableHttpClient;
public final class HttpClients {
public static CloseableHttpClient createDefault() { return null; }
}

View File

@@ -63,7 +63,6 @@ ql/javascript/ql/src/experimental/Security/CWE-347/decodeJwtWithoutVerificationL
ql/javascript/ql/src/experimental/Security/CWE-444/InsecureHttpParser.ql ql/javascript/ql/src/experimental/Security/CWE-444/InsecureHttpParser.ql
ql/javascript/ql/src/experimental/Security/CWE-522-DecompressionBombs/DecompressionBombs.ql ql/javascript/ql/src/experimental/Security/CWE-522-DecompressionBombs/DecompressionBombs.ql
ql/javascript/ql/src/experimental/Security/CWE-918/SSRF.ql ql/javascript/ql/src/experimental/Security/CWE-918/SSRF.ql
ql/javascript/ql/src/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.ql
ql/javascript/ql/src/experimental/StandardLibrary/MultipleArgumentsToSetConstructor.ql ql/javascript/ql/src/experimental/StandardLibrary/MultipleArgumentsToSetConstructor.ql
ql/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-020/UntrustedDataToExternalAPI.ql ql/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-020/UntrustedDataToExternalAPI.ql
ql/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-078/CommandInjection.ql ql/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-078/CommandInjection.ql

View File

@@ -1,4 +0,0 @@
---
category: newQuery
---
* Added a new experimental query, `javascript/ssrf-ipv6-transition-incomplete-guard`, to detect SSRF host-validation guards that reject private IPv4 ranges but fail to unwrap IPv6-transition forms (IPv4-mapped `::ffff:`, NAT64 `64:ff9b::`, 6to4 `2002::`), allowing the guard to be bypassed by wrapping an internal IPv4 address in a transition literal.

View File

@@ -1,59 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Server-side request forgery (SSRF) guards frequently reject requests to internal
addresses by checking the request host against a denylist of private, loopback and
cloud-metadata IPv4 ranges. When such a guard inspects only the dotted-quad IPv4 form
and never unwraps IPv6-transition representations, it can be bypassed: the host
validator classifies the address as public, but the operating system routes the
connection to the embedded internal IPv4 endpoint.
</p>
<p>
The affected forms include IPv4-mapped IPv6 (<code>::ffff:169.254.169.254</code>),
NAT64 (<code>64:ff9b::a9fe:a9fe</code>) and 6to4 (<code>2002::</code>). A URL such as
<code>http://[::ffff:169.254.169.254]/</code> passes a dotted-quad denylist unchanged
while still reaching the internal address.
</p>
</overview>
<recommendation>
<p>
Normalize the host before validating it: parse the address with a transition-aware
library and unwrap IPv4-mapped, NAT64 and 6to4 forms to their embedded IPv4 address,
then apply the private-range check to the normalized value. Libraries such as
<code>ipaddr.js</code> classify these forms correctly via their range API, and
SSRF-protection libraries such as <code>request-filtering-agent</code> apply the check
after DNS resolution. Validate the resolved address rather than the textual host.
</p>
</recommendation>
<example>
<p>
The following guard rejects private IPv4 ranges using the <code>private-ip</code>
package, which inspects the textual IPv4 form only. An attacker supplies
<code>::ffff:169.254.169.254</code>, which the guard classifies as public, but the
request still reaches the internal metadata endpoint.
</p>
<sample src="examples/SsrfIpv6TransitionIncompleteGuardBad.js"/>
<p>
The following guard parses the host with a transition-aware classifier, so the
embedded internal IPv4 address is detected regardless of the transition form used.
</p>
<sample src="examples/SsrfIpv6TransitionIncompleteGuardGood.js"/>
</example>
<references>
<li>OWASP: <a href="https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">Server-Side Request Forgery</a>.</li>
<li>Common Weakness Enumeration: <a href="https://cwe.mitre.org/data/definitions/918.html">CWE-918</a>.</li>
<li>Common Weakness Enumeration: <a href="https://cwe.mitre.org/data/definitions/1389.html">CWE-1389</a>.</li>
</references>
</qhelp>

View File

@@ -1,129 +0,0 @@
/**
* @name SSRF host guard does not reject IPv6-transition forms
* @description An SSRF host guard that rejects private or loopback IPv4 ranges but never
* unwraps IPv6-transition forms (IPv4-mapped `::ffff:`, NAT64 `64:ff9b::`,
* 6to4 `2002::`) can be bypassed by wrapping an internal IPv4 address in a
* transition literal, allowing requests to reach internal endpoints.
* @kind problem
* @problem.severity warning
* @id javascript/ssrf-ipv6-transition-incomplete-guard
* @tags security
* experimental
* external/cwe/cwe-918
* external/cwe/cwe-1389
*/
import javascript
/**
* Holds if `f` imports a dotted-quad-oriented private-IP guard package whose
* classification is performed on the textual IPv4 form and therefore returns
* `false` for an internal address wrapped in an IPv6-transition literal.
*/
predicate importsHandRolledIpGuard(File f) {
exists(DataFlow::SourceNode mod |
mod.getFile() = f and
mod = DataFlow::moduleImport(["private-ip", "is-ip", "ip", "ip-range-check"])
)
}
/**
* Holds if `f` contains a call to an `isPrivate`-style host classifier, the
* common name for a hand-rolled SSRF guard.
*/
predicate hasIsPrivateCall(File f) {
exists(DataFlow::CallNode c |
c.getFile() = f and
c.getCalleeName().regexpMatch("(?i)^is_?private(ip|address|host)?$")
)
or
exists(DataFlow::MethodCallNode m |
m.getFile() = f and
m.getMethodName().regexpMatch("(?i)^is_?private(ip|address|host)?$")
)
}
/**
* Holds if `f` contains a hand-written RFC 1918, loopback or cloud-metadata IPv4
* literal used as a denylist entry.
*/
predicate hasRfc1918Literal(File f) {
exists(StringLiteral s |
s.getFile() = f and
s.getValue()
.regexpMatch("(?i).*(127\\.0\\.0\\.1|169\\.254\\.169\\.254|10\\.|192\\.168|172\\.1[6-9]|::1|fc00|fd00|metadata\\.google).*")
)
}
/** Holds if `f` carries any hand-rolled, dotted-quad-oriented SSRF guard signal. */
predicate hasUnsafeGuardSignal(File f) {
importsHandRolledIpGuard(f) or
hasIsPrivateCall(f) or
hasRfc1918Literal(f)
}
/** Holds if `func` has a name that reads as an SSRF host or URL validator. */
predicate isSsrfValidatorFunction(Function func) {
func.getName()
.regexpMatch("(?i).*(validate|check|guard|reject|deny|block|allow|is_?safe|sanitiz)e?_?.*(url|host|ip|address|target|endpoint|webhook|origin).*")
or
func.getName()
.regexpMatch("(?i).*(is_?)?(private|internal|loopback|reserved|external)_?(ip|address|host|url).*")
or
func.getName().regexpMatch("(?i).*(ssrf|metadata).*")
}
/**
* Holds if `f` imports a maturity-hardened, transition-aware address classifier
* or SSRF-protection library that does unwrap IPv6-transition forms.
*/
predicate importsSafeClassifier(File f) {
exists(DataFlow::SourceNode mod |
mod.getFile() = f and
mod =
DataFlow::moduleImport([
"ipaddr.js", "ssrf-req-filter", "request-filtering-agent", "ssrf-agent", "netmask",
"ip-cidr", "cidr-matcher", "blocked-at"
])
)
}
/**
* Holds if `f` already performs an explicit IPv6-transition unwrap or
* canonicalization, so the guard does see the embedded IPv4 address.
*/
predicate hasTransitionUnwrap(File f) {
exists(StringLiteral s |
s.getFile() = f and
(
s.getValue().matches("%64:ff9b%") or
s.getValue().matches("%::ffff%") or
s.getValue().matches("%2002:%") or
s.getValue().matches("%2001:%")
)
)
or
exists(Identifier id |
id.getFile() = f and
id.getName()
.regexpMatch("(?i).*(ipv4mapped|v4mapped|mappedipv4|ipv4inipv6|embeddedipv4|unwrap.*ip|toipv4|canonicaliz|isipv4compat).*")
)
or
exists(DataFlow::MethodCallNode m | m.getFile() = f and m.getMethodName() = ["range", "kind"])
}
/** Holds if `f` is treated as safe (transition-aware), suppressing the alert. */
predicate isSafe(File f) { importsSafeClassifier(f) or hasTransitionUnwrap(f) }
from Function guard, File f
where
guard.getFile() = f and
isSsrfValidatorFunction(guard) and
hasUnsafeGuardSignal(f) and
not isSafe(f) and
not f.getRelativePath()
.regexpMatch("(?i).*/(tests?|specs?|examples?|__tests__|e2e|node_modules)/.*")
select guard,
"This SSRF host guard rejects private IPv4 ranges but never unwraps IPv6-transition forms " +
"(IPv4-mapped '::ffff:', NAT64 '64:ff9b::', 6to4 '2002::'); an attacker can wrap an internal " +
"IPv4 address in a transition literal to bypass it and reach internal endpoints."

View File

@@ -1,14 +0,0 @@
const isPrivate = require('private-ip');
const fetch = require('node-fetch');
// BAD: `private-ip` classifies the textual IPv4 form only, so it returns false
// for `::ffff:169.254.169.254`. The guard treats the wrapped internal address as
// public, but the request still reaches the metadata endpoint.
async function validateUrlHost(host) {
if (isPrivate(host)) {
throw new Error('blocked private host');
}
return fetch('http://' + host + '/');
}
module.exports = { validateUrlHost };

View File

@@ -1,16 +0,0 @@
const ipaddr = require('ipaddr.js');
const fetch = require('node-fetch');
// GOOD: ipaddr.js parses the host and classifies it with `.range()`, which is
// transition-aware. `::ffff:169.254.169.254` parses as an IPv4-mapped address and
// is reported in the `linkLocal` range, so the guard is complete.
async function validateTargetHost(host) {
const addr = ipaddr.parse(host);
const range = addr.range();
if (range === 'private' || range === 'loopback' || range === 'linkLocal') {
throw new Error('blocked internal host');
}
return fetch('http://' + host + '/');
}
module.exports = { validateTargetHost };

View File

@@ -1,2 +0,0 @@
| bad-private-ip-pkg.js:6:1:11:1 | async f ... '/');\\n} | This SSRF host guard rejects private IPv4 ranges but never unwraps IPv6-transition forms (IPv4-mapped '::ffff:', NAT64 '64:ff9b::', 6to4 '2002::'); an attacker can wrap an internal IPv4 address in a transition literal to bypass it and reach internal endpoints. |
| bad-rfc1918-regex.js:5:1:16:1 | functio ... '/');\\n} | This SSRF host guard rejects private IPv4 ranges but never unwraps IPv6-transition forms (IPv4-mapped '::ffff:', NAT64 '64:ff9b::', 6to4 '2002::'); an attacker can wrap an internal IPv4 address in a transition literal to bypass it and reach internal endpoints. |

View File

@@ -1 +0,0 @@
experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.ql

View File

@@ -1,13 +0,0 @@
const isPrivate = require('private-ip');
const fetch = require('node-fetch');
// BAD: `private-ip` classifies the textual IPv4 form only. It returns false for
// `::ffff:169.254.169.254`, so a transition-wrapped internal address slips past.
async function validateUrlHost(host) { // NOT OK
if (isPrivate(host)) {
throw new Error('blocked private host');
}
return fetch('http://' + host + '/');
}
module.exports = { validateUrlHost };

View File

@@ -1,18 +0,0 @@
const http = require('http');
// BAD: a hand-written RFC 1918 / loopback / metadata denylist matched against the
// host string. The embedded IPv4 inside `::ffff:10.0.0.1` is never seen.
function checkTargetHost(host) { // NOT OK
if (
host === '127.0.0.1' ||
host === '169.254.169.254' ||
host.startsWith('10.') ||
host.startsWith('192.168') ||
host.startsWith('172.16')
) {
throw new Error('blocked internal host');
}
return http.get('http://' + host + '/');
}
module.exports = { checkTargetHost };

View File

@@ -1,32 +0,0 @@
const http = require('http');
const IPV4_MAPPED_PREFIX = '::ffff:';
// OK: this guard uses a hand-rolled denylist, but it first unwraps the
// IPv6-transition form, so the embedded IPv4 is normalized before the check.
function unwrapMapped(host) {
// strip an IPv4-mapped `::ffff:` prefix down to the embedded dotted quad
if (host.toLowerCase().startsWith(IPV4_MAPPED_PREFIX)) {
return host.slice(IPV4_MAPPED_PREFIX.length);
}
return host;
}
function isPrivateAddress(host) { // OK
const h = unwrapMapped(host);
return (
h === '127.0.0.1' ||
h === '169.254.169.254' ||
h.startsWith('10.') ||
h.startsWith('192.168')
);
}
function validateHost(host) { // OK
if (isPrivateAddress(host)) {
throw new Error('blocked internal host');
}
return http.get('http://' + host + '/');
}
module.exports = { validateHost };

View File

@@ -1,16 +0,0 @@
const ipaddr = require('ipaddr.js');
const fetch = require('node-fetch');
// OK: ipaddr.js parses the address and classifies it with `.range()`, which is
// transition-aware. `::ffff:10.0.0.1` parses as an IPv4-mapped address and is
// reported in the `private` range, so the guard is complete.
async function validateTargetHost(host) { // OK
const addr = ipaddr.parse(host);
const range = addr.range();
if (range === 'private' || range === 'loopback' || range === 'linkLocal') {
throw new Error('blocked internal host');
}
return fetch('http://' + host + '/');
}
module.exports = { validateTargetHost };

View File

@@ -21,19 +21,13 @@ file_coverage_languages:
scc_languages: scc_languages:
- TypeScript - TypeScript
- TypeScript Typings - TypeScript Typings
- name: vue
display_name: Vue.js component
scc_languages:
- Vue
github_api_languages: github_api_languages:
- JavaScript - JavaScript
- TypeScript - TypeScript
- Vue
scc_languages: scc_languages:
- JavaScript - JavaScript
- TypeScript - TypeScript
- TypeScript Typings - TypeScript Typings
- Vue
file_types: file_types:
- name: javascript - name: javascript
display_name: JavaScript display_name: JavaScript

View File

@@ -36,8 +36,6 @@ private module Input implements InputSig<Location, PythonDataFlow> {
// parameter, but dataflow-consistency queries should _not_ complain about there not // parameter, but dataflow-consistency queries should _not_ complain about there not
// being a post-update node for the synthetic `**kwargs` parameter. // being a post-update node for the synthetic `**kwargs` parameter.
n instanceof SynthDictSplatParameterNode n instanceof SynthDictSplatParameterNode
or
Private::Conversions::readStep(n, _, _)
} }
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {

View File

@@ -213,9 +213,11 @@ class ExprWithPointsTo extends Expr {
* Gets what this expression might "refer-to" in the given `context`. * Gets what this expression might "refer-to" in the given `context`.
*/ */
predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) { predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) {
this.getAFlowNode() exists(ControlFlowNode this_, ControlFlowNode origin_ |
.(ControlFlowNodeWithPointsTo) this_.getNode() = this and origin_.getNode() = origin
.refersTo(context, obj, cls, origin.getAFlowNode()) |
this_.(ControlFlowNodeWithPointsTo).refersTo(context, obj, cls, origin_)
)
} }
/** /**
@@ -226,7 +228,11 @@ class ExprWithPointsTo extends Expr {
*/ */
pragma[nomagic] pragma[nomagic]
predicate refersTo(Object obj, AstNode origin) { predicate refersTo(Object obj, AstNode origin) {
this.getAFlowNode().(ControlFlowNodeWithPointsTo).refersTo(obj, origin.getAFlowNode()) exists(ControlFlowNode this_, ControlFlowNode origin_ |
this_.getNode() = this and origin_.getNode() = origin
|
this_.(ControlFlowNodeWithPointsTo).refersTo(obj, origin_)
)
} }
/** /**
@@ -240,16 +246,22 @@ class ExprWithPointsTo extends Expr {
* in the given `context`. * in the given `context`.
*/ */
predicate pointsTo(Context context, Value value, AstNode origin) { predicate pointsTo(Context context, Value value, AstNode origin) {
this.getAFlowNode() exists(ControlFlowNode this_, ControlFlowNode origin_ |
.(ControlFlowNodeWithPointsTo) this_.getNode() = this and origin_.getNode() = origin
.pointsTo(context, value, origin.getAFlowNode()) |
this_.(ControlFlowNodeWithPointsTo).pointsTo(context, value, origin_)
)
} }
/** /**
* Holds if this expression might "point-to" to `value` which is from `origin`. * Holds if this expression might "point-to" to `value` which is from `origin`.
*/ */
predicate pointsTo(Value value, AstNode origin) { predicate pointsTo(Value value, AstNode origin) {
this.getAFlowNode().(ControlFlowNodeWithPointsTo).pointsTo(value, origin.getAFlowNode()) exists(ControlFlowNode this_, ControlFlowNode origin_ |
this_.getNode() = this and origin_.getNode() = origin
|
this_.(ControlFlowNodeWithPointsTo).pointsTo(value, origin_)
)
} }
/** /**
@@ -475,7 +487,10 @@ class FunctionMetricsWithPointsTo extends FunctionMetrics {
not non_coupling_method(result) and not non_coupling_method(result) and
exists(Call call | call.getScope() = this | exists(Call call | call.getScope() = this |
exists(FunctionObject callee | callee.getFunction() = result | exists(FunctionObject callee | callee.getFunction() = result |
call.getAFlowNode().getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee) exists(CallNode call_ |
call_.getNode() = call and
call_.getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee)
)
) )
or or
exists(Attribute a | call.getFunc() = a | exists(Attribute a | call.getFunc() = a |

View File

@@ -64,7 +64,7 @@ private predicate jump_to_defn(ControlFlowNode use, Definition defn) {
private predicate preferred_jump_to_defn(Expr use, Definition def) { private predicate preferred_jump_to_defn(Expr use, Definition def) {
not use instanceof ClassExpr and not use instanceof ClassExpr and
not use instanceof FunctionExpr and not use instanceof FunctionExpr and
jump_to_defn(use.getAFlowNode(), def) exists(ControlFlowNode useNode | useNode.getNode() = use | jump_to_defn(useNode, def))
} }
private predicate unique_jump_to_defn(Expr use, Definition def) { private predicate unique_jump_to_defn(Expr use, Definition def) {
@@ -452,7 +452,7 @@ private predicate self_parameter_jump_to_defn_attribute(
* This exists primarily for testing use `getPreferredDefinition()` instead. * This exists primarily for testing use `getPreferredDefinition()` instead.
*/ */
Definition getADefinition(Expr use) { Definition getADefinition(Expr use) {
jump_to_defn(use.getAFlowNode(), result) and exists(ControlFlowNode useNode | useNode.getNode() = use | jump_to_defn(useNode, result)) and
not use instanceof Call and not use instanceof Call and
not use.isArtificial() and not use.isArtificial() and
// Not the use itself // Not the use itself

View File

@@ -0,0 +1,5 @@
---
category: deprecated
---
* The `AstNode.getAFlowNode()` predicate has been deprecated. Use `ControlFlowNode.getNode()` from the other direction instead: replace `e.getAFlowNode() = n` with `n.getNode() = e`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Python taint tracking is now more precise for values flowing through container contents, such as list, set, tuple, and dictionary elements. This may remove some false positive alerts.

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `Function.getAReturnValueFlowNode()` predicate has been deprecated. Bind a `Return` node explicitly instead — `exists(Return ret | ret.getScope() = f and n.getNode() = ret.getValue())`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Python type tracking now follows values stored in instance attributes such as `self.attr` across instance methods on the same class. As a result, analysis is more likely to recognize user-defined objects that are stored on `self` and used later in other methods, which may produce additional results.

View File

@@ -16,21 +16,26 @@ abstract class AstNode extends AstNode_ {
/** Gets the scope that this node occurs in */ /** Gets the scope that this node occurs in */
abstract Scope getScope(); abstract Scope getScope();
/**
* Gets a flow node corresponding directly to this node.
* NOTE: For some statements and other purely syntactic elements,
* there may not be a `ControlFlowNode`
*/
cached
ControlFlowNode getAFlowNode() {
Stages::AST::ref() and
py_flow_bb_node(result, this, _, _)
}
/** Gets the location for this AST node */ /** Gets the location for this AST node */
cached cached
Location getLocation() { none() } Location getLocation() { none() }
/**
* DEPRECATED: use `ControlFlowNode.getNode()` from the other direction instead;
* that is, replace `e.getAFlowNode() = n` with `n.getNode() = e`. This API is
* being removed to untangle the AST and CFG hierarchies in preparation for
* migrating the dataflow library off the legacy CFG.
*
* Gets a flow node corresponding directly to this node.
* NOTE: For some statements and other purely syntactic elements,
* there may not be a `ControlFlowNode`.
*/
cached
deprecated ControlFlowNode getAFlowNode() {
Stages::AST::ref() and
py_flow_bb_node(result, this, _, _)
}
/** /**
* Whether this syntactic element is artificial, that is it is generated * Whether this syntactic element is artificial, that is it is generated
* by the compiler and is not present in the source * by the compiler and is not present in the source

View File

@@ -28,7 +28,9 @@ class Expr extends Expr_, AstNode {
/** Whether this expression may have a side effect (as determined purely from its syntax) */ /** Whether this expression may have a side effect (as determined purely from its syntax) */
predicate hasSideEffects() { predicate hasSideEffects() {
/* If an exception raised by this expression handled, count that as a side effect */ /* If an exception raised by this expression handled, count that as a side effect */
this.getAFlowNode().getASuccessor().getNode() instanceof ExceptStmt exists(ControlFlowNode n | n.getNode() = this |
n.getASuccessor().getNode() instanceof ExceptStmt
)
or or
this.getASubExpression().hasSideEffects() this.getASubExpression().hasSideEffects()
} }
@@ -68,8 +70,6 @@ class Attribute extends Attribute_ {
/* syntax: Expr.name */ /* syntax: Expr.name */
override Expr getASubExpression() { result = this.getObject() } override Expr getASubExpression() { result = this.getObject() }
override AttrNode getAFlowNode() { result = super.getAFlowNode() }
/** Gets the name of this attribute. That is the `name` in `obj.name` */ /** Gets the name of this attribute. That is the `name` in `obj.name` */
string getName() { result = Attribute_.super.getAttr() } string getName() { result = Attribute_.super.getAttr() }
@@ -96,8 +96,6 @@ class Subscript extends Subscript_ {
} }
Expr getObject() { result = Subscript_.super.getValue() } Expr getObject() { result = Subscript_.super.getValue() }
override SubscriptNode getAFlowNode() { result = super.getAFlowNode() }
} }
/** A call expression, such as `func(...)` */ /** A call expression, such as `func(...)` */
@@ -113,8 +111,6 @@ class Call extends Call_ {
override string toString() { result = this.getFunc().toString() + "()" } override string toString() { result = this.getFunc().toString() + "()" }
override CallNode getAFlowNode() { result = super.getAFlowNode() }
/** Gets a tuple (*) argument of this call. */ /** Gets a tuple (*) argument of this call. */
Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() } Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() }
@@ -200,8 +196,6 @@ class IfExp extends IfExp_ {
override Expr getASubExpression() { override Expr getASubExpression() {
result = this.getTest() or result = this.getBody() or result = this.getOrelse() result = this.getTest() or result = this.getBody() or result = this.getOrelse()
} }
override IfExprNode getAFlowNode() { result = super.getAFlowNode() }
} }
/** A starred expression, such as the `*rest` in the assignment `first, *rest = seq` */ /** A starred expression, such as the `*rest` in the assignment `first, *rest = seq` */
@@ -410,8 +404,6 @@ class PlaceHolder extends PlaceHolder_ {
override Expr getASubExpression() { none() } override Expr getASubExpression() { none() }
override string toString() { result = "$" + this.getId() } override string toString() { result = "$" + this.getId() }
override NameNode getAFlowNode() { result = super.getAFlowNode() }
} }
/** A tuple expression such as `( 1, 3, 5, 7, 9 )` */ /** A tuple expression such as `( 1, 3, 5, 7, 9 )` */
@@ -478,8 +470,6 @@ class Name extends Name_ {
override string toString() { result = this.getId() } override string toString() { result = this.getId() }
override NameNode getAFlowNode() { result = super.getAFlowNode() }
override predicate isArtificial() { override predicate isArtificial() {
/* Artificial variable names in comprehensions all start with "." */ /* Artificial variable names in comprehensions all start with "." */
this.getId().charAt(0) = "." this.getId().charAt(0) = "."
@@ -585,8 +575,6 @@ abstract class NameConstant extends Name, ImmutableLiteral {
override predicate isConstant() { any() } override predicate isConstant() { any() }
override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() }
override predicate isArtificial() { none() } override predicate isArtificial() { none() }
} }

View File

@@ -555,27 +555,27 @@ class DefinitionNode extends ControlFlowNode {
cached cached
DefinitionNode() { DefinitionNode() {
Stages::AST::ref() and Stages::AST::ref() and
exists(Assign a | a.getATarget().getAFlowNode() = this) exists(Assign a | this.getNode() = a.getATarget())
or or
exists(AssignExpr a | a.getTarget().getAFlowNode() = this) exists(AssignExpr a | this.getNode() = a.getTarget())
or or
exists(AnnAssign a | a.getTarget().getAFlowNode() = this and exists(a.getValue())) exists(AnnAssign a | this.getNode() = a.getTarget() and exists(a.getValue()))
or or
exists(Alias a | a.getAsname().getAFlowNode() = this) exists(Alias a | this.getNode() = a.getAsname())
or or
augstore(_, this) augstore(_, this)
or or
// `x, y = 1, 2` where LHS is a combination of list or tuples // `x, y = 1, 2` where LHS is a combination of list or tuples
exists(Assign a | list_or_tuple_nested_element(a.getATarget()).getAFlowNode() = this) exists(Assign a | this.getNode() = list_or_tuple_nested_element(a.getATarget()))
or or
exists(For for | for.getTarget().getAFlowNode() = this) exists(For for | this.getNode() = for.getTarget())
or or
exists(Parameter param | this = param.asName().getAFlowNode() and exists(param.getDefault())) exists(Parameter param | this.getNode() = param.asName() and exists(param.getDefault()))
} }
/** flow node corresponding to the value assigned for the definition corresponding to this flow node */ /** flow node corresponding to the value assigned for the definition corresponding to this flow node */
ControlFlowNode getValue() { ControlFlowNode getValue() {
result = assigned_value(this.getNode()).getAFlowNode() and result.getNode() = assigned_value(this.getNode()) and
( (
result.getBasicBlock().dominates(this.getBasicBlock()) result.getBasicBlock().dominates(this.getBasicBlock())
or or
@@ -584,7 +584,7 @@ class DefinitionNode extends ControlFlowNode {
// since the default value for a parameter is evaluated in the same basic block as // since the default value for a parameter is evaluated in the same basic block as
// the function definition, but the parameter belongs to the basic block of the function, // the function definition, but the parameter belongs to the basic block of the function,
// there is no dominance relationship between the two. // there is no dominance relationship between the two.
exists(Parameter param | this = param.asName().getAFlowNode()) exists(Parameter param | this.getNode() = param.asName())
) )
} }
} }
@@ -901,7 +901,7 @@ class ExceptFlowNode extends ControlFlowNode {
exists(ExceptStmt ex | exists(ExceptStmt ex |
this.getBasicBlock().dominates(result.getBasicBlock()) and this.getBasicBlock().dominates(result.getBasicBlock()) and
ex = this.getNode() and ex = this.getNode() and
result = ex.getType().getAFlowNode() result.getNode() = ex.getType()
) )
} }
@@ -913,7 +913,7 @@ class ExceptFlowNode extends ControlFlowNode {
exists(ExceptStmt ex | exists(ExceptStmt ex |
this.getBasicBlock().dominates(result.getBasicBlock()) and this.getBasicBlock().dominates(result.getBasicBlock()) and
ex = this.getNode() and ex = this.getNode() and
result = ex.getName().getAFlowNode() result.getNode() = ex.getName()
) )
} }
} }
@@ -928,7 +928,7 @@ class ExceptGroupFlowNode extends ControlFlowNode {
*/ */
ControlFlowNode getType() { ControlFlowNode getType() {
this.getBasicBlock().dominates(result.getBasicBlock()) and this.getBasicBlock().dominates(result.getBasicBlock()) and
result = this.getNode().(ExceptGroupStmt).getType().getAFlowNode() result.getNode() = this.getNode().(ExceptGroupStmt).getType()
} }
/** /**
@@ -937,7 +937,7 @@ class ExceptGroupFlowNode extends ControlFlowNode {
*/ */
ControlFlowNode getName() { ControlFlowNode getName() {
this.getBasicBlock().dominates(result.getBasicBlock()) and this.getBasicBlock().dominates(result.getBasicBlock()) and
result = this.getNode().(ExceptGroupStmt).getName().getAFlowNode() result.getNode() = this.getNode().(ExceptGroupStmt).getName()
} }
} }

View File

@@ -153,8 +153,16 @@ class Function extends Function_, Scope, AstNode {
override predicate contains(AstNode inner) { Scope.super.contains(inner) } override predicate contains(AstNode inner) { Scope.super.contains(inner) }
/** Gets a control flow node for a return value of this function */ /**
ControlFlowNode getAReturnValueFlowNode() { * DEPRECATED: bind a `Return` node explicitly instead, e.g.
* `exists(Return ret | ret.getScope() = this and n.getNode() = ret.getValue())`.
* This API is being phased out together with `AstNode.getAFlowNode()` to
* untangle the AST and CFG hierarchies in preparation for migrating the
* dataflow library off the legacy CFG.
*
* Gets a control flow node for a return value of this function.
*/
deprecated ControlFlowNode getAReturnValueFlowNode() {
exists(Return ret | exists(Return ret |
ret.getScope() = this and ret.getScope() = this and
ret.getValue() = result.getNode() ret.getValue() = result.getNode()

View File

@@ -162,8 +162,6 @@ class ImportMember extends ImportMember_ {
string getImportedModuleName() { string getImportedModuleName() {
result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName() result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName()
} }
override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() }
} }
/** An import statement */ /** An import statement */

View File

@@ -46,20 +46,23 @@ class SelfAttributeRead extends SelfAttribute {
} }
predicate guardedByHasattr() { predicate guardedByHasattr() {
exists(Variable var, ControlFlowNode n | exists(Variable var, ControlFlowNode n, ControlFlowNode this_, ControlFlowNode obj_ |
var.getAUse() = this.getObject().getAFlowNode() and this_.getNode() = this and obj_.getNode() = this.getObject()
|
var.getAUse() = obj_ and
hasattr(n, var.getAUse(), this.getName()) and hasattr(n, var.getAUse(), this.getName()) and
n.strictlyDominates(this.getAFlowNode()) n.strictlyDominates(this_)
) )
} }
pragma[noinline] pragma[noinline]
predicate locallyDefined() { predicate locallyDefined() {
exists(SelfAttributeStore store | exists(SelfAttributeStore store, ControlFlowNode store_, ControlFlowNode this_ |
this.getName() = store.getName() and store_.getNode() = store and this_.getNode() = this
this.getScope() = store.getScope()
| |
store.getAFlowNode().strictlyDominates(this.getAFlowNode()) this.getName() = store.getName() and
this.getScope() = store.getScope() and
store_.strictlyDominates(this_)
) )
} }
} }

View File

@@ -5,24 +5,30 @@ private import semmle.python.dataflow.new.DataFlow
private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) {
exists(CompareNode cn | cn = g | exists(CompareNode cn | cn = g |
exists(ImmutableLiteral const, Cmpop op | exists(ImmutableLiteral const, Cmpop op, ControlFlowNode c |
c.getNode() = const and
(
op = any(Eq eq) and branch = true op = any(Eq eq) and branch = true
or or
op = any(NotEq ne) and branch = false op = any(NotEq ne) and branch = false
)
| |
cn.operands(const.getAFlowNode(), op, node) cn.operands(c, op, node)
or or
cn.operands(node, op, const.getAFlowNode()) cn.operands(node, op, c)
) )
or or
exists(NameConstant const, Cmpop op | exists(NameConstant const, Cmpop op, ControlFlowNode c |
c.getNode() = const and
(
op = any(Is is_) and branch = true op = any(Is is_) and branch = true
or or
op = any(IsNot isn) and branch = false op = any(IsNot isn) and branch = false
)
| |
cn.operands(const.getAFlowNode(), op, node) cn.operands(c, op, node)
or or
cn.operands(node, op, const.getAFlowNode()) cn.operands(node, op, c)
) )
or or
exists(IterableNode const_iterable, Cmpop op | exists(IterableNode const_iterable, Cmpop op |

View File

@@ -228,7 +228,7 @@ private class ClassDefinitionAsAttrWrite extends AttrWrite, CfgNode {
override Node getValue() { result.asCfgNode() = node.getValue() } override Node getValue() { result.asCfgNode() = node.getValue() }
override Node getObject() { result.asCfgNode() = cls.getAFlowNode() } override Node getObject() { result.asCfgNode().getNode() = cls }
override ExprNode getAttributeNameExpr() { none() } override ExprNode getAttributeNameExpr() { none() }

View File

@@ -1913,8 +1913,8 @@ abstract class ReturnNode extends Node {
class ExtractedReturnNode extends ReturnNode, CfgNode { class ExtractedReturnNode extends ReturnNode, CfgNode {
// See `TaintTrackingImplementation::returnFlowStep` // See `TaintTrackingImplementation::returnFlowStep`
ExtractedReturnNode() { ExtractedReturnNode() {
node = any(Return ret).getValue().getAFlowNode() or node.getNode() = any(Return ret).getValue() or
node = any(Yield yield).getAFlowNode() node.getNode() = any(Yield yield)
} }
override ReturnKind getKind() { any() } override ReturnKind getKind() { any() }
@@ -1932,7 +1932,7 @@ class ExtractedReturnNode extends ReturnNode, CfgNode {
class YieldNodeInContextManagerFunction extends ReturnNode, CfgNode { class YieldNodeInContextManagerFunction extends ReturnNode, CfgNode {
YieldNodeInContextManagerFunction() { YieldNodeInContextManagerFunction() {
hasContextmanagerDecorator(node.getScope()) and hasContextmanagerDecorator(node.getScope()) and
node = any(Yield yield).getValue().getAFlowNode() node.getNode() = any(Yield yield).getValue()
} }
override ReturnKind getKind() { any() } override ReturnKind getKind() { any() }

View File

@@ -185,8 +185,8 @@ private predicate synthDictSplatArgumentNodeStoreStep(
*/ */
predicate yieldStoreStep(Node nodeFrom, Content c, Node nodeTo) { predicate yieldStoreStep(Node nodeFrom, Content c, Node nodeTo) {
exists(Yield yield | exists(Yield yield |
nodeTo.asCfgNode() = yield.getAFlowNode() and nodeTo.asCfgNode().getNode() = yield and
nodeFrom.asCfgNode() = yield.getValue().getAFlowNode() and nodeFrom.asCfgNode().getNode() = yield.getValue() and
// TODO: Consider if this will also need to transfer dictionary content // TODO: Consider if this will also need to transfer dictionary content
// once dictionary comprehensions are supported. // once dictionary comprehensions are supported.
c instanceof ListElementContent c instanceof ListElementContent
@@ -753,7 +753,7 @@ predicate jumpStepNotSharedWithTypeTracker(Node nodeFrom, Node nodeTo) {
* As of 2024-04-02 the type-tracking library only supports precise content, so there is * As of 2024-04-02 the type-tracking library only supports precise content, so there is
* no reason to include steps for list content right now. * no reason to include steps for list content right now.
*/ */
predicate storeStepCommon(Node nodeFrom, Content c, Node nodeTo) { predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
tupleStoreStep(nodeFrom, c, nodeTo) tupleStoreStep(nodeFrom, c, nodeTo)
or or
dictStoreStep(nodeFrom, c, nodeTo) dictStoreStep(nodeFrom, c, nodeTo)
@@ -767,8 +767,7 @@ predicate storeStepCommon(Node nodeFrom, Content c, Node nodeTo) {
* Holds if data can flow from `nodeFrom` to `nodeTo` via an assignment to * Holds if data can flow from `nodeFrom` to `nodeTo` via an assignment to
* content `c`. * content `c`.
*/ */
predicate storeStep(Node nodeFrom, ContentSet cs, Node nodeTo) { predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) {
exists(Content c | cs = singleton(c) |
storeStepCommon(nodeFrom, c, nodeTo) storeStepCommon(nodeFrom, c, nodeTo)
or or
listStoreStep(nodeFrom, c, nodeTo) listStoreStep(nodeFrom, c, nodeTo)
@@ -781,6 +780,9 @@ predicate storeStep(Node nodeFrom, ContentSet cs, Node nodeTo) {
or or
any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo) any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo)
or or
FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), c,
nodeTo.(FlowSummaryNode).getSummaryNode())
or
synthStarArgsElementParameterNodeStoreStep(nodeFrom, c, nodeTo) synthStarArgsElementParameterNodeStoreStep(nodeFrom, c, nodeTo)
or or
synthDictSplatArgumentNodeStoreStep(nodeFrom, c, nodeTo) synthDictSplatArgumentNodeStoreStep(nodeFrom, c, nodeTo)
@@ -788,10 +790,6 @@ predicate storeStep(Node nodeFrom, ContentSet cs, Node nodeTo) {
yieldStoreStep(nodeFrom, c, nodeTo) yieldStoreStep(nodeFrom, c, nodeTo)
or or
VariableCapture::storeStep(nodeFrom, c, nodeTo) VariableCapture::storeStep(nodeFrom, c, nodeTo)
)
or
FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), cs,
nodeTo.(FlowSummaryNode).getSummaryNode())
} }
/** /**
@@ -987,7 +985,7 @@ predicate attributeStoreStep(Node nodeFrom, AttributeContent c, Node nodeTo) {
/** /**
* Subset of `readStep` that should be shared with type-tracking. * Subset of `readStep` that should be shared with type-tracking.
*/ */
predicate readStepCommon(Node nodeFrom, Content c, Node nodeTo) { predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
subscriptReadStep(nodeFrom, c, nodeTo) subscriptReadStep(nodeFrom, c, nodeTo)
or or
iterableUnpackingReadStep(nodeFrom, c, nodeTo) iterableUnpackingReadStep(nodeFrom, c, nodeTo)
@@ -996,8 +994,7 @@ predicate readStepCommon(Node nodeFrom, Content c, Node nodeTo) {
/** /**
* Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`. * Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`.
*/ */
predicate readStep(Node nodeFrom, ContentSet cs, Node nodeTo) { predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) {
exists(Content c | cs = singleton(c) |
readStepCommon(nodeFrom, c, nodeTo) readStepCommon(nodeFrom, c, nodeTo)
or or
matchReadStep(nodeFrom, c, nodeTo) matchReadStep(nodeFrom, c, nodeTo)
@@ -1006,15 +1003,12 @@ predicate readStep(Node nodeFrom, ContentSet cs, Node nodeTo) {
or or
attributeReadStep(nodeFrom, c, nodeTo) attributeReadStep(nodeFrom, c, nodeTo)
or or
FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), c,
nodeTo.(FlowSummaryNode).getSummaryNode())
or
synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo) synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo)
or or
VariableCapture::readStep(nodeFrom, c, nodeTo) VariableCapture::readStep(nodeFrom, c, nodeTo)
)
or
FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), cs,
nodeTo.(FlowSummaryNode).getSummaryNode())
or
Conversions::readStep(nodeFrom, cs, nodeTo)
} }
/** Data flows from a sequence to a subscript of the sequence. */ /** Data flows from a sequence to a subscript of the sequence. */
@@ -1070,68 +1064,23 @@ predicate attributeReadStep(Node nodeFrom, AttributeContent c, AttrRead nodeTo)
nodeTo.accesses(nodeFrom, c.getAttribute()) nodeTo.accesses(nodeFrom, c.getAttribute())
} }
module Conversions {
private import semmle.python.Concepts
predicate decoderReadStep(Node nodeFrom, ContentSet c, Node nodeTo) {
exists(Decoding decoding |
nodeFrom = decoding.getAnInput() and
nodeTo = decoding.getOutput()
) and
c.isAnyTupleOrDictionaryElement()
}
predicate encoderReadStep(Node nodeFrom, ContentSet c, Node nodeTo) {
exists(Encoding encoding |
nodeFrom = encoding.getAnInput() and
nodeTo = encoding.getOutput()
) and
c.isAnyTupleOrDictionaryElement()
}
predicate formatReadStep(Node nodeFrom, ContentSet c, Node nodeTo) {
// % formatting
exists(BinaryExprNode fmt | fmt = nodeTo.asCfgNode() |
fmt.getOp() instanceof Mod and
fmt.getRight() = nodeFrom.asCfgNode()
) and
c.isAnyTupleElement()
or
// format_map
// see https://docs.python.org/3/library/stdtypes.html#str.format_map
nodeTo.(MethodCallNode).calls(_, "format_map") and
nodeTo.(MethodCallNode).getArg(0) = nodeFrom and
c.isAnyDictionaryElement()
}
predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) {
decoderReadStep(nodeFrom, c, nodeTo)
or
encoderReadStep(nodeFrom, c, nodeTo)
or
formatReadStep(nodeFrom, c, nodeTo)
}
}
/** /**
* Holds if values stored inside content `c` are cleared at node `n`. For example, * Holds if values stored inside content `c` are cleared at node `n`. For example,
* any value stored inside `f` is cleared at the pre-update node associated with `x` * any value stored inside `f` is cleared at the pre-update node associated with `x`
* in `x.f = newValue`. * in `x.f = newValue`.
*/ */
predicate clearsContent(Node n, ContentSet cs) { predicate clearsContent(Node n, ContentSet c) {
exists(Content c | cs = singleton(c) |
matchClearStep(n, c) matchClearStep(n, c)
or or
attributeClearStep(n, c) attributeClearStep(n, c)
or or
dictClearStep(n, c) dictClearStep(n, c)
or or
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
or
dictSplatParameterNodeClearStep(n, c) dictSplatParameterNodeClearStep(n, c)
or or
VariableCapture::clearsContent(n, c) VariableCapture::clearsContent(n, c)
)
or
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), cs)
} }
/** /**
@@ -1249,65 +1198,12 @@ predicate allowParameterReturnInSelf(ParameterNode p) {
) )
} }
bindingset[s]
private string getFirstChar(string s) {
result =
min(int i, string c |
c = s.charAt(i) and c != "_"
or
c = "" and i = s.length()
|
c order by i
)
}
private string getAttributeContentFirstChar(AttributeContent ac) {
result = getFirstChar(ac.getAttribute())
}
private string getDictionaryElementContentKeyFirstChar(DictionaryElementContent dec) {
result = getFirstChar(dec.getKey())
}
private newtype TContentApprox =
TListElementContentApprox() or
TSetElementContentApprox() or
TTupleElementContentApprox() or
TDictionaryElementContentApprox(string first) {
first = "" // for `TDictionaryElementAnyContent`
or
first = getDictionaryElementContentKeyFirstChar(_)
} or
TAttributeContentApprox(string first) { first = getAttributeContentFirstChar(_) } or
TCapturedVariableContentApprox()
/** An approximated `Content`. */ /** An approximated `Content`. */
class ContentApprox extends TContentApprox { class ContentApprox = Unit;
/** Gets a textual representation of this element. */
string toString() { result = "" }
}
/** Gets an approximated value for content `c`. */ /** Gets an approximated value for content `c`. */
ContentApprox getContentApprox(Content c) { pragma[inline]
c = TListElementContent() and ContentApprox getContentApprox(Content c) { any() }
result = TListElementContentApprox()
or
c = TSetElementContent() and
result = TSetElementContentApprox()
or
c = TTupleElementContent(_) and
result = TTupleElementContentApprox()
or
result = TDictionaryElementContentApprox(getDictionaryElementContentKeyFirstChar(c))
or
c = TDictionaryElementAnyContent() and
result = TDictionaryElementContentApprox("")
or
result = TAttributeContentApprox(getAttributeContentFirstChar(c))
or
c = TCapturedVariableContent(_) and
result = TCapturedVariableContentApprox()
}
/** Helper for `.getEnclosingCallable`. */ /** Helper for `.getEnclosingCallable`. */
DataFlowCallable getCallableScope(Scope s) { DataFlowCallable getCallableScope(Scope s) {

View File

@@ -485,7 +485,7 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
/** Gets a node that reads this variable, excluding reads that happen through `from ... import *`. */ /** Gets a node that reads this variable, excluding reads that happen through `from ... import *`. */
Node getALocalRead() { Node getALocalRead() {
result.asCfgNode() = var.getALoad().getAFlowNode() and result.asCfgNode().getNode() = var.getALoad() and
not result.getScope() = mod not result.getScope() = mod
} }
@@ -898,78 +898,19 @@ class CapturedVariableContent extends Content, TCapturedVariableContent {
override string getMaDRepresentation() { none() } override string getMaDRepresentation() { none() }
} }
/**
* An entity that represents a set of `Content`s.
*
* Most `ContentSet`s are singletons (i.e. they consist of a single `Content`),
* but `AnyDictionaryElement` and `AnyTupleElement` act as wildcards on the
* read side: a read at such a `ContentSet` matches any specific dictionary
* key / tuple index store, as well as (for dictionaries) the
* "unknown-bucket" Content `DictionaryElementAnyContent`.
*
* Keeping these as wildcard `ContentSet`s (rather than enumerating one
* `ContentSet` per key/index) keeps the dataflow `readSetEx` relation small
* when implicit reads are used (e.g. at sinks via `defaultImplicitTaintRead`).
*/
private newtype TContentSet =
TSingletonContent(Content c) or
TAnyTupleElement() or
TAnyDictionaryElement() or
TAnyTupleOrDictionaryElement()
/** /**
* An entity that represents a set of `Content`s. * An entity that represents a set of `Content`s.
* *
* The set may be interpreted differently depending on whether it is * The set may be interpreted differently depending on whether it is
* stored into (`getAStoreContent`) or read from (`getAReadContent`). * stored into (`getAStoreContent`) or read from (`getAReadContent`).
*/ */
class ContentSet extends TContentSet { class ContentSet instanceof Content {
/** Holds if this content set is the singleton `{c}`. */
predicate isSingleton(Content c) { this = TSingletonContent(c) }
/** Holds if this content set is the wildcard for all tuple elements. */
predicate isAnyTupleElement() { this = TAnyTupleElement() }
/** Holds if this content set is the wildcard for all dictionary elements. */
predicate isAnyDictionaryElement() { this = TAnyDictionaryElement() }
/** Holds if this content set is the wildcard for all tuple elements or dictionary elements. */
predicate isAnyTupleOrDictionaryElement() { this = TAnyTupleOrDictionaryElement() }
/** Gets a content that may be stored into when storing into this set. */ /** Gets a content that may be stored into when storing into this set. */
Content getAStoreContent() { this = TSingletonContent(result) } Content getAStoreContent() { result = this }
/** Gets a content that may be read from when reading from this set. */ /** Gets a content that may be read from when reading from this set. */
Content getAReadContent() { Content getAReadContent() { result = this }
this = TSingletonContent(result)
or
// Wildcard expansion: a read at "any tuple element" matches a store at any
// specific tuple index. (Stores always target a specific index, so we don't
// need a `TupleElementAnyContent` Content kind here.)
this = TAnyTupleElement() and result instanceof TupleElementContent
or
this = TAnyDictionaryElement() and
(result instanceof DictionaryElementContent or result instanceof DictionaryElementAnyContent)
or
this = TAnyTupleOrDictionaryElement() and
(
result instanceof TupleElementContent or
result instanceof DictionaryElementContent or
result instanceof DictionaryElementAnyContent
)
}
/** Gets a textual representation of this content set. */ /** Gets a textual representation of this content set. */
string toString() { string toString() { result = super.toString() }
exists(Content c | this = TSingletonContent(c) | result = c.toString())
or
this = TAnyTupleElement() and result = "Any tuple element"
or
this = TAnyDictionaryElement() and result = "Any dictionary element"
or
this = TAnyTupleOrDictionaryElement() and result = "Any tuple or dictionary element"
} }
}
/** Gets the singleton `ContentSet` wrapping the `Content` `c`. */
ContentSet singleton(Content c) { result = TSingletonContent(c) }

View File

@@ -66,29 +66,21 @@ module Input implements InputSig<Location, DataFlowImplSpecific::PythonDataFlow>
} }
string encodeContent(ContentSet cs, string arg) { string encodeContent(ContentSet cs, string arg) {
exists(Content c | cs.isSingleton(c) | cs = TListElementContent() and result = "ListElement" and arg = ""
c = TListElementContent() and result = "ListElement" and arg = ""
or or
c = TSetElementContent() and result = "SetElement" and arg = "" cs = TSetElementContent() and result = "SetElement" and arg = ""
or or
exists(int index | exists(int index |
c = TTupleElementContent(index) and result = "TupleElement" and arg = index.toString() cs = TTupleElementContent(index) and result = "TupleElement" and arg = index.toString()
) )
or or
exists(string key | exists(string key |
c = TDictionaryElementContent(key) and result = "DictionaryElement" and arg = key cs = TDictionaryElementContent(key) and result = "DictionaryElement" and arg = key
) )
or or
c = TDictionaryElementAnyContent() and result = "DictionaryElementAny" and arg = "" cs = TDictionaryElementAnyContent() and result = "DictionaryElementAny" and arg = ""
or or
exists(string attr | c = TAttributeContent(attr) and result = "Attribute" and arg = attr) exists(string attr | cs = TAttributeContent(attr) and result = "Attribute" and arg = attr)
)
or
cs.isAnyTupleElement() and result = "AnyTupleElement" and arg = ""
or
cs.isAnyDictionaryElement() and result = "AnyDictionaryElement" and arg = ""
or
cs.isAnyTupleOrDictionaryElement() and result = "AnyTupleOrDictionaryElement" and arg = ""
} }
bindingset[token] bindingset[token]
@@ -147,29 +139,27 @@ module Private {
predicate withContent = SC::withContent/1; predicate withContent = SC::withContent/1;
/** Gets a summary component that represents a list element. */ /** Gets a summary component that represents a list element. */
SummaryComponent listElement() { result = content(singleton(any(ListElementContent c))) } SummaryComponent listElement() { result = content(any(ListElementContent c)) }
/** Gets a summary component that represents a set element. */ /** Gets a summary component that represents a set element. */
SummaryComponent setElement() { result = content(singleton(any(SetElementContent c))) } SummaryComponent setElement() { result = content(any(SetElementContent c)) }
/** Gets a summary component that represents a tuple element. */ /** Gets a summary component that represents a tuple element. */
SummaryComponent tupleElement(int index) { SummaryComponent tupleElement(int index) {
exists(TupleElementContent c | c.getIndex() = index and result = content(singleton(c))) exists(TupleElementContent c | c.getIndex() = index and result = content(c))
} }
/** Gets a summary component that represents a dictionary element. */ /** Gets a summary component that represents a dictionary element. */
SummaryComponent dictionaryElement(string key) { SummaryComponent dictionaryElement(string key) {
exists(DictionaryElementContent c | c.getKey() = key and result = content(singleton(c))) exists(DictionaryElementContent c | c.getKey() = key and result = content(c))
} }
/** Gets a summary component that represents a dictionary element at any key. */ /** Gets a summary component that represents a dictionary element at any key. */
SummaryComponent dictionaryElementAny() { SummaryComponent dictionaryElementAny() { result = content(any(DictionaryElementAnyContent c)) }
result = content(singleton(any(DictionaryElementAnyContent c)))
}
/** Gets a summary component that represents an attribute element. */ /** Gets a summary component that represents an attribute element. */
SummaryComponent attribute(string attr) { SummaryComponent attribute(string attr) {
exists(AttributeContent c | c.getAttribute() = attr and result = content(singleton(c))) exists(AttributeContent c | c.getAttribute() = attr and result = content(c))
} }
/** Gets a summary component that represents the return value of a call. */ /** Gets a summary component that represents the return value of a call. */

View File

@@ -9,7 +9,19 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.internal.ImportStar private import semmle.python.dataflow.new.internal.ImportStar
private import semmle.python.dataflow.new.TypeTracking private import semmle.python.dataflow.new.TypeTracking
private import semmle.python.dataflow.new.internal.DataFlowPrivate private import semmle.python.dataflow.new.internal.DataFlowPrivate
private import semmle.python.essa.SsaDefinitions
/**
* Holds if `init` is a package's `__init__.py` and `var` is a global variable in
* `init` whose name matches a submodule of the package.
*
* Inlined from `SsaSource::init_module_submodule_defn` to avoid pulling
* `semmle.python.essa.SsaDefinitions` into the new dataflow stack.
*/
private predicate initModuleSubmoduleDefn(GlobalVariable var, Module init) {
init.isPackageInit() and
exists(init.getPackage().getSubModule(var.getId())) and
var.getScope() = init
}
/** /**
* Python modules and the way imports are resolved are... complicated. Here's a crash course in how * Python modules and the way imports are resolved are... complicated. Here's a crash course in how
@@ -326,7 +338,7 @@ module ImportResolution {
// imported yet. // imported yet.
exists(string submodule, Module package, EssaVariable var | exists(string submodule, Module package, EssaVariable var |
submodule = var.getName() and submodule = var.getName() and
SsaSource::init_module_submodule_defn(var.getSourceVariable(), package.getEntryNode()) and initModuleSubmoduleDefn(var.getSourceVariable(), package) and
m = getModuleFromName(package.getPackageName() + "." + submodule) and m = getModuleFromName(package.getPackageName() + "." + submodule) and
result.asCfgNode() = var.getDefinition().(EssaNodeDefinition).getDefiningNode() result.asCfgNode() = var.getDefinition().(EssaNodeDefinition).getDefiningNode()
) )

View File

@@ -11,34 +11,12 @@ private import semmle.python.ApiGraphs
*/ */
predicate defaultTaintSanitizer(DataFlow::Node node) { none() } predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/**
* Holds if default taint tracking should read content `contentSet` implicitly and
* propagate taint from a container to reads of that content.
*/
private predicate defaultTaintReadContent(DataFlow::ContentSet contentSet) {
// Tuple and dictionary content is precise, so use wildcard content sets to avoid
// blowing up the size of `Stage1::readSetEx` (otherwise this predicate would
// expand to one row per (node, distinct key or index) and the framework's
// read-set relation grows quadratically). `ContentSet.getAReadContent` expands
// these wildcards back to the specific contents when matching against stores.
contentSet.isAnyTupleOrDictionaryElement()
or
// List and set element content is already imprecise, so no wildcard expansion is
// needed.
contentSet.getAStoreContent() instanceof DataFlow::ListElementContent
or
contentSet.getAStoreContent() instanceof DataFlow::SetElementContent
}
/** /**
* Holds if default `TaintTracking::Configuration`s should allow implicit reads * Holds if default `TaintTracking::Configuration`s should allow implicit reads
* of `c` at sinks and inputs to additional taint steps. * of `c` at sinks and inputs to additional taint steps.
*/ */
bindingset[node] bindingset[node]
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { none() }
exists(node) and
defaultTaintReadContent(c)
}
private module Cached { private module Cached {
/** /**
@@ -150,6 +128,11 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
nodeFrom.getNode() = object and nodeFrom.getNode() = object and
method_name in ["partition", "rpartition", "rsplit", "split", "splitlines"] method_name in ["partition", "rpartition", "rsplit", "split", "splitlines"]
or or
// Iterable[str] -> str
// TODO: check if these should be handled differently in regards to content
method_name = "join" and
nodeFrom.getNode() = call.getArg(0)
or
// Mapping[str, Any] -> str // Mapping[str, Any] -> str
method_name = "format_map" and method_name = "format_map" and
nodeFrom.getNode() = call.getArg(0) nodeFrom.getNode() = call.getArg(0)
@@ -178,21 +161,32 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
} }
/** /**
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to reading * Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to containers
* content from containers (lists/sets/dictionaries/tuples): subscripts, iteration, * (lists/sets/dictionaries): literals, constructor invocation, methods. Note that this
* constructor invocation, methods. * is currently very imprecise, as an example, since we model `dict.get`, we treat any
* `<tainted object>.get(<arg>)` will be tainted, whether it's true or not.
*/ */
predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(DataFlow::ContentSet contentSet | // construction by literal
DataFlowPrivate::readStep(nodeFrom, contentSet, nodeTo) and //
exists(DataFlow::Content c | c = contentSet.getAReadContent() | // TODO: once we have proper flow-summary modeling, we might not need this step any
c instanceof DataFlow::TupleElementContent or // longer -- but there needs to be a matching read-step for the store-step, and we
c instanceof DataFlow::DictionaryElementContent or // don't provide that right now.
c instanceof DataFlow::DictionaryElementAnyContent or DataFlowPrivate::listStoreStep(nodeFrom, _, nodeTo)
c instanceof DataFlow::ListElementContent or or
c instanceof DataFlow::SetElementContent DataFlowPrivate::setStoreStep(nodeFrom, _, nodeTo)
) or
) DataFlowPrivate::tupleStoreStep(nodeFrom, _, nodeTo)
or
DataFlowPrivate::dictStoreStep(nodeFrom, _, nodeTo)
or
// comprehension, so there is taint-flow from `x` in `[x for x in xs]` to the
// resulting list of the list-comprehension.
//
// TODO: once we have proper flow-summary modeling, we might not need this step any
// longer -- but there needs to be a matching read-step for the store-step, and we
// don't provide that right now.
DataFlowPrivate::yieldStoreStep(nodeFrom, _, nodeTo)
} }
/** /**

View File

@@ -94,8 +94,10 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
Node returnOf(Node callable, SummaryComponent return) { Node returnOf(Node callable, SummaryComponent return) {
return = FlowSummaryImpl::Private::SummaryComponent::return() and return = FlowSummaryImpl::Private::SummaryComponent::return() and
// `result` should be the return value of a callable expression (lambda or function) referenced by `callable` // `result` should be the return value of a callable expression (lambda or function) referenced by `callable`
result.asCfgNode() = exists(Return ret |
callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getAReturnValueFlowNode() ret.getScope() = callable.getALocalSource().asExpr().(CallableExpr).getInnerScope() and
result.asCfgNode().getNode() = ret.getValue()
)
} }
// Relating callables to nodes // Relating callables to nodes
@@ -167,15 +169,11 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
} }
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */ /** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */
predicate levelStepCall(Node nodeFrom, LocalSourceNode nodeTo) { predicate levelStepCall(Node nodeFrom, LocalSourceNode nodeTo) { none() }
instanceFieldStep(nodeFrom, nodeTo)
}
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. */ /** Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. */
predicate levelStepNoCall(Node nodeFrom, LocalSourceNode nodeTo) { predicate levelStepNoCall(Node nodeFrom, LocalSourceNode nodeTo) {
TypeTrackerSummaryFlow::levelStepNoCall(nodeFrom, nodeTo) TypeTrackerSummaryFlow::levelStepNoCall(nodeFrom, nodeTo)
or
localFieldStep(nodeFrom, nodeTo)
} }
/** /**
@@ -245,7 +243,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
// is only fed set/list content) // is only fed set/list content)
not nodeFrom instanceof DataFlowPublic::IterableElementNode not nodeFrom instanceof DataFlowPublic::IterableElementNode
or or
TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, DataFlowPublic::singleton(content)) TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, content)
} }
/** /**
@@ -276,15 +274,14 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
nodeFrom.asCfgNode() instanceof SequenceNode nodeFrom.asCfgNode() instanceof SequenceNode
) )
or or
TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, DataFlowPublic::singleton(content)) TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, content)
} }
/** /**
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`. * Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
*/ */
predicate loadStoreStep(Node nodeFrom, Node nodeTo, Content loadContent, Content storeContent) { predicate loadStoreStep(Node nodeFrom, Node nodeTo, Content loadContent, Content storeContent) {
TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent)
DataFlowPublic::singleton(loadContent), DataFlowPublic::singleton(storeContent))
} }
/** /**
@@ -321,87 +318,6 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
) )
} }
/**
* Holds if `ref` accesses attribute `attr` of `self`, where `self` is the first
* parameter of an instance method of `cls` (i.e. an access of the form `self.attr`).
*
* Static methods and class methods are excluded, since their first parameter is not a
* `self` instance reference.
*/
private predicate selfAttrRef(Class cls, string attr, DataFlowPublic::AttrRef ref) {
exists(Function method, Name selfUse |
method = cls.getAMethod() and
not DataFlowDispatch::isStaticmethod(method) and
not DataFlowDispatch::isClassmethod(method) and
selfUse.getVariable() = method.getArg(0).(Name).getVariable() and
ref.getObject().asCfgNode().getNode() = selfUse and
ref.mayHaveAttributeName(attr)
)
}
/**
* Holds if `read` reads attribute `attr` from an instance of `cls`, where the instance
* is referred to from outside the methods of `cls` (i.e. an access of the form
* `instance.attr`, where `instance` is a reference to an instance of `cls`).
*
* This complements `selfAttrRef`, which only handles `self.attr` accesses inside the
* methods of `cls`. Unlike `selfAttrRef`, this depends on the call graph (via
* `classInstanceTracker`), so steps using it must be reported as `levelStepCall`.
*/
private predicate instanceAttrRead(Class cls, string attr, DataFlowPublic::AttrRead read) {
read.getObject() = DataFlowDispatch::classInstanceTracker(cls) and
read.mayHaveAttributeName(attr)
}
/**
* Holds if `nodeFrom` is written to attribute `self.attr` in some instance method of a
* class, and `nodeTo` reads attribute `self.attr` in some (possibly different) instance
* method of the same class.
*
* This models flow through instance attributes (`self.foo`): a value stored into
* `self.foo` in one method can be read from `self.foo` in another method. Type-tracking
* handles the store and read steps via `AttrWrite`/`AttrRead`, but on its own it cannot
* relate the `self` of the writing method to the `self` of the reading method. Following
* the approach used for Ruby and JavaScript, we model this directly as a level step from
* the written value to the read reference, for any pair of methods on the class (not
* just from `__init__`).
*
* This is an over-approximation: it is instance-insensitive (it does not distinguish
* between different instances of the same class) and order-insensitive (it does not
* require the write to happen before the read), matching the precision of
* instance-attribute handling for Ruby and JavaScript.
*/
private predicate localFieldStep(Node nodeFrom, LocalSourceNode nodeTo) {
exists(Class cls, string attr, DataFlowPublic::AttrWrite write, DataFlowPublic::AttrRead read |
selfAttrRef(cls, attr, write) and
nodeFrom = write.getValue() and
selfAttrRef(cls, attr, read) and
nodeTo = read
)
}
/**
* Holds if `nodeFrom` is written to attribute `self.attr` in some instance method of a
* class, and `nodeTo` reads attribute `attr` from an instance of the same class outside
* its methods (e.g. `instance.attr`).
*
* This is the cross-instance counterpart of `localFieldStep`: it relates a write of
* `self.attr` inside the class to a read of `attr` on a reference to an instance of the
* class. Identifying instances relies on the call graph (via `classInstanceTracker`), so
* this step is reported as `levelStepCall` rather than `levelStepNoCall`.
*
* Like `localFieldStep`, this is an over-approximation: it is both instance-insensitive
* and order-insensitive.
*/
private predicate instanceFieldStep(Node nodeFrom, LocalSourceNode nodeTo) {
exists(Class cls, string attr, DataFlowPublic::AttrWrite write, DataFlowPublic::AttrRead read |
selfAttrRef(cls, attr, write) and
nodeFrom = write.getValue() and
instanceAttrRead(cls, attr, read) and
nodeTo = read
)
}
/** /**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */

View File

@@ -61,7 +61,7 @@ private module CaptureInput implements Shared::InputSig<Location, Cfg::BasicBloc
class VariableWrite extends ControlFlowNode { class VariableWrite extends ControlFlowNode {
CapturedVariable v; CapturedVariable v;
VariableWrite() { this = v.getAStore().getAFlowNode().(DefinitionNode).getValue() } VariableWrite() { exists(DefinitionNode d | d.getNode() = v.getAStore() | this = d.getValue()) }
CapturedVariable getVariable() { result = v } CapturedVariable getVariable() { result = v }
@@ -71,7 +71,7 @@ private module CaptureInput implements Shared::InputSig<Location, Cfg::BasicBloc
class VariableRead extends Expr { class VariableRead extends Expr {
CapturedVariable v; CapturedVariable v;
VariableRead() { this = v.getALoad().getAFlowNode() } VariableRead() { this.getNode() = v.getALoad() }
CapturedVariable getVariable() { result = v } CapturedVariable getVariable() { result = v }
} }

View File

@@ -448,8 +448,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
context = TNoParam() and context = TNoParam() and
src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and
node.asCfgNode() = call and node.asCfgNode() = call and
retval.asCfgNode() = retval.asCfgNode().getNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue()
any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
) and ) and
edgeLabel = "return" edgeLabel = "return"
} }
@@ -471,8 +470,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
this.callContexts(call, src, pyfunc, context, callee) and this.callContexts(call, src, pyfunc, context, callee) and
retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and
node.asCfgNode() = call and node.asCfgNode() = call and
retval.asCfgNode() = retval.asCfgNode().getNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue()
any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
) and ) and
edgeLabel = "call" edgeLabel = "call"
} }
@@ -716,8 +714,10 @@ private class EssaTaintTracking extends string instanceof TaintTracking::Configu
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
path.noAttribute() path.noAttribute()
| |
assign.getValue().getAFlowNode() = srcnode.asCfgNode() and srcnode.asCfgNode().getNode() = assign.getValue() and
depth = iterable_unpacking_descent(assign.getATarget().getAFlowNode(), defn.getDefiningNode()) and exists(SequenceNode left_parent | left_parent.getNode() = assign.getATarget() |
depth = iterable_unpacking_descent(left_parent, defn.getDefiningNode())
) and
kind = taint_at_depth(srckind, depth) kind = taint_at_depth(srckind, depth)
) )
} }
@@ -964,7 +964,7 @@ private TaintKind taint_at_depth(SequenceKind parent_kind, int depth) {
* - with `left_defn` = `*y`, `left_parent` = `((x, *y), ...)`, result = 1 * - with `left_defn` = `*y`, `left_parent` = `((x, *y), ...)`, result = 1
*/ */
int iterable_unpacking_descent(SequenceNode left_parent, ControlFlowNode left_defn) { int iterable_unpacking_descent(SequenceNode left_parent, ControlFlowNode left_defn) {
exists(Assign a | a.getATarget().getASubExpression*().getAFlowNode() = left_parent) and exists(Assign a | left_parent.getNode() = a.getATarget().getASubExpression*()) and
left_parent.getAnElement() = left_defn and left_parent.getAnElement() = left_defn and
// Handle `a, *b = some_iterable` // Handle `a, *b = some_iterable`
if left_defn instanceof StarredNode then result = 0 else result = 1 if left_defn instanceof StarredNode then result = 0 else result = 1

View File

@@ -56,7 +56,7 @@ module SsaSource {
predicate with_definition(Variable v, ControlFlowNode defn) { predicate with_definition(Variable v, ControlFlowNode defn) {
exists(With with, Name var | exists(With with, Name var |
with.getOptionalVars() = var and with.getOptionalVars() = var and
var.getAFlowNode() = defn defn.getNode() = var
| |
var = v.getAStore() var = v.getAStore()
) )
@@ -67,7 +67,7 @@ module SsaSource {
predicate pattern_capture_definition(Variable v, ControlFlowNode defn) { predicate pattern_capture_definition(Variable v, ControlFlowNode defn) {
exists(MatchCapturePattern capture, Name var | exists(MatchCapturePattern capture, Name var |
capture.getVariable() = var and capture.getVariable() = var and
var.getAFlowNode() = defn defn.getNode() = var
| |
var = v.getAStore() var = v.getAStore()
) )
@@ -78,7 +78,7 @@ module SsaSource {
predicate pattern_alias_definition(Variable v, ControlFlowNode defn) { predicate pattern_alias_definition(Variable v, ControlFlowNode defn) {
exists(MatchAsPattern pattern, Name var | exists(MatchAsPattern pattern, Name var |
pattern.getAlias() = var and pattern.getAlias() = var and
var.getAFlowNode() = defn defn.getNode() = var
| |
var = v.getAStore() var = v.getAStore()
) )

View File

@@ -59,7 +59,7 @@ module Bottle {
override Parameter getARoutedParameter() { none() } override Parameter getARoutedParameter() { none() }
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node } override Function getARequestHandler() { node.getNode() = result.getADecorator() }
} }
} }
@@ -73,7 +73,10 @@ module Bottle {
/** A response returned by a view callable. */ /** A response returned by a view callable. */
class BottleReturnResponse extends Http::Server::HttpResponse::Range { class BottleReturnResponse extends Http::Server::HttpResponse::Range {
BottleReturnResponse() { BottleReturnResponse() {
this.asCfgNode() = any(View::ViewCallable vc).getAReturnValueFlowNode() exists(Return ret |
ret.getScope() = any(View::ViewCallable vc) and
this.asCfgNode().getNode() = ret.getValue()
)
} }
override DataFlow::Node getBody() { result = this } override DataFlow::Node getBody() { result = this }

View File

@@ -2872,7 +2872,10 @@ module PrivateDjango {
DataFlow::CfgNode DataFlow::CfgNode
{ {
DjangoRedirectViewGetRedirectUrlReturn() { DjangoRedirectViewGetRedirectUrlReturn() {
node = any(GetRedirectUrlFunction f).getAReturnValueFlowNode() exists(Return ret |
ret.getScope() = any(GetRedirectUrlFunction f) and
node.getNode() = ret.getValue()
)
} }
override DataFlow::Node getRedirectLocation() { result = this } override DataFlow::Node getRedirectLocation() { result = this }

View File

@@ -129,7 +129,7 @@ module FastApi {
result in [this.getArg(0), this.getArgByName("path")] result in [this.getArg(0), this.getArgByName("path")]
} }
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node } override Function getARequestHandler() { node.getNode() = result.getADecorator() }
override string getFramework() { result = "FastAPI" } override string getFramework() { result = "FastAPI" }
@@ -309,7 +309,10 @@ module FastApi {
FastApiRouteSetup routeSetup; FastApiRouteSetup routeSetup;
FastApiRequestHandlerReturn() { FastApiRequestHandlerReturn() {
node = routeSetup.getARequestHandler().getAReturnValueFlowNode() exists(Return ret |
ret.getScope() = routeSetup.getARequestHandler() and
node.getNode() = ret.getValue()
)
} }
override DataFlow::Node getBody() { result = this } override DataFlow::Node getBody() { result = this }

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