Compare commits

..

71 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
d73a911d74 Convert Swift .qlref tests to inline expectation tests 2026-06-11 22:48:07 +00:00
copilot-swe-agent[bot]
de8b3360bc Initial plan 2026-06-11 22:22:11 +00:00
Asger F
ad18659373 Merge pull request #21796 from mattcosta7/patch-1
Add UseMemoDirective and UseNoMemoDirective classes
2026-06-11 23:01:29 +02:00
Matthew Costabile
923fe2dcb9 Merge branch 'main' into patch-1 2026-06-11 15:19:58 -04:00
Jeroen Ketema
642259cd51 Merge pull request #21968 from jketema/jketema/namequalifiers
C++: Fix `NameQualifyingElement` db inconsistency
2026-06-11 15:11:51 +02:00
Owen Mansel-Chan
0d984588f9 Merge pull request #21965 from owen-mc/go/convert-to-inline-expectation-tests
Go: convert all qlref tests to inline expectation tests using postprocessing
2026-06-11 13:27:06 +01:00
Owen Mansel-Chan
b4a9689341 Convert .qlref test to inline expectations 2026-06-11 07:15:54 +02:00
Owen Mansel-Chan
6a8e20a0c8 Fix pre-existing whitespace issues in go test files 2026-06-11 07:15:09 +02:00
Owen Mansel-Chan
4c411bbcb5 Convert hand-rolled inline expectations test 2026-06-11 07:13:48 +02:00
Asger F
b60bf8c79f Merge pull request #21950 from tonghuaroot/experimental-ssrf-ipv6-transition-js
Add experimental query: SSRF host guard missing IPv6-transition unwrap (CWE-918/CWE-1389)
2026-06-10 21:42:54 +02:00
Jeroen Ketema
ef00aa2567 C++: Add upgrade and downgrade scripts 2026-06-10 14:38:15 +02:00
Jeroen Ketema
6d0968744b C++: Fix NameQualifyingElement db inconsistency 2026-06-10 14:35:36 +02:00
Jeroen Ketema
98f147556a C++: Add namequalifier test with inconsistency
While where the remove the file restriction in QL.
2026-06-10 14:27:56 +02:00
tonghuaroot (童话)
4c1a0058bf Add SsrfIpv6TransitionIncompleteGuard.ql to not_included_in_qls.expected
Fix the JS integration test failure flagged in review by listing the new
experimental CWE-918 query in the expected not-included-in-qls suite, in
sorted order.
2026-06-10 08:42:42 +08:00
Tom Hvitved
f5919875b7 Merge pull request #21941 from hvitved/python/content-approx
Python: Implement `ContentApprox`
2026-06-09 15:46:04 +02:00
Owen Mansel-Chan
8d456df26f Merge pull request #21960 from github/dependabot/go_modules/go/extractor/extractor-dependencies-28a04969f3
Bump golang.org/x/mod from 0.36.0 to 0.37.0 in /go/extractor in the extractor-dependencies group
2026-06-09 05:30:45 +01:00
dependabot[bot]
72fcf27d1a Bump golang.org/x/mod
Bumps the extractor-dependencies group in /go/extractor with 1 update: [golang.org/x/mod](https://github.com/golang/mod).


Updates `golang.org/x/mod` from 0.36.0 to 0.37.0
- [Commits](https://github.com/golang/mod/compare/v0.36.0...v0.37.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: extractor-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-09 03:03:37 +00:00
yoff
0cea01c22f Merge pull request #21926 from github/yoff/python-simplify-decorator-predicates
Python: simplify decorator-detection predicates to pure AST match
2026-06-08 22:04:33 +02:00
Anders Schack-Mulligen
a473565256 Merge pull request #21954 from aschackmull/cfg/consistency-child-idx
Cfg: Add consistency check for relevant child indices.
2026-06-08 14:44:20 +02:00
Anders Schack-Mulligen
c47135a40b Cfg: Add consistency check for relevant child indices. 2026-06-08 13:40:33 +02:00
Owen Mansel-Chan
3cbc8f0262 Merge pull request #21951 from github/workflow/go-version-update
Go: Update to 1.26.4
2026-06-08 11:47:47 +01:00
Tom Hvitved
cc1ea25856 Python: Implement ContentApprox 2026-06-08 08:41:28 +02:00
github-actions[bot]
5a38cbd5d5 Go: Update to 1.26.4 2026-06-08 04:30:10 +00:00
tonghuaroot
e93bc11f6f Add experimental JS query for SSRF guards missing IPv6-transition unwrap
Add javascript/ssrf-ipv6-transition-incomplete-guard, an experimental
@kind problem query that flags hand-rolled SSRF host guards which reject
private/loopback IPv4 ranges but never unwrap IPv6-transition forms
(IPv4-mapped ::ffff:, NAT64 64:ff9b::, 6to4 2002::). Such guards can be
bypassed by wrapping an internal IPv4 address in a transition literal.

Includes a .qhelp with good/bad examples, a change note, and a test pack
with two true-positive fixtures (private-ip package guard and a
hand-written RFC 1918 denylist) and two negative-control fixtures
(ipaddr.js range classifier and an explicit ::ffff: unwrap).

Signed-off-by: tonghuaroot <23011166+tonghuaroot@users.noreply.github.com>
2026-06-06 21:47:24 +08:00
Owen Mansel-Chan
cf6d94cf8a Merge pull request #21324 from github/copilot/automate-go-version-updates-again
Automate Go version updates via scheduled workflow
2026-06-06 03:03:03 +01:00
Owen Mansel-Chan
292fc8b777 Fix detection of failed text replacement
I checked and the comment seems to be correct.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-06 02:52:21 +01:00
Owen Mansel-Chan
a1759d9834 Use --force-with-lease for slightly improved safety
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-06 02:51:36 +01:00
Owen Mansel-Chan
6b74874372 Minor improvement to PR text 2026-06-06 02:32:43 +01:00
copilot-swe-agent[bot]
ef29d22c75 Update Go version workflow to include patch numbers in messages 2026-06-06 01:03:44 +00:00
Owen Mansel-Chan
1f91f915c7 Merge pull request #21888 from owen-mc/py/remove-imprecise-container-steps
Python: Remove imprecise container steps #2
2026-06-04 22:16:24 +01:00
Jon Janego
ba8eebe2b5 Merge pull request #21948 from github/codeql-spark-run-26974832191
Update changelog documentation site for codeql-cli-2.25.6
2026-06-04 14:55:17 -05:00
github-actions[bot]
dc1409e5f4 update codeql documentation 2026-06-04 19:36:45 +00:00
Owen Mansel-Chan
da999ee440 Address review comments 2026-06-03 21:24:16 +01:00
Owen Mansel-Chan
6f2cc43f32 Remove imprecise model for tuple() 2026-06-02 21:59:48 +01:00
Owen Mansel-Chan
5042fdee84 Remove imprecise model for list() 2026-06-02 21:59:46 +01:00
Owen Mansel-Chan
04341c47bd Tweak model for str.join 2026-06-02 21:59:44 +01:00
Owen Mansel-Chan
b27d08ee32 Update edges in expected test output 2026-06-02 18:29:56 +01:00
Owen Mansel-Chan
20ce679d61 Accept changed edges in test output
No changes to alerts
2026-06-02 16:15:08 +01:00
Owen Mansel-Chan
f62ebef9e0 Adjust expected test output 2026-06-02 16:15:06 +01:00
Owen Mansel-Chan
c3ef1ddd64 Add MaD models for lxml and xml etree.fromstringlist 2026-06-02 16:15:01 +01:00
Owen Mansel-Chan
dede5bc49b Track flow through tuple() with list with tainted elements 2026-06-02 16:14:59 +01:00
Owen Mansel-Chan
ad97b6dd64 Use access path for str.join model 2026-06-02 16:14:56 +01:00
yoff
5fb75ac987 Python: simplify decorator-detection predicates to pure AST match
The internal predicates that identify `@staticmethod`, `@classmethod` and
`@property` decorators previously required the decorator's `NameNode` to
satisfy `isGlobal()` (i.e. no SSA def reaches the decorator's name use).
That filter was correct but unnecessarily indirect: these three names
are builtins, and even when a class body redefines one, the class body
has not started executing at the decorator position, so Python uses the
builtin.

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

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

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-01 14:04:43 +00:00
Owen Mansel-Chan
b38440490a Address review comment 2026-05-31 21:47:44 +01:00
Owen Mansel-Chan
aee33a0cc9 Add missing code for TAnyTupleOrDictionaryElement 2026-05-29 10:26:24 +01:00
Owen Mansel-Chan
df15a719cb Add a ContentSet for any tuple or dictionary element 2026-05-28 16:48:23 +01:00
Owen Mansel-Chan
812e8e6b34 Add change note 2026-05-28 11:37:54 +01:00
Owen Mansel-Chan
80c6f082d1 Fix TODO in containerStep 2026-05-28 11:34:02 +01:00
Owen Mansel-Chan
ec13e1bcd3 Add wildcard ContentSets to avoid performance problems 2026-05-27 15:28:07 +01:00
Matthew Costabile
2884428b62 Merge branch 'main' into patch-1 2026-05-26 07:16:24 -04:00
Owen Mansel-Chan
e8779295ee Update test results 2026-05-22 11:43:18 +01:00
Rasmus Lerchedahl Petersen
fa758d6bf5 python: fix test 2026-05-21 16:59:19 +01:00
Rasmus Lerchedahl Petersen
fa9426c749 Python: extra tests for comprehension 2026-05-21 16:59:18 +01:00
Rasmus Lerchedahl Petersen
0ecca91dea Python: typo 2026-05-21 16:59:16 +01:00
Rasmus Lerchedahl Petersen
f669a4f3bf Python: Make sure all imprecise taint bubbles up 2026-05-21 16:59:14 +01:00
Rasmus Lerchedahl Petersen
3275c814bd Python: reset test expectations 2026-05-21 16:59:11 +01:00
Rasmus Lerchedahl Petersen
9a180036a5 Python: conversion step for format_map
and adjust collection test
2026-05-21 16:59:08 +01:00
Rasmus Lerchedahl Petersen
93e7ab52b7 Python: adjust test expectations
We now find an alert on this line as we hope to
It is not an alert for _full_ SSRF, though, since that configuration cannot handle multiple substitutions.
2026-05-21 16:58:51 +01:00
Rasmus Lerchedahl Petersen
facb3b681d Python: recover taint for % format strings 2026-05-21 16:57:50 +01:00
Rasmus Lerchedahl Petersen
b67694b2ab Python: Remove imprecise container steps
- remove `tupleStoreStep` and `dictStoreStep` from `containerStep`
   These are imprecise compared to the content being precise.
- add implicit reads to recover taint at sinks
- add implicit read steps for decoders
  to supplement the `AdditionalTaintStep`
  that now only covers when the full container is tainted.
2026-05-21 16:57:44 +01:00
Matthew Costabile
e10750b35e Merge branch 'main' into patch-1 2026-05-05 22:09:09 -04:00
Matthew Costabile
18550039f2 Update KnownDirective.expected 2026-05-05 11:06:40 -04:00
Matthew Costabile
0caa483925 change note and test 2026-05-05 13:20:39 +00:00
Matthew Costabile
640b17ec78 Add UseMemoDirective and UseNoMemoDirective classes 2026-05-05 07:41:36 -04:00
Owen Mansel-Chan
a367294c23 Merge branch 'main' into copilot/automate-go-version-updates-again 2026-04-23 14:41:46 +01:00
copilot-swe-agent[bot]
b6004045bd Clean up Go version workflow - remove unnecessary escaping and checks
Co-authored-by: mbg <278086+mbg@users.noreply.github.com>
2026-02-13 11:23:44 +00:00
copilot-swe-agent[bot]
cc7e03b0f5 Add error handling and validation to Go version workflow
Co-authored-by: mbg <278086+mbg@users.noreply.github.com>
2026-02-13 11:22:36 +00:00
copilot-swe-agent[bot]
1cbd423251 Improve portability and fix PR detection in Go version workflow
Co-authored-by: mbg <278086+mbg@users.noreply.github.com>
2026-02-13 11:21:13 +00:00
copilot-swe-agent[bot]
437244fe90 Fix portability issues in Go version update workflow
Co-authored-by: mbg <278086+mbg@users.noreply.github.com>
2026-02-13 11:19:56 +00:00
copilot-swe-agent[bot]
f7cf24d1f9 Add Go version update workflow
Co-authored-by: mbg <278086+mbg@users.noreply.github.com>
2026-02-13 11:17:57 +00:00
copilot-swe-agent[bot]
c3bafacf81 Initial plan 2026-02-13 11:15:15 +00:00
344 changed files with 13370 additions and 2112 deletions

208
.github/workflows/go-version-update.yml vendored Normal file
View File

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

View File

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

View File

@@ -2,7 +2,7 @@
### Minor Analysis Improvements
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like `^[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.
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.
## 0.4.36

View File

@@ -2,4 +2,4 @@
### Minor Analysis Improvements
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like `^[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.
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.

View File

@@ -15,7 +15,7 @@
### Bug Fixes
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check.
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check.
## 0.6.28

View File

@@ -15,4 +15,4 @@
### Bug Fixes
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check.
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -38,7 +38,7 @@ 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 in minor point, added one more listed resource and added one more recommendation for things to check.
* 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -104,7 +104,7 @@ JavaScript/TypeScript
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 less fewer positive results after these changes.
* 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
"""""
@@ -114,7 +114,7 @@ Swift
GitHub Actions
""""""""""""""
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like :code:`^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.
* 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
""""

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,21 +1,21 @@
#select
| EndToEnd.go:58:18:58:47 | call to Get | EndToEnd.go:58:18:58:25 | selection of Params | EndToEnd.go:58:18:58:47 | call to Get | This path depends on a $@. | EndToEnd.go:58:18:58:25 | selection of Params | user-provided value |
| EndToEnd.go:64:26:64:55 | call to Get | EndToEnd.go:64:26:64:33 | selection of Params | EndToEnd.go:64:26:64:55 | call to Get | This path depends on a $@. | EndToEnd.go:64:26:64:33 | selection of Params | user-provided value |
| EndToEnd.go:59:18:59:47 | call to Get | EndToEnd.go:59:18:59:25 | selection of Params | EndToEnd.go:59:18:59:47 | call to Get | This path depends on a $@. | EndToEnd.go:59:18:59:25 | selection of Params | user-provided value |
| EndToEnd.go:65:26:65:55 | call to Get | EndToEnd.go:65:26:65:33 | selection of Params | EndToEnd.go:65:26:65:55 | call to Get | This path depends on a $@. | EndToEnd.go:65:26:65:33 | selection of Params | user-provided value |
edges
| EndToEnd.go:58:18:58:25 | selection of Params | EndToEnd.go:58:18:58:30 | selection of Form | provenance | Src:MaD:3 |
| EndToEnd.go:58:18:58:30 | selection of Form | EndToEnd.go:58:18:58:47 | call to Get | provenance | MaD:4 Sink:MaD:2 |
| EndToEnd.go:64:26:64:33 | selection of Params | EndToEnd.go:64:26:64:38 | selection of Form | provenance | Src:MaD:3 |
| EndToEnd.go:64:26:64:38 | selection of Form | EndToEnd.go:64:26:64:55 | call to Get | provenance | MaD:4 Sink:MaD:1 |
| EndToEnd.go:59:18:59:25 | selection of Params | EndToEnd.go:59:18:59:30 | selection of Form | provenance | Src:MaD:3 |
| EndToEnd.go:59:18:59:30 | selection of Form | EndToEnd.go:59:18:59:47 | call to Get | provenance | MaD:4 Sink:MaD:2 |
| EndToEnd.go:65:26:65:33 | selection of Params | EndToEnd.go:65:26:65:38 | selection of Form | provenance | Src:MaD:3 |
| EndToEnd.go:65:26:65:38 | selection of Form | EndToEnd.go:65:26:65:55 | call to Get | provenance | MaD:4 Sink:MaD:1 |
models
| 1 | Sink: group:revel; Controller; true; RenderFileName; ; ; Argument[0]; path-injection; manual |
| 2 | Sink: os; ; false; Open; ; ; Argument[0]; path-injection; manual |
| 3 | Source: group:revel; Controller; true; Params; ; ; ; remote; manual |
| 4 | Summary: net/url; Values; true; Get; ; ; Argument[receiver]; ReturnValue; taint; manual |
nodes
| EndToEnd.go:58:18:58:25 | selection of Params | semmle.label | selection of Params |
| EndToEnd.go:58:18:58:30 | selection of Form | semmle.label | selection of Form |
| EndToEnd.go:58:18:58:47 | call to Get | semmle.label | call to Get |
| EndToEnd.go:64:26:64:33 | selection of Params | semmle.label | selection of Params |
| EndToEnd.go:64:26:64:38 | selection of Form | semmle.label | selection of Form |
| EndToEnd.go:64:26:64:55 | call to Get | semmle.label | call to Get |
| EndToEnd.go:59:18:59:25 | selection of Params | semmle.label | selection of Params |
| EndToEnd.go:59:18:59:30 | selection of Form | semmle.label | selection of Form |
| EndToEnd.go:59:18:59:47 | call to Get | semmle.label | call to Get |
| EndToEnd.go:65:26:65:33 | selection of Params | semmle.label | selection of Params |
| EndToEnd.go:65:26:65:38 | selection of Form | semmle.label | selection of Form |
| EndToEnd.go:65:26:65:55 | call to Get | semmle.label | call to Get |
subpaths

View File

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

View File

@@ -33,11 +33,11 @@ func init() {
switch event {
case revel.ENGINE_BEFORE_INITIALIZED:
revel.AddHTTPMux("/this/is/a/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hi there, it worked", r.URL.Path) // $ responsebody='selection of Path' responsebody='"Hi there, it worked"'
fmt.Fprintln(w, "Hi there, it worked", r.URL.Path) // $ responsebody='selection of Path' responsebody='"Hi there, it worked"' Alert[go/reflected-xss]
w.WriteHeader(200)
}))
revel.AddHTTPMux("/this/is/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hi there, shorter prefix", r.URL.Path) // $ responsebody='selection of Path' responsebody='"Hi there, shorter prefix"'
fmt.Fprintln(w, "Hi there, shorter prefix", r.URL.Path) // $ responsebody='selection of Path' responsebody='"Hi there, shorter prefix"' Alert[go/reflected-xss]
w.WriteHeader(200)
}))
}

View File

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

View File

@@ -9,7 +9,7 @@ import (
)
func main() {
client := notes.NewNotesServiceProtobufClient("http://localhost:8000", &http.Client{}) // test: ssrfSink
client := notes.NewNotesServiceProtobufClient("http://localhost:8000", &http.Client{}) // $ ssrfSink
ctx := context.Background()

View File

@@ -20,7 +20,7 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Note struct { // test: message
type Note struct { // $ message
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
@@ -83,7 +83,7 @@ func (x *Note) GetCreatedAt() int64 {
return 0
}
type CreateNoteParams struct { // test: message
type CreateNoteParams struct { // $ message
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
@@ -130,7 +130,7 @@ func (x *CreateNoteParams) GetText() string {
return ""
}
type GetAllNotesParams struct { // test: message
type GetAllNotesParams struct { // $ message
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
@@ -168,7 +168,7 @@ func (*GetAllNotesParams) Descriptor() ([]byte, []int) {
return file_rpc_notes_service_proto_rawDescGZIP(), []int{2}
}
type GetAllNotesResult struct { // test: message
type GetAllNotesResult struct { // $ message
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
@@ -340,7 +340,7 @@ func file_rpc_notes_service_proto_init() {
}
}
}
type x struct{}
type x struct{} // $ SPURIOUS: message // not message
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),

View File

@@ -31,7 +31,7 @@ const _ = twirp.TwirpPackageMinVersion_8_1_0
// NotesService Interface
// ======================
type NotesService interface { // test: serviceInterface
type NotesService interface { // $ serviceInterface
CreateNote(context.Context, *CreateNoteParams) (*Note, error)
GetAllNotes(context.Context, *GetAllNotesParams) (*GetAllNotesResult, error)
@@ -41,7 +41,7 @@ type NotesService interface { // test: serviceInterface
// NotesService Protobuf Client
// ============================
type notesServiceProtobufClient struct { // test: serviceClient
type notesServiceProtobufClient struct { // $ serviceClient
client HTTPClient
urls [2]string
interceptor twirp.Interceptor
@@ -50,7 +50,7 @@ type notesServiceProtobufClient struct { // test: serviceClient
// NewNotesServiceProtobufClient creates a Protobuf client that implements the NotesService interface.
// It communicates using Protobuf and can be configured with a custom HTTPClient.
func NewNotesServiceProtobufClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) NotesService { // test: clientConstructor
func NewNotesServiceProtobufClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) NotesService { // $ clientConstructor
if c, ok := client.(*http.Client); ok {
client = withoutRedirects(c)
}
@@ -84,7 +84,7 @@ func NewNotesServiceProtobufClient(baseURL string, client HTTPClient, opts ...tw
}
}
func (c *notesServiceProtobufClient) CreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // test: !handler
func (c *notesServiceProtobufClient) CreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // not handler
ctx = ctxsetters.WithPackageName(ctx, "gotwirprpcexample.rpc.notes")
ctx = ctxsetters.WithServiceName(ctx, "NotesService")
ctx = ctxsetters.WithMethodName(ctx, "CreateNote")
@@ -113,7 +113,7 @@ func (c *notesServiceProtobufClient) CreateNote(ctx context.Context, in *CreateN
return caller(ctx, in)
}
func (c *notesServiceProtobufClient) callCreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // test: !handler
func (c *notesServiceProtobufClient) callCreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // not handler
out := new(Note)
ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out)
if err != nil {
@@ -130,7 +130,7 @@ func (c *notesServiceProtobufClient) callCreateNote(ctx context.Context, in *Cre
return out, nil
}
func (c *notesServiceProtobufClient) GetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // test: !handler
func (c *notesServiceProtobufClient) GetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // not handler
ctx = ctxsetters.WithPackageName(ctx, "gotwirprpcexample.rpc.notes")
ctx = ctxsetters.WithServiceName(ctx, "NotesService")
ctx = ctxsetters.WithMethodName(ctx, "GetAllNotes")
@@ -159,7 +159,7 @@ func (c *notesServiceProtobufClient) GetAllNotes(ctx context.Context, in *GetAll
return caller(ctx, in)
}
func (c *notesServiceProtobufClient) callGetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // test: !handler
func (c *notesServiceProtobufClient) callGetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // not handler
out := new(GetAllNotesResult)
ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[1], in, out)
if err != nil {
@@ -180,7 +180,7 @@ func (c *notesServiceProtobufClient) callGetAllNotes(ctx context.Context, in *Ge
// NotesService JSON Client
// ========================
type notesServiceJSONClient struct { // test: serviceClient
type notesServiceJSONClient struct { // $ serviceClient
client HTTPClient
urls [2]string
interceptor twirp.Interceptor
@@ -189,7 +189,7 @@ type notesServiceJSONClient struct { // test: serviceClient
// NewNotesServiceJSONClient creates a JSON client that implements the NotesService interface.
// It communicates using JSON and can be configured with a custom HTTPClient.
func NewNotesServiceJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) NotesService { // test: clientConstructor
func NewNotesServiceJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) NotesService { // $ clientConstructor
if c, ok := client.(*http.Client); ok {
client = withoutRedirects(c)
}
@@ -223,7 +223,7 @@ func NewNotesServiceJSONClient(baseURL string, client HTTPClient, opts ...twirp.
}
}
func (c *notesServiceJSONClient) CreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // test: !handler
func (c *notesServiceJSONClient) CreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // not handler
ctx = ctxsetters.WithPackageName(ctx, "gotwirprpcexample.rpc.notes")
ctx = ctxsetters.WithServiceName(ctx, "NotesService")
ctx = ctxsetters.WithMethodName(ctx, "CreateNote")
@@ -252,7 +252,7 @@ func (c *notesServiceJSONClient) CreateNote(ctx context.Context, in *CreateNoteP
return caller(ctx, in)
}
func (c *notesServiceJSONClient) callCreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // test: !handler
func (c *notesServiceJSONClient) callCreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // not handler
out := new(Note)
ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out)
if err != nil {
@@ -269,7 +269,7 @@ func (c *notesServiceJSONClient) callCreateNote(ctx context.Context, in *CreateN
return out, nil
}
func (c *notesServiceJSONClient) GetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // test: !handler
func (c *notesServiceJSONClient) GetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // not handler
ctx = ctxsetters.WithPackageName(ctx, "gotwirprpcexample.rpc.notes")
ctx = ctxsetters.WithServiceName(ctx, "NotesService")
ctx = ctxsetters.WithMethodName(ctx, "GetAllNotes")
@@ -298,7 +298,7 @@ func (c *notesServiceJSONClient) GetAllNotes(ctx context.Context, in *GetAllNote
return caller(ctx, in)
}
func (c *notesServiceJSONClient) callGetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // test: !handler
func (c *notesServiceJSONClient) callGetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // not handler
out := new(GetAllNotesResult)
ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[1], in, out)
if err != nil {
@@ -319,7 +319,7 @@ func (c *notesServiceJSONClient) callGetAllNotes(ctx context.Context, in *GetAll
// NotesService Server Handler
// ===========================
type notesServiceServer struct { // test: serviceServer
type notesServiceServer struct { // $ serviceServer
NotesService
interceptor twirp.Interceptor
hooks *twirp.ServerHooks
@@ -331,7 +331,7 @@ type notesServiceServer struct { // test: serviceServer
// NewNotesServiceServer builds a TwirpServer that can be used as an http.Handler to handle
// HTTP requests that are routed to the right method in the provided svc implementation.
// The opts are twirp.ServerOption modifiers, for example twirp.WithServerHooks(hooks).
func NewNotesServiceServer(svc NotesService, opts ...interface{}) TwirpServer { // test: serverConstructor
func NewNotesServiceServer(svc NotesService, opts ...interface{}) TwirpServer { // $ serverConstructor
serverOpts := newServerOpts(opts)
// Using ReadOpt allows backwards and forwards compatibility with new options in the future
@@ -535,7 +535,7 @@ func (s *notesServiceServer) serveCreateNoteProtobuf(ctx context.Context, resp h
return
}
buf, err := io.ReadAll(req.Body)
buf, err := io.ReadAll(req.Body) // $ Source
if err != nil {
s.handleRequestBodyError(ctx, resp, "failed to read request body", err)
return
@@ -812,7 +812,7 @@ func (s *notesServiceServer) PathPrefix() string {
// automatically disabled if *(net/http).Client is passed to client
// constructors. See the withoutRedirects function in this file for more
// details.
type HTTPClient interface {
type HTTPClient interface { // $ SPURIOUS: serviceInterface // not serviceInterface
Do(req *http.Request) (*http.Response, error)
}
@@ -820,7 +820,7 @@ type HTTPClient interface {
// HTTP handlers with additional methods for accessing metadata about the
// service. Those accessors are a low-level API for building reflection tools.
// Most people can think of TwirpServers as just http.Handlers.
type TwirpServer interface {
type TwirpServer interface { // $ SPURIOUS: serviceInterface // not serviceInterface
http.Handler
// ServiceDescriptor returns gzipped bytes describing the .proto file that

View File

@@ -16,7 +16,7 @@ type notesService struct {
CurrentId int32
}
func (s *notesService) CreateNote(ctx context.Context, params *notes.CreateNoteParams) (*notes.Note, error) { // test: routeHandler, request
func (s *notesService) CreateNote(ctx context.Context, params *notes.CreateNoteParams) (*notes.Note, error) { // $ Source request handler // route handler
if len(params.Text) < 4 {
return nil, twirp.InvalidArgument.Error("Text should be min 4 characters.")
}
@@ -27,8 +27,8 @@ func (s *notesService) CreateNote(ctx context.Context, params *notes.CreateNoteP
CreatedAt: time.Now().UnixMilli(),
}
notes.NewNotesServiceProtobufClient(params.Text, &http.Client{}) // test: ssrfSink, ssrf
notes.NewNotesServiceProtobufClient(strconv.FormatInt(int64(s.CurrentId), 10), &http.Client{}) // test: ssrfSink, !ssrf
notes.NewNotesServiceProtobufClient(params.Text, &http.Client{}) // $ Alert ssrfSink ssrf
notes.NewNotesServiceProtobufClient(strconv.FormatInt(int64(s.CurrentId), 10), &http.Client{}) // $ ssrfSink // not ssrf
s.Notes = append(s.Notes, note)
@@ -37,7 +37,7 @@ func (s *notesService) CreateNote(ctx context.Context, params *notes.CreateNoteP
return &note, nil
}
func (s *notesService) GetAllNotes(ctx context.Context, params *notes.GetAllNotesParams) (*notes.GetAllNotesResult, error) { // test: routeHandler, request
func (s *notesService) GetAllNotes(ctx context.Context, params *notes.GetAllNotesParams) (*notes.GetAllNotesResult, error) { // $ request handler // route handler
allNotes := make([]*notes.Note, 0)
fmt.Println(params)
@@ -57,7 +57,7 @@ func main() {
mux := http.NewServeMux()
mux.Handle(notesServer.PathPrefix(), notesServer)
err := http.ListenAndServe(":8000", notesServer) // test: !ssrfSink
err := http.ListenAndServe(":8000", notesServer) // not ssrfSink
if err != nil {
panic(err)
}

View File

@@ -1,32 +1,2 @@
invalidModelRow
passingPositiveTests
| PASSED | clientConstructor | rpc/notes/service.twirp.go:53:114:53:139 | comment |
| PASSED | clientConstructor | rpc/notes/service.twirp.go:192:110:192:135 | comment |
| PASSED | message | rpc/notes/service.pb.go:23:20:23:35 | comment |
| PASSED | message | rpc/notes/service.pb.go:86:32:86:47 | comment |
| PASSED | message | rpc/notes/service.pb.go:133:33:133:48 | comment |
| PASSED | message | rpc/notes/service.pb.go:171:33:171:48 | comment |
| PASSED | request | server/main.go:19:111:19:140 | comment |
| PASSED | request | server/main.go:40:126:40:155 | comment |
| PASSED | serverConstructor | rpc/notes/service.twirp.go:334:81:334:106 | comment |
| PASSED | serviceClient | rpc/notes/service.twirp.go:44:42:44:63 | comment |
| PASSED | serviceClient | rpc/notes/service.twirp.go:183:38:183:59 | comment |
| PASSED | serviceInterface | rpc/notes/service.twirp.go:34:31:34:55 | comment |
| PASSED | serviceServer | rpc/notes/service.twirp.go:322:34:322:55 | comment |
| PASSED | ssrf | server/main.go:30:97:30:119 | comment |
| PASSED | ssrfSink | client/main.go:12:89:12:105 | comment |
| PASSED | ssrfSink | server/main.go:30:97:30:119 | comment |
| PASSED | ssrfSink | server/main.go:31:97:31:120 | comment |
failingPositiveTests
passingNegativeTests
| PASSED | !handler | rpc/notes/service.twirp.go:87:109:87:125 | comment |
| PASSED | !handler | rpc/notes/service.twirp.go:116:113:116:129 | comment |
| PASSED | !handler | rpc/notes/service.twirp.go:133:124:133:140 | comment |
| PASSED | !handler | rpc/notes/service.twirp.go:162:128:162:144 | comment |
| PASSED | !handler | rpc/notes/service.twirp.go:226:105:226:121 | comment |
| PASSED | !handler | rpc/notes/service.twirp.go:255:109:255:125 | comment |
| PASSED | !handler | rpc/notes/service.twirp.go:272:120:272:136 | comment |
| PASSED | !handler | rpc/notes/service.twirp.go:301:124:301:140 | comment |
| PASSED | !ssrf | server/main.go:31:97:31:120 | comment |
| PASSED | !ssrfSink | server/main.go:60:51:60:68 | comment |
failingNegativeTests
testFailures

View File

@@ -2,181 +2,76 @@ import go
import semmle.go.dataflow.ExternalFlow
import ModelValidation
import semmle.go.security.RequestForgery
import utils.test.InlineExpectationsTest
class InlineTest extends LineComment {
string tests;
InlineTest() { tests = this.getText().regexpCapture("\\s*test:(.*)", 1) }
string getPositiveTest() {
result = tests.trim().splitAt(",").trim() and not result.matches("!%")
module TwirpTest implements TestSig {
string getARelevantTag() {
result =
[
"handler", "request", "ssrfSink", "message", "serviceInterface", "serviceClient",
"serviceServer", "clientConstructor", "serverConstructor", "ssrf"
]
}
string getNegativeTest() { result = tests.trim().splitAt(",").trim() and result.matches("!%") }
predicate hasPositiveTest(string test) { test = this.getPositiveTest() }
predicate hasNegativeTest(string test) { test = this.getNegativeTest() }
predicate inNode(DataFlow::Node n) {
this.getLocation().getFile() = n.getFile() and
this.getLocation().getStartLine() = n.getStartLine()
additional predicate hasEntityResult(Location location, string element, Entity entity) {
location = entity.getDeclaration().getLocation() and
element = entity.toString()
}
predicate inEntity(Entity e) {
this.getLocation().getFile() = e.getDeclaration().getFile() and
this.getLocation().getStartLine() = e.getDeclaration().getLocation().getStartLine()
additional predicate hasTypeResult(Location location, string element, Type goType) {
exists(TypeEntity typeEntity |
typeEntity.getType() = goType and
location = typeEntity.getDeclaration().getLocation() and
element = goType.toString()
)
}
predicate inType(Type t) {
exists(TypeEntity te |
te.getType() = t and
this.getLocation().getFile() = te.getDeclaration().getFile() and
this.getLocation().getStartLine() = te.getDeclaration().getLocation().getStartLine()
predicate hasActualResult(Location location, string element, string tag, string value) {
value = "" and
(
tag = "handler" and
exists(Twirp::ServiceHandler handler | hasEntityResult(location, element, handler))
or
tag = "request" and
exists(Twirp::Request request |
location = request.getLocation() and
element = request.toString()
)
or
tag = "ssrfSink" and
exists(RequestForgery::Sink sink |
location = sink.getLocation() and
element = sink.toString()
)
or
tag = "message" and
exists(Twirp::ProtobufMessageType message | hasTypeResult(location, element, message))
or
tag = "serviceInterface" and
exists(Twirp::ServiceInterfaceType serviceInterface |
hasTypeResult(location, element, serviceInterface.getDefinedType())
)
or
tag = "serviceClient" and
exists(Twirp::ServiceClientType client | hasTypeResult(location, element, client))
or
tag = "serviceServer" and
exists(Twirp::ServiceServerType server | hasTypeResult(location, element, server))
or
tag = "clientConstructor" and
exists(Twirp::ClientConstructor constructor | hasEntityResult(location, element, constructor))
or
tag = "serverConstructor" and
exists(Twirp::ServerConstructor constructor | hasEntityResult(location, element, constructor))
or
tag = "ssrf" and
exists(DataFlow::Node sink |
RequestForgery::Flow::flowTo(sink) and
location = sink.getLocation() and
element = sink.toString()
)
)
}
}
query predicate passingPositiveTests(string res, string expectation, InlineTest t) {
res = "PASSED" and
t.hasPositiveTest(expectation) and
(
expectation = "handler" and
exists(Twirp::ServiceHandler n | t.inEntity(n))
or
expectation = "request" and
exists(Twirp::Request n | t.inNode(n))
or
expectation = "ssrfSink" and
exists(RequestForgery::Sink n | t.inNode(n))
or
expectation = "message" and
exists(Twirp::ProtobufMessageType n | t.inType(n))
or
expectation = "serviceInterface" and
exists(Twirp::ServiceInterfaceType n | t.inType(n.getDefinedType()))
or
expectation = "serviceClient" and
exists(Twirp::ServiceClientType n | t.inType(n))
or
expectation = "serviceServer" and
exists(Twirp::ServiceServerType n | t.inType(n))
or
expectation = "clientConstructor" and
exists(Twirp::ClientConstructor n | t.inEntity(n))
or
expectation = "serverConstructor" and
exists(Twirp::ServerConstructor n | t.inEntity(n))
or
expectation = "ssrf" and
exists(DataFlow::Node sink | RequestForgery::Flow::flowTo(sink) and t.inNode(sink))
)
}
query predicate failingPositiveTests(string res, string expectation, InlineTest t) {
res = "FAILED" and
t.hasPositiveTest(expectation) and
(
expectation = "handler" and
not exists(Twirp::ServiceHandler n | t.inEntity(n))
or
expectation = "request" and
not exists(Twirp::Request n | t.inNode(n))
or
expectation = "ssrfSink" and
not exists(RequestForgery::Sink n | t.inNode(n))
or
expectation = "message" and
not exists(Twirp::ProtobufMessageType n | t.inType(n))
or
expectation = "serviceInterface" and
not exists(Twirp::ServiceInterfaceType n | t.inType(n.getDefinedType()))
or
expectation = "serviceClient" and
not exists(Twirp::ServiceClientType n | t.inType(n))
or
expectation = "serviceServer" and
not exists(Twirp::ServiceServerType n | t.inType(n))
or
expectation = "clientConstructor" and
not exists(Twirp::ClientConstructor n | t.inEntity(n))
or
expectation = "serverConstructor" and
not exists(Twirp::ServerConstructor n | t.inEntity(n))
or
expectation = "ssrf" and
not exists(DataFlow::Node sink | RequestForgery::Flow::flowTo(sink) and t.inNode(sink))
)
}
query predicate passingNegativeTests(string res, string expectation, InlineTest t) {
res = "PASSED" and
t.hasNegativeTest(expectation) and
(
expectation = "!handler" and
not exists(Twirp::ServiceHandler n | t.inEntity(n))
or
expectation = "!request" and
not exists(Twirp::Request n | t.inNode(n))
or
expectation = "!ssrfSink" and
not exists(RequestForgery::Sink n | t.inNode(n))
or
expectation = "!message" and
not exists(Twirp::ProtobufMessageType n | t.inType(n))
or
expectation = "!serviceInterface" and
not exists(Twirp::ServiceInterfaceType n | t.inType(n))
or
expectation = "!serviceClient" and
not exists(Twirp::ServiceClientType n | t.inType(n))
or
expectation = "!serviceServer" and
not exists(Twirp::ServiceServerType n | t.inType(n))
or
expectation = "!clientConstructor" and
not exists(Twirp::ClientConstructor n | t.inEntity(n))
or
expectation = "!serverConstructor" and
not exists(Twirp::ServerConstructor n | t.inEntity(n))
or
expectation = "!ssrf" and
not exists(DataFlow::Node sink | RequestForgery::Flow::flowTo(sink) and t.inNode(sink))
)
}
query predicate failingNegativeTests(string res, string expectation, InlineTest t) {
res = "FAILED" and
t.hasNegativeTest(expectation) and
(
expectation = "!handler" and
exists(Twirp::ServiceHandler n | t.inEntity(n))
or
expectation = "!request" and
exists(Twirp::Request n | t.inNode(n))
or
expectation = "!ssrfSink" and
exists(RequestForgery::Sink n | t.inNode(n))
or
expectation = "!message" and
exists(Twirp::ProtobufMessageType n | t.inType(n))
or
expectation = "!serviceInterface" and
exists(Twirp::ServiceInterfaceType n | t.inType(n))
or
expectation = "!serviceClient" and
exists(Twirp::ServiceClientType n | t.inType(n))
or
expectation = "!serviceServer" and
exists(Twirp::ServiceServerType n | t.inType(n))
or
expectation = "!clientConstructor" and
exists(Twirp::ClientConstructor n | t.inEntity(n))
or
expectation = "!serverConstructor" and
exists(Twirp::ServerConstructor n | t.inEntity(n))
or
expectation = "!ssrf" and
exists(DataFlow::Node sink | RequestForgery::Flow::flowTo(sink) and t.inNode(sink))
)
}
import MakeTest<TwirpTest>

View File

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

View File

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

View File

@@ -9,50 +9,50 @@ import (
func test(request *http.Request, writer http.ResponseWriter) {
param1 := request.URL.Query().Get("param1")
param1 := request.URL.Query().Get("param1") // $ Source[go/reflected-xss]
writer.Write([]byte(html.EscapeString(param1))) // GOOD: escaped.
writer.Write([]byte(html.UnescapeString(param1))) // BAD: unescaped.
writer.Write([]byte(html.UnescapeString(param1))) // $ Alert[go/reflected-xss] // BAD: unescaped.
node, _ := html.Parse(request.Body)
writer.Write([]byte(node.Data)) // BAD: writing unescaped HTML data
node, _ := html.Parse(request.Body) // $ Source[go/reflected-xss]
writer.Write([]byte(node.Data)) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
node2, _ := html.ParseWithOptions(request.Body)
writer.Write([]byte(node2.Data)) // BAD: writing unescaped HTML data
node2, _ := html.ParseWithOptions(request.Body) // $ Source[go/reflected-xss]
writer.Write([]byte(node2.Data)) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
nodes, _ := html.ParseFragment(request.Body, nil)
writer.Write([]byte(nodes[0].Data)) // BAD: writing unescaped HTML data
nodes, _ := html.ParseFragment(request.Body, nil) // $ Source[go/reflected-xss]
writer.Write([]byte(nodes[0].Data)) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
nodes2, _ := html.ParseFragmentWithOptions(request.Body, nil)
writer.Write([]byte(nodes2[0].Data)) // BAD: writing unescaped HTML data
nodes2, _ := html.ParseFragmentWithOptions(request.Body, nil) // $ Source[go/reflected-xss]
writer.Write([]byte(nodes2[0].Data)) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
html.Render(writer, node) // BAD: rendering untrusted HTML to `writer`
html.Render(writer, node) // $ Alert[go/reflected-xss] // BAD: rendering untrusted HTML to `writer`
tokenizer := html.NewTokenizer(request.Body)
writer.Write(tokenizer.Buffered()) // BAD: writing unescaped HTML data
writer.Write(tokenizer.Raw()) // BAD: writing unescaped HTML data
tokenizer := html.NewTokenizer(request.Body) // $ Source[go/reflected-xss]
writer.Write(tokenizer.Buffered()) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
writer.Write(tokenizer.Raw()) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
_, value, _ := tokenizer.TagAttr()
writer.Write(value) // BAD: writing unescaped HTML data
writer.Write(tokenizer.Text()) // BAD: writing unescaped HTML data
writer.Write([]byte(tokenizer.Token().Data)) // BAD: writing unescaped HTML data
writer.Write(value) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
writer.Write(tokenizer.Text()) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
writer.Write([]byte(tokenizer.Token().Data)) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
tokenizerFragment := html.NewTokenizerFragment(request.Body, "some context")
writer.Write(tokenizerFragment.Buffered()) // BAD: writing unescaped HTML data
tokenizerFragment := html.NewTokenizerFragment(request.Body, "some context") // $ Source[go/reflected-xss]
writer.Write(tokenizerFragment.Buffered()) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
var cleanNode html.Node
taintedNode, _ := html.Parse(request.Body)
taintedNode, _ := html.Parse(request.Body) // $ Source[go/reflected-xss]
cleanNode.AppendChild(taintedNode)
html.Render(writer, &cleanNode) // BAD: writing unescaped HTML data
html.Render(writer, &cleanNode) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
var cleanNode2 html.Node
taintedNode2, _ := html.Parse(request.Body)
taintedNode2, _ := html.Parse(request.Body) // $ Source[go/reflected-xss]
cleanNode2.InsertBefore(taintedNode2, &cleanNode2)
html.Render(writer, &cleanNode2) // BAD: writing unescaped HTML data
html.Render(writer, &cleanNode2) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data
}
func sqlTest(request *http.Request, db *sql.DB) {
// Ensure EscapeString is a taint propagator for non-XSS queries, e.g. SQL injection:
cookie, _ := request.Cookie("SomeCookie")
db.Query(html.EscapeString(cookie.Value))
cookie, _ := request.Cookie("SomeCookie") // $ Source[go/sql-injection]
db.Query(html.EscapeString(cookie.Value)) // $ Alert[go/sql-injection]
}

View File

@@ -2,7 +2,7 @@ package main
func isPrefixOf(xs, ys []int) bool {
for i := 0; i < len(xs); i++ {
if len(ys) == 0 || xs[i] != ys[i] { // NOT OK
if len(ys) == 0 || xs[i] != ys[i] { // $ Alert // NOT OK
return false
}
}

View File

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

View File

@@ -7,7 +7,7 @@ func zeroOutExceptBad(a []int, lower int, upper int) {
}
// zero out everything above index `upper`
for i := upper + 1; i < len(a); i-- { // NOT OK
for i := upper + 1; i < len(a); i-- { // $ Alert // NOT OK
a[i] = 0
}
}

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