acidtest 0.8.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/acidtest-pr-comment.yml +219 -0
- package/README.md +176 -36
- package/dist/analysis/dataflow-graph.d.ts +19 -0
- package/dist/analysis/dataflow-graph.d.ts.map +1 -0
- package/dist/analysis/dataflow-graph.js +365 -0
- package/dist/analysis/dataflow-graph.js.map +1 -0
- package/dist/analysis/dataflow-types.d.ts +86 -0
- package/dist/analysis/dataflow-types.d.ts.map +1 -0
- package/dist/analysis/dataflow-types.js +8 -0
- package/dist/analysis/dataflow-types.js.map +1 -0
- package/dist/analysis/dataflow.test.d.ts +7 -0
- package/dist/analysis/dataflow.test.d.ts.map +1 -0
- package/dist/analysis/dataflow.test.js +257 -0
- package/dist/analysis/dataflow.test.js.map +1 -0
- package/dist/analysis/taint-propagation.d.ts +30 -0
- package/dist/analysis/taint-propagation.d.ts.map +1 -0
- package/dist/analysis/taint-propagation.js +207 -0
- package/dist/analysis/taint-propagation.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/layers/code.d.ts +1 -1
- package/dist/layers/code.d.ts.map +1 -1
- package/dist/layers/code.js +247 -3
- package/dist/layers/code.js.map +1 -1
- package/dist/layers/code.test.js +196 -0
- package/dist/layers/code.test.js.map +1 -1
- package/dist/layers/crossref.d.ts.map +1 -1
- package/dist/layers/crossref.js +7 -0
- package/dist/layers/crossref.js.map +1 -1
- package/dist/layers/dataflow.d.ts +29 -0
- package/dist/layers/dataflow.d.ts.map +1 -0
- package/dist/layers/dataflow.js +217 -0
- package/dist/layers/dataflow.js.map +1 -0
- package/dist/layers/injection.d.ts.map +1 -1
- package/dist/layers/injection.js +8 -1
- package/dist/layers/injection.js.map +1 -1
- package/dist/layers/permissions.d.ts.map +1 -1
- package/dist/layers/permissions.js +7 -0
- package/dist/layers/permissions.js.map +1 -1
- package/dist/mcp-server.js +1 -1
- package/dist/parsers/parser-interface.d.ts +31 -0
- package/dist/parsers/parser-interface.d.ts.map +1 -0
- package/dist/parsers/parser-interface.js +6 -0
- package/dist/parsers/parser-interface.js.map +1 -0
- package/dist/parsers/parsers.test.d.ts +5 -0
- package/dist/parsers/parsers.test.d.ts.map +1 -0
- package/dist/parsers/parsers.test.js +111 -0
- package/dist/parsers/parsers.test.js.map +1 -0
- package/dist/parsers/python-parser.d.ts +18 -0
- package/dist/parsers/python-parser.d.ts.map +1 -0
- package/dist/parsers/python-parser.js +120 -0
- package/dist/parsers/python-parser.js.map +1 -0
- package/dist/parsers/typescript-parser.d.ts +16 -0
- package/dist/parsers/typescript-parser.d.ts.map +1 -0
- package/dist/parsers/typescript-parser.js +112 -0
- package/dist/parsers/typescript-parser.js.map +1 -0
- package/dist/patterns/dangerous-calls-python.json +220 -0
- package/dist/patterns/dangerous-imports-python.json +256 -0
- package/dist/patterns/insecure-crypto.json +163 -0
- package/dist/patterns/prototype-pollution.json +72 -0
- package/dist/patterns/python-deserialization.json +94 -0
- package/dist/patterns/regex-dos.json +50 -0
- package/dist/patterns/sql-injection.json +91 -0
- package/dist/patterns/xss-injection.json +115 -0
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +6 -0
- package/dist/reporter.js.map +1 -1
- package/dist/scanner.d.ts +1 -1
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +48 -5
- package/dist/scanner.js.map +1 -1
- package/dist/scanner.test.js +31 -0
- package/dist/scanner.test.js.map +1 -1
- package/dist/schemas/pattern.schema.json +139 -0
- package/dist/test-corpus/validate-corpus.d.ts +7 -0
- package/dist/test-corpus/validate-corpus.d.ts.map +1 -0
- package/dist/test-corpus/validate-corpus.js +341 -0
- package/dist/test-corpus/validate-corpus.js.map +1 -0
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/validation/pattern-validator.d.ts +34 -0
- package/dist/validation/pattern-validator.d.ts.map +1 -0
- package/dist/validation/pattern-validator.js +168 -0
- package/dist/validation/pattern-validator.js.map +1 -0
- package/dist/validation/pattern-validator.test.d.ts +5 -0
- package/dist/validation/pattern-validator.test.d.ts.map +1 -0
- package/dist/validation/pattern-validator.test.js +222 -0
- package/dist/validation/pattern-validator.test.js.map +1 -0
- package/dist/validation/validate-patterns.d.ts +6 -0
- package/dist/validation/validate-patterns.d.ts.map +1 -0
- package/dist/validation/validate-patterns.js +55 -0
- package/dist/validation/validate-patterns.js.map +1 -0
- package/package.json +11 -4
- package/test-fixtures/fixture-no-manifest-node/README.md +4 -0
- package/test-fixtures/fixture-no-manifest-node/index.js +24 -0
- package/test-fixtures/fixture-no-manifest-python/README.md +4 -0
- package/test-fixtures/fixture-no-manifest-python/app.py +24 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Python parser implementation using tree-sitter-python
|
|
3
|
+
* Extracts imports, functions, and variables from Python code
|
|
4
|
+
*/
|
|
5
|
+
import Parser from 'tree-sitter';
|
|
6
|
+
import Python from 'tree-sitter-python';
|
|
7
|
+
export class PythonParser {
|
|
8
|
+
parser;
|
|
9
|
+
constructor() {
|
|
10
|
+
this.parser = new Parser();
|
|
11
|
+
// For tree-sitter 0.21.x, Python is the language object itself
|
|
12
|
+
this.parser.setLanguage(Python);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Check if this parser can handle the given file
|
|
16
|
+
*/
|
|
17
|
+
canParse(filePath) {
|
|
18
|
+
return /\.py$/i.test(filePath);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parse Python file and extract information
|
|
22
|
+
*/
|
|
23
|
+
parse(filePath, content) {
|
|
24
|
+
const tree = this.parser.parse(content);
|
|
25
|
+
const rootNode = tree.rootNode;
|
|
26
|
+
const imports = [];
|
|
27
|
+
const functions = [];
|
|
28
|
+
const variables = [];
|
|
29
|
+
// Traverse the AST
|
|
30
|
+
const traverse = (node) => {
|
|
31
|
+
// Extract import statements: import X, import Y
|
|
32
|
+
if (node.type === 'import_statement') {
|
|
33
|
+
const nameNode = node.childForFieldName('name');
|
|
34
|
+
if (nameNode) {
|
|
35
|
+
const module = nameNode.text;
|
|
36
|
+
const line = node.startPosition.row + 1;
|
|
37
|
+
imports.push({ module, names: [], line });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Extract from imports: from X import Y, Z
|
|
41
|
+
if (node.type === 'import_from_statement') {
|
|
42
|
+
const moduleNode = node.childForFieldName('module_name');
|
|
43
|
+
const module = moduleNode ? moduleNode.text : '';
|
|
44
|
+
const names = [];
|
|
45
|
+
const line = node.startPosition.row + 1;
|
|
46
|
+
// Get imported names
|
|
47
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
48
|
+
const child = node.child(i);
|
|
49
|
+
if (child?.type === 'dotted_name' || child?.type === 'identifier') {
|
|
50
|
+
// This might be the imported name
|
|
51
|
+
const nameText = child.text;
|
|
52
|
+
if (nameText !== module && !names.includes(nameText)) {
|
|
53
|
+
names.push(nameText);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else if (child?.type === 'aliased_import') {
|
|
57
|
+
const nameChild = child.childForFieldName('name');
|
|
58
|
+
if (nameChild) {
|
|
59
|
+
names.push(nameChild.text);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
imports.push({ module, names, line });
|
|
64
|
+
}
|
|
65
|
+
// Extract function definitions
|
|
66
|
+
if (node.type === 'function_definition') {
|
|
67
|
+
const nameNode = node.childForFieldName('name');
|
|
68
|
+
if (nameNode) {
|
|
69
|
+
const name = nameNode.text;
|
|
70
|
+
const params = [];
|
|
71
|
+
const line = node.startPosition.row + 1;
|
|
72
|
+
// Get parameters
|
|
73
|
+
const parametersNode = node.childForFieldName('parameters');
|
|
74
|
+
if (parametersNode) {
|
|
75
|
+
for (let i = 0; i < parametersNode.childCount; i++) {
|
|
76
|
+
const paramChild = parametersNode.child(i);
|
|
77
|
+
if (paramChild?.type === 'identifier') {
|
|
78
|
+
params.push(paramChild.text);
|
|
79
|
+
}
|
|
80
|
+
else if (paramChild?.type === 'typed_parameter' || paramChild?.type === 'default_parameter') {
|
|
81
|
+
const paramName = paramChild.childForFieldName('name');
|
|
82
|
+
if (paramName) {
|
|
83
|
+
params.push(paramName.text);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
functions.push({ name, params, line });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Extract variable assignments at module level
|
|
92
|
+
if (node.type === 'assignment' && node.parent?.type === 'expression_statement') {
|
|
93
|
+
const leftNode = node.childForFieldName('left');
|
|
94
|
+
const rightNode = node.childForFieldName('right');
|
|
95
|
+
if (leftNode?.type === 'identifier') {
|
|
96
|
+
const name = leftNode.text;
|
|
97
|
+
const value = rightNode ? rightNode.text.substring(0, 100) : undefined;
|
|
98
|
+
const line = node.startPosition.row + 1;
|
|
99
|
+
variables.push({ name, value, line });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Recursively traverse children
|
|
103
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
104
|
+
const child = node.child(i);
|
|
105
|
+
if (child) {
|
|
106
|
+
traverse(child);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
traverse(rootNode);
|
|
111
|
+
return {
|
|
112
|
+
filePath,
|
|
113
|
+
ast: tree,
|
|
114
|
+
imports,
|
|
115
|
+
functions,
|
|
116
|
+
variables
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=python-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python-parser.js","sourceRoot":"","sources":["../../src/parsers/python-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript/JavaScript parser implementation
|
|
3
|
+
* Extracts imports, functions, and variables from TypeScript/JavaScript code
|
|
4
|
+
*/
|
|
5
|
+
import type { Parser, ParsedFile } from './parser-interface.js';
|
|
6
|
+
export declare class TypeScriptParser implements Parser {
|
|
7
|
+
/**
|
|
8
|
+
* Check if this parser can handle the given file
|
|
9
|
+
*/
|
|
10
|
+
canParse(filePath: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Parse TypeScript/JavaScript file and extract information
|
|
13
|
+
*/
|
|
14
|
+
parse(filePath: string, content: string): ParsedFile;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=typescript-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typescript-parser.d.ts","sourceRoot":"","sources":["../../src/parsers/typescript-parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAA4D,MAAM,uBAAuB,CAAC;AAE1H,qBAAa,gBAAiB,YAAW,MAAM;IAC7C;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAInC;;OAEG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU;CA+GrD"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript/JavaScript parser implementation
|
|
3
|
+
* Extracts imports, functions, and variables from TypeScript/JavaScript code
|
|
4
|
+
*/
|
|
5
|
+
import ts from 'typescript';
|
|
6
|
+
export class TypeScriptParser {
|
|
7
|
+
/**
|
|
8
|
+
* Check if this parser can handle the given file
|
|
9
|
+
*/
|
|
10
|
+
canParse(filePath) {
|
|
11
|
+
return /\.(ts|js|mjs|cjs)$/i.test(filePath);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse TypeScript/JavaScript file and extract information
|
|
15
|
+
*/
|
|
16
|
+
parse(filePath, content) {
|
|
17
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
18
|
+
const imports = [];
|
|
19
|
+
const functions = [];
|
|
20
|
+
const variables = [];
|
|
21
|
+
// Traverse AST to extract imports, functions, and variables
|
|
22
|
+
const visit = (node) => {
|
|
23
|
+
// Extract import statements
|
|
24
|
+
if (ts.isImportDeclaration(node)) {
|
|
25
|
+
const importClause = node.importClause;
|
|
26
|
+
const moduleSpecifier = node.moduleSpecifier;
|
|
27
|
+
if (ts.isStringLiteral(moduleSpecifier)) {
|
|
28
|
+
const module = moduleSpecifier.text;
|
|
29
|
+
const names = [];
|
|
30
|
+
// Named imports
|
|
31
|
+
if (importClause?.namedBindings) {
|
|
32
|
+
if (ts.isNamedImports(importClause.namedBindings)) {
|
|
33
|
+
for (const element of importClause.namedBindings.elements) {
|
|
34
|
+
names.push(element.name.text);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (ts.isNamespaceImport(importClause.namedBindings)) {
|
|
38
|
+
names.push(importClause.namedBindings.name.text);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Default import
|
|
42
|
+
if (importClause?.name) {
|
|
43
|
+
names.push(importClause.name.text);
|
|
44
|
+
}
|
|
45
|
+
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
|
|
46
|
+
imports.push({ module, names, line });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Extract require() calls
|
|
50
|
+
if (ts.isCallExpression(node)) {
|
|
51
|
+
const expression = node.expression;
|
|
52
|
+
if (ts.isIdentifier(expression) && expression.text === 'require') {
|
|
53
|
+
if (node.arguments.length > 0) {
|
|
54
|
+
const arg = node.arguments[0];
|
|
55
|
+
if (ts.isStringLiteral(arg)) {
|
|
56
|
+
const module = arg.text;
|
|
57
|
+
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
|
|
58
|
+
imports.push({ module, names: [], line });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Extract function declarations
|
|
64
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
65
|
+
const name = node.name.text;
|
|
66
|
+
const params = node.parameters.map(p => {
|
|
67
|
+
if (ts.isIdentifier(p.name)) {
|
|
68
|
+
return p.name.text;
|
|
69
|
+
}
|
|
70
|
+
return p.name.getText(sourceFile);
|
|
71
|
+
});
|
|
72
|
+
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
|
|
73
|
+
functions.push({ name, params, line });
|
|
74
|
+
}
|
|
75
|
+
// Extract arrow functions assigned to variables
|
|
76
|
+
if (ts.isVariableStatement(node)) {
|
|
77
|
+
for (const declaration of node.declarationList.declarations) {
|
|
78
|
+
if (ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
79
|
+
const name = declaration.name.text;
|
|
80
|
+
const line = sourceFile.getLineAndCharacterOfPosition(declaration.getStart()).line + 1;
|
|
81
|
+
// Check if it's a function
|
|
82
|
+
if (ts.isArrowFunction(declaration.initializer) || ts.isFunctionExpression(declaration.initializer)) {
|
|
83
|
+
const funcNode = declaration.initializer;
|
|
84
|
+
const params = funcNode.parameters.map(p => {
|
|
85
|
+
if (ts.isIdentifier(p.name)) {
|
|
86
|
+
return p.name.text;
|
|
87
|
+
}
|
|
88
|
+
return p.name.getText(sourceFile);
|
|
89
|
+
});
|
|
90
|
+
functions.push({ name, params, line });
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Regular variable
|
|
94
|
+
const value = declaration.initializer.getText(sourceFile).substring(0, 100);
|
|
95
|
+
variables.push({ name, value, line });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
ts.forEachChild(node, visit);
|
|
101
|
+
};
|
|
102
|
+
visit(sourceFile);
|
|
103
|
+
return {
|
|
104
|
+
filePath,
|
|
105
|
+
ast: sourceFile,
|
|
106
|
+
imports,
|
|
107
|
+
functions,
|
|
108
|
+
variables
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=typescript-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typescript-parser.js","sourceRoot":"","sources":["../../src/parsers/typescript-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
{
|
|
2
|
+
"category": "dangerous-calls",
|
|
3
|
+
"patterns": [
|
|
4
|
+
{
|
|
5
|
+
"id": "pycall-001",
|
|
6
|
+
"name": "subprocess-shell-true",
|
|
7
|
+
"description": "Uses subprocess with shell=True, enabling shell injection",
|
|
8
|
+
"severity": "CRITICAL",
|
|
9
|
+
"match": {
|
|
10
|
+
"type": "regex",
|
|
11
|
+
"value": "subprocess\\.(run|call|Popen|check_output|check_call)\\s*\\([^)]*shell\\s*=\\s*True",
|
|
12
|
+
"flags": "g"
|
|
13
|
+
},
|
|
14
|
+
"layer": "code",
|
|
15
|
+
"remediation": {
|
|
16
|
+
"title": "Remove shell=True from subprocess calls",
|
|
17
|
+
"suggestions": [
|
|
18
|
+
"Use explicit argument lists: subprocess.run(['cmd', 'arg1', 'arg2'])",
|
|
19
|
+
"Never set shell=True, especially with user input",
|
|
20
|
+
"Use shlex.quote() if you must construct shell commands",
|
|
21
|
+
"Consider using pathlib or os.path for file operations instead",
|
|
22
|
+
"Validate and sanitize all arguments before passing to subprocess"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "pycall-002",
|
|
28
|
+
"name": "os-system-call",
|
|
29
|
+
"description": "Uses os.system() for direct shell command execution",
|
|
30
|
+
"severity": "CRITICAL",
|
|
31
|
+
"match": {
|
|
32
|
+
"type": "regex",
|
|
33
|
+
"value": "os\\.system\\s*\\(",
|
|
34
|
+
"flags": "g"
|
|
35
|
+
},
|
|
36
|
+
"layer": "code",
|
|
37
|
+
"remediation": {
|
|
38
|
+
"title": "Replace os.system() with subprocess",
|
|
39
|
+
"suggestions": [
|
|
40
|
+
"Use subprocess.run() with explicit arguments instead",
|
|
41
|
+
"Never use os.system() with user-controlled input",
|
|
42
|
+
"Consider using built-in Python APIs for file/path operations",
|
|
43
|
+
"If shell commands are needed, use subprocess without shell=True"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "pycall-003",
|
|
49
|
+
"name": "os-popen-call",
|
|
50
|
+
"description": "Uses os.popen() for shell command execution",
|
|
51
|
+
"severity": "CRITICAL",
|
|
52
|
+
"match": {
|
|
53
|
+
"type": "regex",
|
|
54
|
+
"value": "os\\.popen[234]?\\s*\\(",
|
|
55
|
+
"flags": "g"
|
|
56
|
+
},
|
|
57
|
+
"layer": "code"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "pycall-004",
|
|
61
|
+
"name": "os-exec-family",
|
|
62
|
+
"description": "Uses os.exec* family for program execution",
|
|
63
|
+
"severity": "HIGH",
|
|
64
|
+
"match": {
|
|
65
|
+
"type": "regex",
|
|
66
|
+
"value": "os\\.(execl|execle|execlp|execlpe|execv|execve|execvp|execvpe)\\s*\\(",
|
|
67
|
+
"flags": "g"
|
|
68
|
+
},
|
|
69
|
+
"layer": "code"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "pycall-005",
|
|
73
|
+
"name": "os-spawn-family",
|
|
74
|
+
"description": "Uses os.spawn* family for process spawning",
|
|
75
|
+
"severity": "HIGH",
|
|
76
|
+
"match": {
|
|
77
|
+
"type": "regex",
|
|
78
|
+
"value": "os\\.(spawnl|spawnle|spawnlp|spawnlpe|spawnv|spawnve|spawnvp|spawnvpe)\\s*\\(",
|
|
79
|
+
"flags": "g"
|
|
80
|
+
},
|
|
81
|
+
"layer": "code"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id": "pycall-006",
|
|
85
|
+
"name": "pickle-loads-call",
|
|
86
|
+
"description": "Uses pickle.loads() which can execute arbitrary code",
|
|
87
|
+
"severity": "CRITICAL",
|
|
88
|
+
"match": {
|
|
89
|
+
"type": "regex",
|
|
90
|
+
"value": "pickle\\.(loads?|Unpickler)\\s*\\(",
|
|
91
|
+
"flags": "g"
|
|
92
|
+
},
|
|
93
|
+
"layer": "code",
|
|
94
|
+
"remediation": {
|
|
95
|
+
"title": "Avoid unpickling untrusted data",
|
|
96
|
+
"suggestions": [
|
|
97
|
+
"Use json.loads() for deserializing JSON data instead",
|
|
98
|
+
"Never unpickle data from untrusted or user-controlled sources",
|
|
99
|
+
"If pickle is required, verify data integrity with HMAC signatures",
|
|
100
|
+
"Consider using safer formats like JSON, msgpack, or protobuf",
|
|
101
|
+
"Implement a restricted unpickler with custom find_class() method"
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "pycall-007",
|
|
107
|
+
"name": "marshal-loads-call",
|
|
108
|
+
"description": "Uses marshal.loads() for deserialization",
|
|
109
|
+
"severity": "HIGH",
|
|
110
|
+
"match": {
|
|
111
|
+
"type": "regex",
|
|
112
|
+
"value": "marshal\\.loads?\\s*\\(",
|
|
113
|
+
"flags": "g"
|
|
114
|
+
},
|
|
115
|
+
"layer": "code"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": "pycall-008",
|
|
119
|
+
"name": "yaml-unsafe-load",
|
|
120
|
+
"description": "Uses yaml.load() without safe loader, enabling arbitrary code execution",
|
|
121
|
+
"severity": "CRITICAL",
|
|
122
|
+
"match": {
|
|
123
|
+
"type": "regex",
|
|
124
|
+
"value": "yaml\\.load\\s*\\([^,)]*\\)",
|
|
125
|
+
"flags": "g"
|
|
126
|
+
},
|
|
127
|
+
"layer": "code",
|
|
128
|
+
"remediation": {
|
|
129
|
+
"title": "Use yaml.safe_load() instead",
|
|
130
|
+
"suggestions": [
|
|
131
|
+
"Replace yaml.load() with yaml.safe_load()",
|
|
132
|
+
"If you need custom tags, use yaml.load(data, Loader=yaml.SafeLoader)",
|
|
133
|
+
"Never use yaml.load() with untrusted input",
|
|
134
|
+
"Consider validating YAML structure after loading"
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"id": "pycall-009",
|
|
140
|
+
"name": "code-object-exec",
|
|
141
|
+
"description": "Executes code objects from compile()",
|
|
142
|
+
"severity": "HIGH",
|
|
143
|
+
"match": {
|
|
144
|
+
"type": "regex",
|
|
145
|
+
"value": "exec\\s*\\(\\s*compile\\s*\\(",
|
|
146
|
+
"flags": "g"
|
|
147
|
+
},
|
|
148
|
+
"layer": "code"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"id": "pycall-010",
|
|
152
|
+
"name": "file-write-operations",
|
|
153
|
+
"description": "Opens files in write mode which could overwrite data",
|
|
154
|
+
"severity": "MEDIUM",
|
|
155
|
+
"match": {
|
|
156
|
+
"type": "regex",
|
|
157
|
+
"value": "open\\s*\\([^)]*['\"]w",
|
|
158
|
+
"flags": "g"
|
|
159
|
+
},
|
|
160
|
+
"layer": "code"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"id": "pycall-011",
|
|
164
|
+
"name": "os-remove-operations",
|
|
165
|
+
"description": "Deletes files or directories",
|
|
166
|
+
"severity": "MEDIUM",
|
|
167
|
+
"match": {
|
|
168
|
+
"type": "regex",
|
|
169
|
+
"value": "os\\.(remove|unlink|rmdir|removedirs)\\s*\\(",
|
|
170
|
+
"flags": "g"
|
|
171
|
+
},
|
|
172
|
+
"layer": "code"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"id": "pycall-012",
|
|
176
|
+
"name": "shutil-rmtree",
|
|
177
|
+
"description": "Recursively deletes directory trees",
|
|
178
|
+
"severity": "HIGH",
|
|
179
|
+
"match": {
|
|
180
|
+
"type": "regex",
|
|
181
|
+
"value": "shutil\\.rmtree\\s*\\(",
|
|
182
|
+
"flags": "g"
|
|
183
|
+
},
|
|
184
|
+
"layer": "code"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"id": "pycall-013",
|
|
188
|
+
"name": "tempfile-mktemp",
|
|
189
|
+
"description": "Uses deprecated mktemp() which has security issues",
|
|
190
|
+
"severity": "MEDIUM",
|
|
191
|
+
"match": {
|
|
192
|
+
"type": "regex",
|
|
193
|
+
"value": "tempfile\\.mktemp\\s*\\(",
|
|
194
|
+
"flags": "g"
|
|
195
|
+
},
|
|
196
|
+
"layer": "code",
|
|
197
|
+
"remediation": {
|
|
198
|
+
"title": "Replace mktemp() with safer alternatives",
|
|
199
|
+
"suggestions": [
|
|
200
|
+
"Use tempfile.mkstemp() which creates files securely",
|
|
201
|
+
"Use tempfile.TemporaryFile() for automatic cleanup",
|
|
202
|
+
"Use tempfile.NamedTemporaryFile() if you need a file name",
|
|
203
|
+
"Never use mktemp() as it's vulnerable to race conditions"
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"id": "pycall-014",
|
|
209
|
+
"name": "assert-statement",
|
|
210
|
+
"description": "Uses assert statements which are removed in optimized bytecode",
|
|
211
|
+
"severity": "LOW",
|
|
212
|
+
"match": {
|
|
213
|
+
"type": "regex",
|
|
214
|
+
"value": "\\bassert\\s+",
|
|
215
|
+
"flags": "g"
|
|
216
|
+
},
|
|
217
|
+
"layer": "code"
|
|
218
|
+
}
|
|
219
|
+
]
|
|
220
|
+
}
|