mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-06 02:30:47 -08:00
test: codeql for wikioperation (#647)
* test: codeql for wikioperation * test: codeql not find suite * Move CodeQL analysis to dedicated workflow Extracted the CodeQL security analysis job from test.yml into a new codeql-analysis.yml workflow file for better separation of concerns and maintainability. * Update codeql-analysis.yml * de * 。
This commit is contained in:
parent
47a0c93cfe
commit
6700c62243
9 changed files with 358 additions and 15 deletions
18
.github/codeql/codeql-config.yml
vendored
Normal file
18
.github/codeql/codeql-config.yml
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
name: "TidGi CodeQL Security Analysis"
|
||||||
|
|
||||||
|
queries:
|
||||||
|
- uses: security-extended
|
||||||
|
|
||||||
|
# Paths to analyze (only source code)
|
||||||
|
paths:
|
||||||
|
- src
|
||||||
|
- scripts
|
||||||
|
|
||||||
|
# Paths to ignore within the analyzed paths
|
||||||
|
# (Excludes test files and mock data from security analysis)
|
||||||
|
paths-ignore:
|
||||||
|
- '**/__tests__/**'
|
||||||
|
- '**/__mocks__/**'
|
||||||
|
- '**/*.test.ts'
|
||||||
|
- '**/*.test.tsx'
|
||||||
|
- '**/*.spec.ts'
|
||||||
30
.github/codeql/codeql-pack.lock.yml
vendored
Normal file
30
.github/codeql/codeql-pack.lock.yml
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
lockVersion: 1.0.0
|
||||||
|
dependencies:
|
||||||
|
codeql/concepts:
|
||||||
|
version: 0.0.7
|
||||||
|
codeql/controlflow:
|
||||||
|
version: 2.0.17
|
||||||
|
codeql/dataflow:
|
||||||
|
version: 2.0.17
|
||||||
|
codeql/javascript-all:
|
||||||
|
version: 2.6.13
|
||||||
|
codeql/mad:
|
||||||
|
version: 1.0.33
|
||||||
|
codeql/regex:
|
||||||
|
version: 1.0.33
|
||||||
|
codeql/ssa:
|
||||||
|
version: 2.0.9
|
||||||
|
codeql/threat-models:
|
||||||
|
version: 1.0.33
|
||||||
|
codeql/tutorial:
|
||||||
|
version: 1.0.33
|
||||||
|
codeql/typetracking:
|
||||||
|
version: 2.0.17
|
||||||
|
codeql/util:
|
||||||
|
version: 2.0.20
|
||||||
|
codeql/xml:
|
||||||
|
version: 1.0.33
|
||||||
|
codeql/yaml:
|
||||||
|
version: 1.0.33
|
||||||
|
compiled: false
|
||||||
83
.github/codeql/electron-executejavascript.ql
vendored
Normal file
83
.github/codeql/electron-executejavascript.ql
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
/**
|
||||||
|
* @name Unsafe use of webFrame.executeJavaScript with user input
|
||||||
|
* @description Detects Electron webFrame.executeJavaScript calls with potentially tainted template strings
|
||||||
|
* @kind path-problem
|
||||||
|
* @problem.severity error
|
||||||
|
* @security-severity 9.0
|
||||||
|
* @precision high
|
||||||
|
* @id tidgi/electron-execute-javascript-injection
|
||||||
|
* @tags security
|
||||||
|
* electron
|
||||||
|
* external/cwe/cwe-094
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javascript
|
||||||
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to webFrame.executeJavaScript
|
||||||
|
*/
|
||||||
|
class ExecuteJavaScriptCall extends DataFlow::MethodCallNode {
|
||||||
|
ExecuteJavaScriptCall() {
|
||||||
|
this.getMethodName() = "executeJavaScript" and
|
||||||
|
(
|
||||||
|
this.getReceiver().(DataFlow::PropRead).getPropertyName() = "webFrame" or
|
||||||
|
this.getReceiver().asExpr().(Identifier).getName() = "webFrame"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for tracking unsafe executeJavaScript usage
|
||||||
|
*/
|
||||||
|
class ExecuteJavaScriptInjectionConfig extends TaintTracking::Configuration {
|
||||||
|
ExecuteJavaScriptInjectionConfig() {
|
||||||
|
this = "ExecuteJavaScriptInjectionConfig"
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node source) {
|
||||||
|
// Function parameters
|
||||||
|
source.asExpr() instanceof Parameter or
|
||||||
|
// Object property access
|
||||||
|
source instanceof DataFlow::PropRead or
|
||||||
|
// Deep link handlers
|
||||||
|
exists(DataFlow::CallNode call |
|
||||||
|
(call.getCalleeName() = "on" or call.getCalleeName() = "handle") and
|
||||||
|
call.getArgument(0).getStringValue() = ["open-url", "second-instance"] and
|
||||||
|
source = call.getCallback(1).getParameter([0..2])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(ExecuteJavaScriptCall exec |
|
||||||
|
sink = exec.getArgument(0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSanitizer(DataFlow::Node node) {
|
||||||
|
// JSON.stringify sanitizes the input
|
||||||
|
exists(DataFlow::CallNode call |
|
||||||
|
call = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") and
|
||||||
|
node = call
|
||||||
|
) or
|
||||||
|
// Explicit type checks
|
||||||
|
exists(DataFlow::CallNode call |
|
||||||
|
call.getCalleeName() = ["isString", "isNumber", "isBoolean"] and
|
||||||
|
node = call
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
|
// Template string interpolation is a taint step
|
||||||
|
exists(TemplateLiteral tl |
|
||||||
|
pred.asExpr() = tl.getAnElement() and
|
||||||
|
succ.asExpr() = tl
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
from ExecuteJavaScriptInjectionConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||||
|
where config.hasFlowPath(source, sink)
|
||||||
|
select sink.getNode(), source, sink,
|
||||||
|
"Potential code injection in webFrame.executeJavaScript: user input $@ flows into executed code without proper sanitization",
|
||||||
|
source.getNode(), "here"
|
||||||
83
.github/codeql/new-function-injection.ql
vendored
Normal file
83
.github/codeql/new-function-injection.ql
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
/**
|
||||||
|
* @name Unsafe use of Function constructor with user input
|
||||||
|
* @description Detects Function constructor calls with potentially tainted template strings
|
||||||
|
* @kind path-problem
|
||||||
|
* @problem.severity error
|
||||||
|
* @security-severity 9.0
|
||||||
|
* @precision high
|
||||||
|
* @id tidgi/new-function-injection
|
||||||
|
* @tags security
|
||||||
|
* external/cwe/cwe-094
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javascript
|
||||||
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to the Function constructor
|
||||||
|
*/
|
||||||
|
class FunctionConstructorCall extends DataFlow::NewNode {
|
||||||
|
FunctionConstructorCall() {
|
||||||
|
this.getCalleeName() = "Function"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for tracking unsafe Function constructor usage
|
||||||
|
*/
|
||||||
|
class FunctionConstructorInjectionConfig extends TaintTracking::Configuration {
|
||||||
|
FunctionConstructorInjectionConfig() {
|
||||||
|
this = "FunctionConstructorInjectionConfig"
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node source) {
|
||||||
|
// Function parameters
|
||||||
|
source.asExpr() instanceof Parameter or
|
||||||
|
// Object property access
|
||||||
|
source instanceof DataFlow::PropRead or
|
||||||
|
// IPC message handlers
|
||||||
|
exists(DataFlow::CallNode call |
|
||||||
|
(call.getCalleeName() = "on" or call.getCalleeName() = "handle") and
|
||||||
|
source = call.getCallback([0..1]).getParameter([0..2])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(FunctionConstructorCall fnCall |
|
||||||
|
sink = fnCall.getAnArgument()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSanitizer(DataFlow::Node node) {
|
||||||
|
// JSON.parse/stringify are safe
|
||||||
|
exists(DataFlow::CallNode call |
|
||||||
|
call = DataFlow::globalVarRef("JSON").getAMemberCall(["stringify", "parse"]) and
|
||||||
|
node = call
|
||||||
|
) or
|
||||||
|
// Whitelist validation
|
||||||
|
exists(DataFlow::MethodCallNode test |
|
||||||
|
test.getMethodName() = "test" and
|
||||||
|
test.getReceiver().asExpr() instanceof RegExpLiteral and
|
||||||
|
node = test
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
|
// Template string interpolation
|
||||||
|
exists(TemplateLiteral tl |
|
||||||
|
pred.asExpr() = tl.getAnElement() and
|
||||||
|
succ.asExpr() = tl
|
||||||
|
) or
|
||||||
|
// String concatenation
|
||||||
|
exists(AddExpr add |
|
||||||
|
pred.asExpr() = add.getAnOperand() and
|
||||||
|
succ.asExpr() = add
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
from FunctionConstructorInjectionConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||||
|
where config.hasFlowPath(source, sink)
|
||||||
|
select sink.getNode(), source, sink,
|
||||||
|
"Potential code injection via Function constructor: user input $@ flows into dynamically created function",
|
||||||
|
source.getNode(), "here"
|
||||||
4
.github/codeql/qlpack.yml
vendored
Normal file
4
.github/codeql/qlpack.yml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
name: tidgi/security-queries
|
||||||
|
version: 1.0.0
|
||||||
|
dependencies:
|
||||||
|
codeql/javascript-all: "*"
|
||||||
96
.github/codeql/template-string-injection.ql
vendored
Normal file
96
.github/codeql/template-string-injection.ql
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
/**
|
||||||
|
* @name Template string injection in code execution
|
||||||
|
* @description Detects user input flowing into template strings that are passed to code execution functions
|
||||||
|
* @kind path-problem
|
||||||
|
* @problem.severity error
|
||||||
|
* @security-severity 9.3
|
||||||
|
* @precision high
|
||||||
|
* @id tidgi/template-string-injection
|
||||||
|
* @tags security
|
||||||
|
* external/cwe/cwe-094
|
||||||
|
* external/cwe/cwe-095
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javascript
|
||||||
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to a function that executes code dynamically
|
||||||
|
*/
|
||||||
|
class CodeExecutionCall extends DataFlow::CallNode {
|
||||||
|
CodeExecutionCall() {
|
||||||
|
// Direct code execution
|
||||||
|
this.getCalleeName() = ["eval", "Function"] or
|
||||||
|
// Electron-specific code execution
|
||||||
|
this.getCalleeName() = "executeJavaScript" or
|
||||||
|
// VM module code execution
|
||||||
|
this.(DataFlow::MethodCallNode).getMethodName() = ["runInContext", "runInNewContext", "runInThisContext"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A template literal that contains potentially tainted elements
|
||||||
|
*/
|
||||||
|
class TaintedTemplateLiteral extends DataFlow::Node {
|
||||||
|
TemplateLiteral literal;
|
||||||
|
|
||||||
|
TaintedTemplateLiteral() {
|
||||||
|
this.asExpr() = literal
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateLiteral getLiteral() {
|
||||||
|
result = literal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for tracking tainted data flow into template literals used in code execution
|
||||||
|
*/
|
||||||
|
class TemplateStringInjectionConfig extends TaintTracking::Configuration {
|
||||||
|
TemplateStringInjectionConfig() {
|
||||||
|
this = "TemplateStringInjectionConfig"
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node source) {
|
||||||
|
// Any parameter or property access could be user-controlled
|
||||||
|
source.asExpr() instanceof Parameter or
|
||||||
|
source instanceof DataFlow::PropRead or
|
||||||
|
// IPC sources in Electron
|
||||||
|
exists(DataFlow::CallNode call |
|
||||||
|
call.getCalleeName() = ["on", "handle", "once"] and
|
||||||
|
source = call.getCallback(0).getParameter(1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node sink) {
|
||||||
|
// Template literal elements that flow into code execution
|
||||||
|
exists(CodeExecutionCall exec, TaintedTemplateLiteral tl |
|
||||||
|
exec.getAnArgument() = tl and
|
||||||
|
exists(Expr element |
|
||||||
|
element = tl.getLiteral().getAnElement() and
|
||||||
|
sink.asExpr() = element
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSanitizer(DataFlow::Node node) {
|
||||||
|
// JSON.stringify is a safe sanitizer
|
||||||
|
exists(DataFlow::CallNode call |
|
||||||
|
call = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") and
|
||||||
|
node = call
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
from TemplateStringInjectionConfig config, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||||
|
CodeExecutionCall exec, TaintedTemplateLiteral tl
|
||||||
|
where
|
||||||
|
config.hasFlowPath(source, sink) and
|
||||||
|
exec.getAnArgument() = tl and
|
||||||
|
exists(Expr element |
|
||||||
|
element = tl.getLiteral().getAnElement() and
|
||||||
|
sink.getNode().asExpr() = element
|
||||||
|
)
|
||||||
|
select exec, source, sink,
|
||||||
|
"Potential code injection: user input $@ flows into template string passed to " + exec.getCalleeName(),
|
||||||
|
source.getNode(), "here"
|
||||||
42
.github/workflows/codeql-analysis.yml
vendored
Normal file
42
.github/workflows/codeql-analysis.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
name: "CodeQL Security Analysis"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*.*.*"
|
||||||
|
paths-ignore:
|
||||||
|
- "README.md"
|
||||||
|
- "docs/**"
|
||||||
|
- ".vscode"
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths-ignore:
|
||||||
|
- "docs/**"
|
||||||
|
- "README.md"
|
||||||
|
- ".vscode"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze JavaScript/TypeScript
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v3
|
||||||
|
with:
|
||||||
|
languages: javascript-typescript
|
||||||
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
|
queries: +./.github/codeql
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v3
|
||||||
|
with:
|
||||||
|
category: "/language:javascript-typescript"
|
||||||
14
.github/workflows/test.yml
vendored
14
.github/workflows/test.yml
vendored
|
|
@ -59,17 +59,3 @@ jobs:
|
||||||
userData-test/settings/
|
userData-test/settings/
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
codeql:
|
|
||||||
name: CodeQL Analysis
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v3
|
|
||||||
with:
|
|
||||||
languages: javascript-typescript
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v3
|
|
||||||
|
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -73,3 +73,4 @@ wiki-dev/
|
||||||
wiki-test/
|
wiki-test/
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
tsconfig.test.json.tsbuildinfo
|
tsconfig.test.json.tsbuildinfo
|
||||||
|
/tidgi-codeql-db
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue