coretrace-python-analyzer 0.1.0__py3-none-any.whl
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.
- coretrace_python/__init__.py +4 -0
- coretrace_python/__main__.py +4 -0
- coretrace_python/abstract/__init__.py +45 -0
- coretrace_python/abstract/constants.py +226 -0
- coretrace_python/abstract/heap.py +252 -0
- coretrace_python/abstract/ranges.py +285 -0
- coretrace_python/abstract/values.py +56 -0
- coretrace_python/analysis/__init__.py +31 -0
- coretrace_python/analysis/manager.py +165 -0
- coretrace_python/analysis/provider.py +73 -0
- coretrace_python/bundled/dependency/dependency_policy/dependency_policy.py +46 -0
- coretrace_python/bundled/dependency/dependency_policy/plugin.toml +9 -0
- coretrace_python/bundled/dependency/reachable_vulnerability/plugin.toml +9 -0
- coretrace_python/bundled/dependency/reachable_vulnerability/reachable_vulnerability.py +56 -0
- coretrace_python/bundled/dependency/sample_advisories/plugin.toml +9 -0
- coretrace_python/bundled/dependency/sample_advisories/sample_advisories.py +109 -0
- coretrace_python/bundled/dependency/vulnerable_dependency/plugin.toml +9 -0
- coretrace_python/bundled/dependency/vulnerable_dependency/vulnerable_dependency.py +43 -0
- coretrace_python/bundled/models/cli/cli_models.py +35 -0
- coretrace_python/bundled/models/cli/plugin.toml +9 -0
- coretrace_python/bundled/models/credentials/credential_models.py +43 -0
- coretrace_python/bundled/models/credentials/plugin.toml +9 -0
- coretrace_python/bundled/models/django/django_models.py +123 -0
- coretrace_python/bundled/models/django/plugin.toml +9 -0
- coretrace_python/bundled/models/fastapi/fastapi_models.py +29 -0
- coretrace_python/bundled/models/fastapi/plugin.toml +9 -0
- coretrace_python/bundled/models/flask/flask_models.py +53 -0
- coretrace_python/bundled/models/flask/plugin.toml +9 -0
- coretrace_python/bundled/models/http_clients/http_client_models.py +43 -0
- coretrace_python/bundled/models/http_clients/plugin.toml +9 -0
- coretrace_python/bundled/models/python_stdlib/plugin.toml +9 -0
- coretrace_python/bundled/models/python_stdlib/python_stdlib.py +68 -0
- coretrace_python/bundled/models/sqlalchemy/plugin.toml +9 -0
- coretrace_python/bundled/models/sqlalchemy/sqlalchemy_models.py +47 -0
- coretrace_python/bundled/secrets/config_secrets/config_secrets.py +38 -0
- coretrace_python/bundled/secrets/config_secrets/plugin.toml +9 -0
- coretrace_python/bundled/secrets/hardcoded_secrets/hardcoded_secrets.py +19 -0
- coretrace_python/bundled/secrets/hardcoded_secrets/plugin.toml +9 -0
- coretrace_python/bundled/security/command_injection/command_injection.py +17 -0
- coretrace_python/bundled/security/command_injection/plugin.toml +9 -0
- coretrace_python/bundled/security/insecure_deserialization/insecure_deserialization.py +17 -0
- coretrace_python/bundled/security/insecure_deserialization/plugin.toml +9 -0
- coretrace_python/bundled/security/open_redirect/open_redirect.py +17 -0
- coretrace_python/bundled/security/open_redirect/plugin.toml +9 -0
- coretrace_python/bundled/security/path_traversal/path_traversal.py +17 -0
- coretrace_python/bundled/security/path_traversal/plugin.toml +9 -0
- coretrace_python/bundled/security/plaintext_credentials/plaintext_credentials.py +21 -0
- coretrace_python/bundled/security/plaintext_credentials/plugin.toml +9 -0
- coretrace_python/bundled/security/sql_injection/plugin.toml +9 -0
- coretrace_python/bundled/security/sql_injection/sql_injection.py +17 -0
- coretrace_python/bundled/security/ssrf/plugin.toml +9 -0
- coretrace_python/bundled/security/ssrf/ssrf.py +17 -0
- coretrace_python/bundled/security/xss/plugin.toml +9 -0
- coretrace_python/bundled/security/xss/xss.py +17 -0
- coretrace_python/bundled/syntax/dangerous_eval/dangerous_eval.py +19 -0
- coretrace_python/bundled/syntax/dangerous_eval/plugin.toml +9 -0
- coretrace_python/bundled/syntax/flask_debug/flask_debug.py +63 -0
- coretrace_python/bundled/syntax/flask_debug/plugin.toml +9 -0
- coretrace_python/bundled/syntax/missing_timeout/missing_timeout.py +51 -0
- coretrace_python/bundled/syntax/missing_timeout/plugin.toml +9 -0
- coretrace_python/bundled/syntax/weak_crypto/plugin.toml +9 -0
- coretrace_python/bundled/syntax/weak_crypto/weak_crypto.py +19 -0
- coretrace_python/cache.py +310 -0
- coretrace_python/cfg/__init__.py +46 -0
- coretrace_python/cfg/builder.py +589 -0
- coretrace_python/cfg/dominance.py +183 -0
- coretrace_python/cfg/model.py +166 -0
- coretrace_python/cli.py +216 -0
- coretrace_python/dataflow/__init__.py +29 -0
- coretrace_python/dataflow/lattice.py +78 -0
- coretrace_python/dataflow/solver.py +96 -0
- coretrace_python/dependency/__init__.py +44 -0
- coretrace_python/dependency/advisories.py +168 -0
- coretrace_python/dependency/correlation.py +87 -0
- coretrace_python/dependency/graph.py +274 -0
- coretrace_python/dependency/policy.py +65 -0
- coretrace_python/dependency/sbom.py +65 -0
- coretrace_python/engine.py +688 -0
- coretrace_python/findings/__init__.py +13 -0
- coretrace_python/findings/coverage.py +45 -0
- coretrace_python/findings/model.py +49 -0
- coretrace_python/findings/refutation.py +427 -0
- coretrace_python/frontend/__init__.py +18 -0
- coretrace_python/frontend/ast_adapter.py +447 -0
- coretrace_python/frontend/parser.py +23 -0
- coretrace_python/hir/__init__.py +5 -0
- coretrace_python/hir/nodes.py +584 -0
- coretrace_python/hir/visitors.py +36 -0
- coretrace_python/interprocedural/__init__.py +49 -0
- coretrace_python/interprocedural/callgraph.py +291 -0
- coretrace_python/interprocedural/modulegraph.py +218 -0
- coretrace_python/interprocedural/summaries.py +463 -0
- coretrace_python/ir/__init__.py +5 -0
- coretrace_python/ir/defuse.py +74 -0
- coretrace_python/ir/lowering.py +575 -0
- coretrace_python/ir/model.py +481 -0
- coretrace_python/ir/printer.py +201 -0
- coretrace_python/ir/ssa.py +277 -0
- coretrace_python/plugins/__init__.py +58 -0
- coretrace_python/plugins/api.py +153 -0
- coretrace_python/plugins/detectors.py +114 -0
- coretrace_python/plugins/loader.py +84 -0
- coretrace_python/plugins/manifest.py +112 -0
- coretrace_python/plugins/registry.py +34 -0
- coretrace_python/plugins/secrets.py +330 -0
- coretrace_python/reporters/__init__.py +22 -0
- coretrace_python/reporters/json_format.py +48 -0
- coretrace_python/reporters/report.py +23 -0
- coretrace_python/reporters/sarif.py +70 -0
- coretrace_python/reporters/text.py +24 -0
- coretrace_python/semantic/__init__.py +9 -0
- coretrace_python/semantic/identity.py +39 -0
- coretrace_python/semantic/imports.py +131 -0
- coretrace_python/semantic/scopes.py +473 -0
- coretrace_python/semantic/symbols.py +87 -0
- coretrace_python/source/__init__.py +13 -0
- coretrace_python/source/manager.py +81 -0
- coretrace_python/source/model.py +57 -0
- coretrace_python/taint/__init__.py +55 -0
- coretrace_python/taint/engine.py +800 -0
- coretrace_python/taint/models.py +317 -0
- coretrace_python/taint/routes.py +99 -0
- coretrace_python_analyzer-0.1.0.dist-info/METADATA +74 -0
- coretrace_python_analyzer-0.1.0.dist-info/RECORD +126 -0
- coretrace_python_analyzer-0.1.0.dist-info/WHEEL +4 -0
- coretrace_python_analyzer-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"""Security model registry (architecture §16, §17).
|
|
2
|
+
|
|
3
|
+
Taint kinds form a bitset joined with ``|``. Plugins register sources, sinks and
|
|
4
|
+
sanitizers keyed by canonical symbol; the engine freezes them into an immutable
|
|
5
|
+
``ModelTable`` and provides it to the Analysis Manager as the ``taint.models`` input,
|
|
6
|
+
so every detector consumes the same models and the same taint result.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import hashlib
|
|
12
|
+
import re
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from enum import Flag, auto
|
|
15
|
+
from types import MappingProxyType
|
|
16
|
+
from typing import ClassVar
|
|
17
|
+
|
|
18
|
+
from coretrace_python.analysis import Analysis, AnalysisContext, MissingInputError
|
|
19
|
+
from coretrace_python.semantic.symbols import SymbolId
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TaintKind(Flag):
|
|
23
|
+
NONE = 0
|
|
24
|
+
SQL = auto()
|
|
25
|
+
COMMAND = auto()
|
|
26
|
+
HTML = auto()
|
|
27
|
+
PATH = auto()
|
|
28
|
+
SSRF = auto()
|
|
29
|
+
CODE = auto()
|
|
30
|
+
ADVISORY = auto()
|
|
31
|
+
DESERIALIZATION = auto()
|
|
32
|
+
REDIRECT = auto()
|
|
33
|
+
ALL = SQL | COMMAND | HTML | PATH | SSRF | CODE | ADVISORY | DESERIALIZATION | REDIRECT
|
|
34
|
+
# Outside ALL on purpose: only credential-named parameters carry it, so a database
|
|
35
|
+
# write reached by ordinary input is not a plaintext credential.
|
|
36
|
+
CREDENTIAL = auto()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ModelError(Exception):
|
|
40
|
+
"""Two models of the same kind claim the same symbol."""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass(frozen=True)
|
|
44
|
+
class Source:
|
|
45
|
+
"""A symbol whose value, or call result, is attacker-controlled."""
|
|
46
|
+
|
|
47
|
+
symbol: SymbolId
|
|
48
|
+
label: str
|
|
49
|
+
kinds: TaintKind = TaintKind.ALL
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass(frozen=True)
|
|
53
|
+
class Sink:
|
|
54
|
+
"""A callable whose arguments must not carry the given taint kinds. ``positions``
|
|
55
|
+
restricts some kinds to argument positions: a SQL statement is the first argument
|
|
56
|
+
of ``execute``, its parameter tuple is not a statement."""
|
|
57
|
+
|
|
58
|
+
symbol: SymbolId
|
|
59
|
+
kinds: TaintKind
|
|
60
|
+
positions: tuple[tuple[TaintKind, tuple[int, ...]], ...] = ()
|
|
61
|
+
|
|
62
|
+
def kinds_at(self, position: int | None) -> TaintKind:
|
|
63
|
+
"""The kinds that must not reach the argument at ``position`` (``None`` for a
|
|
64
|
+
keyword or starred argument)."""
|
|
65
|
+
|
|
66
|
+
kinds = self.kinds
|
|
67
|
+
for restricted, allowed in self.positions:
|
|
68
|
+
if position is None or position not in allowed:
|
|
69
|
+
kinds &= ~restricted
|
|
70
|
+
return kinds
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass(frozen=True)
|
|
74
|
+
class Sanitizer:
|
|
75
|
+
"""A callable whose result no longer carries the given taint kinds."""
|
|
76
|
+
|
|
77
|
+
symbol: SymbolId
|
|
78
|
+
kinds: TaintKind
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass(frozen=True)
|
|
82
|
+
class EntryPoint:
|
|
83
|
+
"""Functions decorated by ``symbol``, and methods of classes deriving from it,
|
|
84
|
+
receive attacker-controlled parameters."""
|
|
85
|
+
|
|
86
|
+
symbol: SymbolId
|
|
87
|
+
label: str
|
|
88
|
+
kinds: TaintKind = TaintKind.ALL
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclass(frozen=True)
|
|
92
|
+
class TypedParameter:
|
|
93
|
+
"""A parameter annotated with ``symbol`` is attacker-controlled."""
|
|
94
|
+
|
|
95
|
+
symbol: SymbolId
|
|
96
|
+
label: str
|
|
97
|
+
kinds: TaintKind = TaintKind.ALL
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclass(frozen=True)
|
|
101
|
+
class NamedParameter:
|
|
102
|
+
"""Parameters whose name matches ``pattern`` carry ``kinds`` (``password`` is a
|
|
103
|
+
credential wherever it is a parameter)."""
|
|
104
|
+
|
|
105
|
+
pattern: str
|
|
106
|
+
label: str
|
|
107
|
+
kinds: TaintKind
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def symbol(self) -> SymbolId:
|
|
111
|
+
digest = hashlib.sha1(self.pattern.encode("utf-8")).hexdigest()[:12]
|
|
112
|
+
return SymbolId(f"python.parameter.p{digest}")
|
|
113
|
+
|
|
114
|
+
def matches(self, name: str) -> bool:
|
|
115
|
+
return re.search(self.pattern, name) is not None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@dataclass(frozen=True)
|
|
119
|
+
class RouteRegistrar:
|
|
120
|
+
"""A call registering a handler elsewhere (``path('login/', views.log_in)``): the
|
|
121
|
+
function or class referenced by ``argument`` (or ``keyword``) is an entry point."""
|
|
122
|
+
|
|
123
|
+
symbol: SymbolId
|
|
124
|
+
argument: int
|
|
125
|
+
label: str
|
|
126
|
+
kinds: TaintKind = TaintKind.ALL
|
|
127
|
+
keyword: str | None = None
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@dataclass(frozen=True)
|
|
131
|
+
class SuffixSink:
|
|
132
|
+
"""A sink matched by the tail of a call's symbol (``objects.raw`` for any model)."""
|
|
133
|
+
|
|
134
|
+
suffix: str
|
|
135
|
+
kinds: TaintKind
|
|
136
|
+
positions: tuple[tuple[TaintKind, tuple[int, ...]], ...] = ()
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def symbol(self) -> SymbolId:
|
|
140
|
+
return SymbolId(f"python.suffix.{self.suffix.replace('.', '_')}")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@dataclass(frozen=True)
|
|
144
|
+
class Validator:
|
|
145
|
+
"""A callable whose truth proves its ``argument`` safe (refutation evidence, §24)."""
|
|
146
|
+
|
|
147
|
+
symbol: SymbolId
|
|
148
|
+
kinds: TaintKind = TaintKind.ALL
|
|
149
|
+
argument: int = 0
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@dataclass(frozen=True)
|
|
153
|
+
class AuthorizationGuard:
|
|
154
|
+
"""A decorator, or a condition, that restricts who reaches the code behind it; a
|
|
155
|
+
flow behind one is a hotspot rather than a vulnerability (§24)."""
|
|
156
|
+
|
|
157
|
+
symbol: SymbolId
|
|
158
|
+
label: str
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
Model = (
|
|
162
|
+
Source
|
|
163
|
+
| Sink
|
|
164
|
+
| Sanitizer
|
|
165
|
+
| EntryPoint
|
|
166
|
+
| TypedParameter
|
|
167
|
+
| Validator
|
|
168
|
+
| AuthorizationGuard
|
|
169
|
+
| NamedParameter
|
|
170
|
+
| RouteRegistrar
|
|
171
|
+
| SuffixSink
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@dataclass(frozen=True)
|
|
176
|
+
class ModelTable:
|
|
177
|
+
sources: tuple[Source, ...]
|
|
178
|
+
sinks: tuple[Sink, ...]
|
|
179
|
+
sanitizers: tuple[Sanitizer, ...]
|
|
180
|
+
entry_points: tuple[EntryPoint, ...] = ()
|
|
181
|
+
typed_parameters: tuple[TypedParameter, ...] = ()
|
|
182
|
+
validators: tuple[Validator, ...] = ()
|
|
183
|
+
authorizations: tuple[AuthorizationGuard, ...] = ()
|
|
184
|
+
named_parameters: tuple[NamedParameter, ...] = ()
|
|
185
|
+
route_registrars: tuple[RouteRegistrar, ...] = ()
|
|
186
|
+
suffix_sinks: tuple[SuffixSink, ...] = ()
|
|
187
|
+
_by_symbol: dict[type[Model], dict[SymbolId, Model]] = field(
|
|
188
|
+
init=False, repr=False, compare=False
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def __post_init__(self) -> None:
|
|
192
|
+
index: dict[type[Model], dict[SymbolId, Model]] = {
|
|
193
|
+
Source: {m.symbol: m for m in self.sources},
|
|
194
|
+
Sink: {m.symbol: m for m in self.sinks},
|
|
195
|
+
Sanitizer: {m.symbol: m for m in self.sanitizers},
|
|
196
|
+
EntryPoint: {m.symbol: m for m in self.entry_points},
|
|
197
|
+
TypedParameter: {m.symbol: m for m in self.typed_parameters},
|
|
198
|
+
Validator: {m.symbol: m for m in self.validators},
|
|
199
|
+
AuthorizationGuard: {m.symbol: m for m in self.authorizations},
|
|
200
|
+
RouteRegistrar: {m.symbol: m for m in self.route_registrars},
|
|
201
|
+
}
|
|
202
|
+
object.__setattr__(self, "_by_symbol", MappingProxyType(index))
|
|
203
|
+
|
|
204
|
+
def entry_point(self, symbol: SymbolId) -> EntryPoint | None:
|
|
205
|
+
found = self._by_symbol[EntryPoint].get(symbol)
|
|
206
|
+
return found if isinstance(found, EntryPoint) else None
|
|
207
|
+
|
|
208
|
+
def typed_parameter(self, symbol: SymbolId) -> TypedParameter | None:
|
|
209
|
+
found = self._by_symbol[TypedParameter].get(symbol)
|
|
210
|
+
return found if isinstance(found, TypedParameter) else None
|
|
211
|
+
|
|
212
|
+
def validator(self, symbol: SymbolId) -> Validator | None:
|
|
213
|
+
found = self._by_symbol[Validator].get(symbol)
|
|
214
|
+
return found if isinstance(found, Validator) else None
|
|
215
|
+
|
|
216
|
+
def authorization(self, symbol: SymbolId) -> AuthorizationGuard | None:
|
|
217
|
+
found = self._by_symbol[AuthorizationGuard].get(symbol)
|
|
218
|
+
return found if isinstance(found, AuthorizationGuard) else None
|
|
219
|
+
|
|
220
|
+
def source(self, symbol: SymbolId) -> Source | None:
|
|
221
|
+
found = self._by_symbol[Source].get(symbol)
|
|
222
|
+
return found if isinstance(found, Source) else None
|
|
223
|
+
|
|
224
|
+
def source_covering(self, symbol: SymbolId) -> Source | None:
|
|
225
|
+
"""The source registered for ``symbol`` or for the closest symbol above it, so a
|
|
226
|
+
source on ``flask.request.args`` also covers ``flask.request.args.get``."""
|
|
227
|
+
|
|
228
|
+
parts = symbol.canonical_name.split(".")
|
|
229
|
+
for length in range(len(parts), 1, -1):
|
|
230
|
+
found = self.source(SymbolId(".".join(parts[:length])))
|
|
231
|
+
if found is not None:
|
|
232
|
+
return found
|
|
233
|
+
return None
|
|
234
|
+
|
|
235
|
+
def sink(self, symbol: SymbolId) -> Sink | None:
|
|
236
|
+
found = self._by_symbol[Sink].get(symbol)
|
|
237
|
+
if isinstance(found, Sink):
|
|
238
|
+
return found
|
|
239
|
+
for suffix in self.suffix_sinks:
|
|
240
|
+
if symbol.canonical_name.endswith(f".{suffix.suffix}"):
|
|
241
|
+
return Sink(symbol, suffix.kinds, suffix.positions)
|
|
242
|
+
return None
|
|
243
|
+
|
|
244
|
+
def route_registrar(self, symbol: SymbolId) -> RouteRegistrar | None:
|
|
245
|
+
found = self._by_symbol[RouteRegistrar].get(symbol)
|
|
246
|
+
return found if isinstance(found, RouteRegistrar) else None
|
|
247
|
+
|
|
248
|
+
def extended(self, *sinks: Sink) -> ModelTable:
|
|
249
|
+
"""A table with extra sinks; a sink already present gains the new kinds."""
|
|
250
|
+
|
|
251
|
+
merged = {sink.symbol: sink for sink in self.sinks}
|
|
252
|
+
for sink in sinks:
|
|
253
|
+
current = merged.get(sink.symbol)
|
|
254
|
+
merged[sink.symbol] = (
|
|
255
|
+
Sink(sink.symbol, current.kinds | sink.kinds, current.positions + sink.positions)
|
|
256
|
+
if current is not None
|
|
257
|
+
else sink
|
|
258
|
+
)
|
|
259
|
+
return ModelTable(
|
|
260
|
+
self.sources,
|
|
261
|
+
tuple(merged.values()),
|
|
262
|
+
self.sanitizers,
|
|
263
|
+
self.entry_points,
|
|
264
|
+
self.typed_parameters,
|
|
265
|
+
self.validators,
|
|
266
|
+
self.authorizations,
|
|
267
|
+
self.named_parameters,
|
|
268
|
+
self.route_registrars,
|
|
269
|
+
self.suffix_sinks,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
def sanitizer(self, symbol: SymbolId) -> Sanitizer | None:
|
|
273
|
+
found = self._by_symbol[Sanitizer].get(symbol)
|
|
274
|
+
return found if isinstance(found, Sanitizer) else None
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class SecurityModelRegistry:
|
|
278
|
+
"""Mutable collection point for the models plugins register."""
|
|
279
|
+
|
|
280
|
+
def __init__(self) -> None:
|
|
281
|
+
self._models: dict[tuple[type[Model], SymbolId], Model] = {}
|
|
282
|
+
|
|
283
|
+
def register(self, *models: Model) -> None:
|
|
284
|
+
for model in models:
|
|
285
|
+
key = (type(model), model.symbol)
|
|
286
|
+
if key in self._models:
|
|
287
|
+
raise ModelError(
|
|
288
|
+
f"{type(model).__name__.lower()} model for {model.symbol} is already registered"
|
|
289
|
+
)
|
|
290
|
+
self._models[key] = model
|
|
291
|
+
|
|
292
|
+
def freeze(self) -> ModelTable:
|
|
293
|
+
models = list(self._models.values())
|
|
294
|
+
return ModelTable(
|
|
295
|
+
sources=tuple(m for m in models if isinstance(m, Source)),
|
|
296
|
+
sinks=tuple(m for m in models if isinstance(m, Sink)),
|
|
297
|
+
sanitizers=tuple(m for m in models if isinstance(m, Sanitizer)),
|
|
298
|
+
entry_points=tuple(m for m in models if isinstance(m, EntryPoint)),
|
|
299
|
+
typed_parameters=tuple(m for m in models if isinstance(m, TypedParameter)),
|
|
300
|
+
validators=tuple(m for m in models if isinstance(m, Validator)),
|
|
301
|
+
authorizations=tuple(m for m in models if isinstance(m, AuthorizationGuard)),
|
|
302
|
+
named_parameters=tuple(m for m in models if isinstance(m, NamedParameter)),
|
|
303
|
+
route_registrars=tuple(m for m in models if isinstance(m, RouteRegistrar)),
|
|
304
|
+
suffix_sinks=tuple(m for m in models if isinstance(m, SuffixSink)),
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class SecurityModelAnalysis(Analysis[ModelTable]):
|
|
309
|
+
"""The frozen model table, provided by the engine rather than computed."""
|
|
310
|
+
|
|
311
|
+
name: ClassVar[str] = "taint.models"
|
|
312
|
+
|
|
313
|
+
@classmethod
|
|
314
|
+
def compute(cls, ctx: AnalysisContext) -> ModelTable:
|
|
315
|
+
raise MissingInputError(
|
|
316
|
+
f"{cls.name} must be provided to the analysis manager before it is requested"
|
|
317
|
+
)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Entry points registered away from their definition (architecture §16, §25).
|
|
2
|
+
|
|
3
|
+
Django views are plain functions listed in ``urls.py``; Flask and FastAPI applications
|
|
4
|
+
can register handlers programmatically too. A ``RouteRegistrar`` model names the
|
|
5
|
+
registering call and the argument that references the handler. The engine scans every
|
|
6
|
+
module of a project for such calls before analysing and provides the result as the
|
|
7
|
+
``taint.routes`` input, so a registered function, or the methods of a registered class,
|
|
8
|
+
receive attacker-controlled parameters wherever they are defined.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from collections.abc import Iterator, Mapping
|
|
14
|
+
from typing import ClassVar
|
|
15
|
+
|
|
16
|
+
from coretrace_python.analysis import Analysis, AnalysisContext
|
|
17
|
+
from coretrace_python.hir import nodes
|
|
18
|
+
from coretrace_python.hir.visitors import Node, children
|
|
19
|
+
from coretrace_python.interprocedural import project_symbol
|
|
20
|
+
from coretrace_python.semantic.scopes import ScopeTable
|
|
21
|
+
from coretrace_python.semantic.symbols import SymbolId, SymbolTable
|
|
22
|
+
from coretrace_python.taint.models import EntryPoint, ModelTable
|
|
23
|
+
|
|
24
|
+
Routes = Mapping[SymbolId, EntryPoint]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class RegisteredRoutes(Analysis[Routes]):
|
|
28
|
+
"""Project symbols registered as handlers, provided by the engine; empty on its own."""
|
|
29
|
+
|
|
30
|
+
name: ClassVar[str] = "taint.routes"
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def compute(cls, ctx: AnalysisContext) -> Routes:
|
|
34
|
+
return {}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def registered_routes(
|
|
38
|
+
module: nodes.Module, scopes: ScopeTable, symbols: SymbolTable, models: ModelTable
|
|
39
|
+
) -> dict[SymbolId, EntryPoint]:
|
|
40
|
+
"""The handlers this module registers, as project symbols, with the entry point the
|
|
41
|
+
registrar grants them."""
|
|
42
|
+
|
|
43
|
+
scope = scopes.module_scope.id
|
|
44
|
+
defined = {
|
|
45
|
+
s.name for s in module.body if isinstance(s, nodes.Function | nodes.Class)
|
|
46
|
+
}
|
|
47
|
+
found: dict[SymbolId, EntryPoint] = {}
|
|
48
|
+
for call in _calls(module.body):
|
|
49
|
+
callee = symbols.resolve_expression(scope, call.callee)
|
|
50
|
+
registrar = models.route_registrar(callee) if callee is not None else None
|
|
51
|
+
if registrar is None:
|
|
52
|
+
continue
|
|
53
|
+
handler: nodes.Expression | None = None
|
|
54
|
+
if registrar.argument < len(call.arguments):
|
|
55
|
+
handler = call.arguments[registrar.argument]
|
|
56
|
+
elif registrar.keyword is not None:
|
|
57
|
+
handler = next((k.value for k in call.keywords if k.name == registrar.keyword), None)
|
|
58
|
+
if handler is None:
|
|
59
|
+
continue
|
|
60
|
+
target = _handler_symbol(handler, module, symbols, scope, defined)
|
|
61
|
+
if target is not None:
|
|
62
|
+
found.setdefault(target, EntryPoint(registrar.symbol, registrar.label, registrar.kinds))
|
|
63
|
+
return found
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _handler_symbol(
|
|
67
|
+
handler: nodes.Expression,
|
|
68
|
+
module: nodes.Module,
|
|
69
|
+
symbols: SymbolTable,
|
|
70
|
+
scope: object,
|
|
71
|
+
defined: set[str],
|
|
72
|
+
) -> SymbolId | None:
|
|
73
|
+
if isinstance(handler, nodes.Call):
|
|
74
|
+
# ``NoteView.as_view()``: the class is the handler.
|
|
75
|
+
handler = handler.callee
|
|
76
|
+
if isinstance(handler, nodes.Attribute) and handler.name == "as_view":
|
|
77
|
+
handler = handler.value
|
|
78
|
+
symbol = symbols.resolve_expression(scope, handler) # type: ignore[arg-type]
|
|
79
|
+
if symbol is not None:
|
|
80
|
+
return symbol
|
|
81
|
+
if isinstance(handler, nodes.Name) and handler.identifier in defined:
|
|
82
|
+
return project_symbol(module.name, handler.identifier)
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _calls(body: tuple[nodes.Statement, ...]) -> Iterator[nodes.Call]:
|
|
87
|
+
for statement in body:
|
|
88
|
+
if isinstance(statement, nodes.Function | nodes.Class):
|
|
89
|
+
continue
|
|
90
|
+
yield from _calls_in(statement)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _calls_in(node: Node) -> Iterator[nodes.Call]:
|
|
94
|
+
if isinstance(node, nodes.Function | nodes.Class | nodes.Lambda | nodes.Comprehension):
|
|
95
|
+
return
|
|
96
|
+
if isinstance(node, nodes.Call):
|
|
97
|
+
yield node
|
|
98
|
+
for child in children(node):
|
|
99
|
+
yield from _calls_in(child)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: coretrace-python-analyzer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Static security analysis infrastructure for Python code
|
|
5
|
+
Project-URL: Homepage, https://github.com/CoreTrace/coretrace-python-analyzer
|
|
6
|
+
Project-URL: Repository, https://github.com/CoreTrace/coretrace-python-analyzer
|
|
7
|
+
Project-URL: Issues, https://github.com/CoreTrace/coretrace-python-analyzer/issues
|
|
8
|
+
Author: CoreTrace
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
Keywords: python,sast,security,static-analysis,taint
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Security
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
24
|
+
Requires-Dist: mypy>=1.15; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.9; extra == 'dev'
|
|
27
|
+
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# CoreTrace Python Analyzer
|
|
31
|
+
|
|
32
|
+
A standalone static security analyzer for Python. It finds injection vulnerabilities by
|
|
33
|
+
following attacker-controlled data through the program, across functions, files, objects
|
|
34
|
+
and closures, and judges each flow against the guards on its path; it reports dangerous
|
|
35
|
+
API usage, secrets committed in sources and configuration, and vulnerable or forbidden
|
|
36
|
+
dependencies, correlated with the code that reaches them. It runs offline, on a file or a
|
|
37
|
+
whole project, with no runtime dependency.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install coretrace-python-analyzer
|
|
41
|
+
coretrace-python-analyzer --check src/ --format sarif > report.sarif
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- [Usage guide](docs/usage.md): command line, rules, report formats, dependencies and
|
|
45
|
+
advisories, cache and parallelism, continuous integration.
|
|
46
|
+
- [Writing a plugin](docs/plugins.md): models for another framework, detectors for
|
|
47
|
+
another rule, secret patterns and project-wide checks.
|
|
48
|
+
- [Architecture](docs/architecture.md): the engine's design and its migration plan.
|
|
49
|
+
|
|
50
|
+
The pipeline: source manager, parser-independent high-level representation (PyHIR),
|
|
51
|
+
semantic resolution of imports and scopes, lowering to a small intermediate
|
|
52
|
+
representation (PyIR), control-flow graphs, SSA, data-flow and abstract interpretation,
|
|
53
|
+
interprocedural summaries, taint and refutation, then plugins and reporters.
|
|
54
|
+
|
|
55
|
+
## Development
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
python -m venv .venv
|
|
59
|
+
python -m pip install -e ".[dev]"
|
|
60
|
+
python -m mypy
|
|
61
|
+
python -m pytest
|
|
62
|
+
python -m ruff check .
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The non-regression suite analyses the public repositories pinned in
|
|
66
|
+
[`tests/regression/repositories.toml`](tests/regression/repositories.toml) and compares
|
|
67
|
+
findings and coverage with the snapshots in `tests/regression/expected/`. It clones on
|
|
68
|
+
first use, needs the network and runs in its own CI job:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
python -m pytest -m regression
|
|
72
|
+
CORETRACE_REGRESSION_UPDATE=1 python -m pytest -m regression # record an intended change
|
|
73
|
+
```
|
|
74
|
+
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
coretrace_python/__init__.py,sha256=eutxN_wsAP00U-4iZdzViOyOKyUlbDgVeatEdvXDSQ4,75
|
|
2
|
+
coretrace_python/__main__.py,sha256=V8DnYtRboISK2VCKm7DGHLREKvqLbqApyWlKBOs26wU,65
|
|
3
|
+
coretrace_python/cache.py,sha256=CGA-5IpBF60rZc8StfhMRwzGxbG_PSluMyAIRi2AatI,10674
|
|
4
|
+
coretrace_python/cli.py,sha256=jgZMY7-HjZDiN4i2d4qvG_2ryZzUYzM2aEuS_XVm6r4,7966
|
|
5
|
+
coretrace_python/engine.py,sha256=1BYreAq6urpxefoBaQkto8SvaFXQB9EaKpTafttRBEw,25748
|
|
6
|
+
coretrace_python/abstract/__init__.py,sha256=n5FNkV8Z4LmwG0r06KWdLj4N2CPSgAKwY3896tdmRgM,999
|
|
7
|
+
coretrace_python/abstract/constants.py,sha256=z4-e7IzysxzGi58wFFff1MlEoV8l7AZsB9EL-q6b7vY,9071
|
|
8
|
+
coretrace_python/abstract/heap.py,sha256=OaESXFGC0qzyhAr76xrCu4skeDVzZM4wlenQqfMTkdk,9642
|
|
9
|
+
coretrace_python/abstract/ranges.py,sha256=zEl9ee55u3E02tkYzzIvCCud5mYRKIUgZd9h_0-crCM,11547
|
|
10
|
+
coretrace_python/abstract/values.py,sha256=SQmgR8jo7cd8KJFDokejg-cFTjJU1CTBUPYyEvbMg-4,1739
|
|
11
|
+
coretrace_python/analysis/__init__.py,sha256=hE7lDwXOdA05_aSZaERRgMv0C2ev8jjJbz4xvrja4Og,728
|
|
12
|
+
coretrace_python/analysis/manager.py,sha256=suoIrPwimyu1AjF6BJwpqAkJBwe6XxzQu9JwV2TN2aQ,5843
|
|
13
|
+
coretrace_python/analysis/provider.py,sha256=Q_OlEcoLzBAsNdAGWijbj_n3E2Ep5UQ4Z8_skqA5Ui8,2211
|
|
14
|
+
coretrace_python/bundled/dependency/dependency_policy/dependency_policy.py,sha256=_CJYHijv4DTgfdumcCqAVV5_MPWjfZOadxeM5pQdw_k,1845
|
|
15
|
+
coretrace_python/bundled/dependency/dependency_policy/plugin.toml,sha256=4w1TA-UKsa82WTnd1xy4bJuU3_G2RNCAWNICLPcZLMk,210
|
|
16
|
+
coretrace_python/bundled/dependency/reachable_vulnerability/plugin.toml,sha256=LuF9jQqZfplN_GBky69Xjq2pksaX1Fs8PYEir-7-vY8,275
|
|
17
|
+
coretrace_python/bundled/dependency/reachable_vulnerability/reachable_vulnerability.py,sha256=jMNw7-ly4Bhjh3gaUDW7z43HOoQPH9f17M3sZ8HtK2M,2507
|
|
18
|
+
coretrace_python/bundled/dependency/sample_advisories/plugin.toml,sha256=cME4pSFzkFsxmIJGGBSrmXqynAd0dg34X-rgEoZ_u6E,184
|
|
19
|
+
coretrace_python/bundled/dependency/sample_advisories/sample_advisories.py,sha256=uViz4fvg2-u7jFKPtPY2G0yPhr_8Ba09exZc-fcZ2w8,3649
|
|
20
|
+
coretrace_python/bundled/dependency/vulnerable_dependency/plugin.toml,sha256=FbmiXLEqtPUZEsDc5q_UqCzn6AecL5HCSdGVy7_2dy0,238
|
|
21
|
+
coretrace_python/bundled/dependency/vulnerable_dependency/vulnerable_dependency.py,sha256=Mu4pOhNrfxds-qsFr9_DZOAQHaW2QAKxwelQEpm41vU,1871
|
|
22
|
+
coretrace_python/bundled/models/cli/cli_models.py,sha256=BfeXGLbS-3EnzYrJMhZeViQO9ZUZB-EFtxobWj-oW8M,977
|
|
23
|
+
coretrace_python/bundled/models/cli/plugin.toml,sha256=D2gkrL1lWc6b4ME_C0hjzwZHJX1l_OChRs3_oapam_s,163
|
|
24
|
+
coretrace_python/bundled/models/credentials/credential_models.py,sha256=Mw9ty8PDDyLNPtbPTTm-sIY9XE8gBsi02dPmLeum2kE,1423
|
|
25
|
+
coretrace_python/bundled/models/credentials/plugin.toml,sha256=0ut7Jc7IdcvbsZKPu6ty-z3DBlMg2CUT7JX4y4nMybo,217
|
|
26
|
+
coretrace_python/bundled/models/django/django_models.py,sha256=87NCkJ5BKWgF_kXnKLJC_tfsQAjqbhkE4o022_bkrok,5339
|
|
27
|
+
coretrace_python/bundled/models/django/plugin.toml,sha256=_Qa2X_4IViORQkcLvLsAC5vI-2P5CxgG8VvnuNIWcFQ,214
|
|
28
|
+
coretrace_python/bundled/models/fastapi/fastapi_models.py,sha256=K2Edlo1RzYKmAJAIChNVUDc8gorAS48MGEMKNlCIGrI,1251
|
|
29
|
+
coretrace_python/bundled/models/fastapi/plugin.toml,sha256=V_R2WcEc-qkST0tTpL-cRf2FEbjK6Mk727WbJmVpWJM,200
|
|
30
|
+
coretrace_python/bundled/models/flask/flask_models.py,sha256=CVspfwmn56fMg8LlhgZUm351_Zw8d8InNv_UZcoIusg,2171
|
|
31
|
+
coretrace_python/bundled/models/flask/plugin.toml,sha256=kI53Xwf5aZKd2n3fEQEbBzNnOXRvuonqEazTOIXPJP4,192
|
|
32
|
+
coretrace_python/bundled/models/http_clients/http_client_models.py,sha256=TmVIg66zRRQxx3C9RT2XX6xLhemm037hIIBFRSyKzU0,1273
|
|
33
|
+
coretrace_python/bundled/models/http_clients/plugin.toml,sha256=vq9tWHgy8-m8LiU1StGhm9Lsy7vnj3w90P4AKDaKfc0,216
|
|
34
|
+
coretrace_python/bundled/models/python_stdlib/plugin.toml,sha256=DWqjG68rx91HCJi_VEp6tUs4ujkzlR7Lq7saMvtK2HM,187
|
|
35
|
+
coretrace_python/bundled/models/python_stdlib/python_stdlib.py,sha256=y88cIJ5Jfw7qCAgvHsXYu7BmVhhCBv66qk4FN0Moh84,3234
|
|
36
|
+
coretrace_python/bundled/models/sqlalchemy/plugin.toml,sha256=2gRbglnMK5U2QWnzs2U2pDvmTeWmrlW7XpJ_8dRmIoY,182
|
|
37
|
+
coretrace_python/bundled/models/sqlalchemy/sqlalchemy_models.py,sha256=Gm2qjyXUrjzALy-MigUhPQyyDxYdfWlQKDZLp1C6Jqk,1697
|
|
38
|
+
coretrace_python/bundled/secrets/config_secrets/config_secrets.py,sha256=JfhWSyVbjlYD9pQYJN6qAc4Rp4IA8PP222akM4KTPU8,1283
|
|
39
|
+
coretrace_python/bundled/secrets/config_secrets/plugin.toml,sha256=dRkA3zQ9wtT2EJyqZ5zGqJ5KYdyIQtQcSvesqrb4M0Q,177
|
|
40
|
+
coretrace_python/bundled/secrets/hardcoded_secrets/hardcoded_secrets.py,sha256=7TD-Nf5S4yfoRBRmJ6Ab6v4Q2zIC2n79FRfNS3I4xos,544
|
|
41
|
+
coretrace_python/bundled/secrets/hardcoded_secrets/plugin.toml,sha256=bkhRJFUrTFP2LiggDP3PkQpC0REtTq8aWrqlkYzxVHc,231
|
|
42
|
+
coretrace_python/bundled/security/command_injection/command_injection.py,sha256=d8CgmU0tWyhuLk_GTaUQHQaWlKIxC5TDY-K370tdyhE,573
|
|
43
|
+
coretrace_python/bundled/security/command_injection/plugin.toml,sha256=x9NUpwdVZsTQpaPNX3HoYcrZWk4sOGN-aSp9Bc8jvCA,240
|
|
44
|
+
coretrace_python/bundled/security/insecure_deserialization/insecure_deserialization.py,sha256=-4KIQDaYo-09gSceuNEs3eutmBn2OBuYBTqiUEYOatk,637
|
|
45
|
+
coretrace_python/bundled/security/insecure_deserialization/plugin.toml,sha256=5OTVO9jZN-HBid8v__jYkxU-RnKX974Qqu7JQMFdj54,268
|
|
46
|
+
coretrace_python/bundled/security/open_redirect/open_redirect.py,sha256=nUjVIgYhVh_2xBs8_1LOfcLDgQ3g3z1E7APqg2sBdpo,562
|
|
47
|
+
coretrace_python/bundled/security/open_redirect/plugin.toml,sha256=8t4KLNG1DIpjjen6TuKxMjz2jv6GDcwVJDm_hJUalCg,224
|
|
48
|
+
coretrace_python/bundled/security/path_traversal/path_traversal.py,sha256=MiTDZBNU6i3WWua1qaxg1swqDy3wlWwBwG6G4ClyDgw,552
|
|
49
|
+
coretrace_python/bundled/security/path_traversal/plugin.toml,sha256=f0ADZimUvQatOffltF5Ihu1mkzf5rNrsaIpKBg2v39c,228
|
|
50
|
+
coretrace_python/bundled/security/plaintext_credentials/plaintext_credentials.py,sha256=QaE2CXAdl0bi4dE5d2d8KnLJrsAcxUDjR76ghfsnXXo,900
|
|
51
|
+
coretrace_python/bundled/security/plaintext_credentials/plugin.toml,sha256=W56wUdAdf7NNirfQhTdKrn-cCwebqmvkRJg9OVFJUyM,263
|
|
52
|
+
coretrace_python/bundled/security/sql_injection/plugin.toml,sha256=U35h6YdbbM93Ar_msWrwY98_bb6rN-qaa1e7XOtPeSo,224
|
|
53
|
+
coretrace_python/bundled/security/sql_injection/sql_injection.py,sha256=W-ppZngb9mLwRjJPGkh__8kaDqYdSrVbciv0mPdYFNE,545
|
|
54
|
+
coretrace_python/bundled/security/ssrf/plugin.toml,sha256=OySYgL9rGh1f4UuVpEOWdgcyp0vAmaP1m2IJ8Al6Ddc,189
|
|
55
|
+
coretrace_python/bundled/security/ssrf/ssrf.py,sha256=bshcPZMjuQtTR4203CUTxFGZuwIYfsi58rnE5XdqKXc,549
|
|
56
|
+
coretrace_python/bundled/security/xss/plugin.toml,sha256=o6aZWoDNCG6CJ11JDa5lVR0v6NHh-Jg5QpNRxoGSJaw,185
|
|
57
|
+
coretrace_python/bundled/security/xss/xss.py,sha256=hzhoblPMivtwoWZ4v7YyAb15GGisX_imGWgxFzCDeqA,532
|
|
58
|
+
coretrace_python/bundled/syntax/dangerous_eval/dangerous_eval.py,sha256=_ktrigLDf-XTKjWtYX-_wZ9-Gb3G4bCzRhpU0Xj-c1g,723
|
|
59
|
+
coretrace_python/bundled/syntax/dangerous_eval/plugin.toml,sha256=97Eyrcet1jcewAIPa78IKYz9XgiOVsZSJ4vWYdMer2I,200
|
|
60
|
+
coretrace_python/bundled/syntax/flask_debug/flask_debug.py,sha256=28OH3_Im_c_xsMxrjpXmCoBHvLOHQ4DT77dFBAwafbs,2596
|
|
61
|
+
coretrace_python/bundled/syntax/flask_debug/plugin.toml,sha256=bz_6Njz6PAgK-o-yFBWB3U2g2vX6_5cFTfwrkkyQmGA,210
|
|
62
|
+
coretrace_python/bundled/syntax/missing_timeout/missing_timeout.py,sha256=fp_IZDhCdaXR6A5tqvWUA-7jCUxqPpB5zRJH_jnaJQQ,2359
|
|
63
|
+
coretrace_python/bundled/syntax/missing_timeout/plugin.toml,sha256=ZsoxXj_a1RxyhIt8FjwnaWDKvX0xpe8eGEof0WP_BwY,226
|
|
64
|
+
coretrace_python/bundled/syntax/weak_crypto/plugin.toml,sha256=fTAnNZZ7N8-2WVJbmtQ3gJzKfBV5eTUkPfiPzj7R-aM,188
|
|
65
|
+
coretrace_python/bundled/syntax/weak_crypto/weak_crypto.py,sha256=OAOuYR1f4Lc_JxdiHs1wxRRKC4K1kayg5REFIlHK71k,671
|
|
66
|
+
coretrace_python/cfg/__init__.py,sha256=2bJEVjyyVwwciPvxiZuNAOpSVO36yutNRGc-7R54EXw,836
|
|
67
|
+
coretrace_python/cfg/builder.py,sha256=bZdSz2LNDOz-DyQ4wu05s1yxpUCSrgOJZ8hpmcA2YgM,27859
|
|
68
|
+
coretrace_python/cfg/dominance.py,sha256=QpM4-mKVMxe75ZLyqx2_1x-4v5WJd9iDqIdi4C7S7rQ,6602
|
|
69
|
+
coretrace_python/cfg/model.py,sha256=6EJiXFAGrsMgCdyxMJ6TClY8tQhJF6Hq2bX802Gc0yg,5308
|
|
70
|
+
coretrace_python/dataflow/__init__.py,sha256=N5uY8VTNjEk6-ARCgDkxr6uGqQIz2NbF-U9sC_v_lfA,547
|
|
71
|
+
coretrace_python/dataflow/lattice.py,sha256=HgYGVcKVUlexvEc0yT47aQCudLxU_SWLpHhr17igkiE,1929
|
|
72
|
+
coretrace_python/dataflow/solver.py,sha256=iDsW0wujhM2DXplu2JMKC46BRsroXlNETHPEoikPeG4,3475
|
|
73
|
+
coretrace_python/dependency/__init__.py,sha256=JOa2OupSyMe6COiSF9Cah6kcdqYJewFprWi9-E1Je6Q,983
|
|
74
|
+
coretrace_python/dependency/advisories.py,sha256=BDZatgUvxeW8vOLLnGax49gSPBO3yiRlUHcPpaZKeMc,6333
|
|
75
|
+
coretrace_python/dependency/correlation.py,sha256=psRKsca9W8Mr790VfFHIjGiblE0k4onKIW-Y2nlt8I0,3562
|
|
76
|
+
coretrace_python/dependency/graph.py,sha256=LIH8PdBBzpqNsic8tQHQmO8LuTJXEHSDHDGnW0mKjwc,10812
|
|
77
|
+
coretrace_python/dependency/policy.py,sha256=u6nUw2nX-kTuqmw_vooxN8eXZoC31ZMoMaxC9pCcwec,2317
|
|
78
|
+
coretrace_python/dependency/sbom.py,sha256=h4K3Gb9O_D6uZyfpwpC5rPcNjH_Ib-3uvFxix6OKlfs,2520
|
|
79
|
+
coretrace_python/findings/__init__.py,sha256=gnJI-uB2CkgZ8I5aFYP_N5yZb7FGNIy7LirVDh4NLwo,372
|
|
80
|
+
coretrace_python/findings/coverage.py,sha256=U8URLEz6EN4B_TTQlLFCOtEmUbINt7a0Bexb-6OUFlI,1203
|
|
81
|
+
coretrace_python/findings/model.py,sha256=lUfefeq3tyYrTu8lA11JbYcHi_JleqWBL3vh7R89E1c,1147
|
|
82
|
+
coretrace_python/findings/refutation.py,sha256=wL26drcy0JB-qHlRpb4jaYWej209GxTi2tt5SWnfCFw,17465
|
|
83
|
+
coretrace_python/frontend/__init__.py,sha256=ULI2tf_IRTMboaKM6uzTkGGh4Agy3cFjtw2H1IPrz4g,627
|
|
84
|
+
coretrace_python/frontend/ast_adapter.py,sha256=oFILfv3NElabtqA-v4xskb0ztz4_ya_dgErDB3s2Yx4,21661
|
|
85
|
+
coretrace_python/frontend/parser.py,sha256=6-CG7rWxUYeOGeDP206SJWy4BMQUP9Mr6Jf-thaFm0s,669
|
|
86
|
+
coretrace_python/hir/__init__.py,sha256=xMpvj-RSp6bd78a_hhkqbe99-snjERkH-_Lv5o9ASbw,180
|
|
87
|
+
coretrace_python/hir/nodes.py,sha256=xvVJq1QmdjKsrS3nuSO8Uf1nX_1aZAyE6ZdCudi-_KY,11843
|
|
88
|
+
coretrace_python/hir/visitors.py,sha256=JFnX09hK6trLyRcWgZ5ehOG2ywX3VvkqQ1h82nahYNg,885
|
|
89
|
+
coretrace_python/interprocedural/__init__.py,sha256=uWnJK9v_ZCXiA-2Z64nkLuyUg1EOAhnVkJ3WxHZhsVM,1014
|
|
90
|
+
coretrace_python/interprocedural/callgraph.py,sha256=ZtOip87-TgQ_DYLhDiR5Z03VsU0jxUVNgMkEkDuNZ4Q,12380
|
|
91
|
+
coretrace_python/interprocedural/modulegraph.py,sha256=0UIKtxxAfTV7WW4B0xcJgVnD-Z6KRS3hpOTMshj1E_U,8595
|
|
92
|
+
coretrace_python/interprocedural/summaries.py,sha256=BLB6nbWZFIHe54Cj1p64jhOLYm9xc1qvJmpoWQi-clw,17657
|
|
93
|
+
coretrace_python/ir/__init__.py,sha256=ShBPYYqoQFePP-mgBjGezQ2acel0-ReOHF9vCC-G_4Q,232
|
|
94
|
+
coretrace_python/ir/defuse.py,sha256=CZEPnlgntRp4MqwR7kLldd2ZlIlBnr-V9VJAxXxwm0c,2616
|
|
95
|
+
coretrace_python/ir/lowering.py,sha256=1Ctuiq_TWzSuNg5eJe438wQ-bve6toKI4VNQJPLlGXE,25739
|
|
96
|
+
coretrace_python/ir/model.py,sha256=cugasB1E05jLAoQyWkGQHvPMsyDEcyL5tbagKqYqRgU,10520
|
|
97
|
+
coretrace_python/ir/printer.py,sha256=iMwFitjwFIM0gelpZelmzTWefwLdxOc37DlPkywI7is,8800
|
|
98
|
+
coretrace_python/ir/ssa.py,sha256=cIYbcv90PI6AOeMrw2ZWp88fy7E2ZO4P3tqjtPHra7g,11116
|
|
99
|
+
coretrace_python/plugins/__init__.py,sha256=Jh5oLVI_Rc7ZzibsMjJzg69LGeNcRRjLcY5XaVOhjgA,1308
|
|
100
|
+
coretrace_python/plugins/api.py,sha256=y1bicTdPypstWs7aJ4JDIOSVKX-MwFq5NSjGntTZhDw,5309
|
|
101
|
+
coretrace_python/plugins/detectors.py,sha256=RcCSsPpFiq4CTrC0IzXTXEAAWoMQXMAhAARgp182f7g,4781
|
|
102
|
+
coretrace_python/plugins/loader.py,sha256=e7S6l3VhMpku0HpnAl5qbBRFiOlsSf66P7low7RsRvU,3174
|
|
103
|
+
coretrace_python/plugins/manifest.py,sha256=F24pgQSwApRUL6ZihRSLv9wL_M03A_pZjrj9Zi4Ku3Q,3438
|
|
104
|
+
coretrace_python/plugins/registry.py,sha256=ixKcT2YDky96TWCFckdzKnGRmFn1dbBVMSZLPvdxvY8,1177
|
|
105
|
+
coretrace_python/plugins/secrets.py,sha256=SqoejVzHHRKn0vSiWBlmN-VEGXX3QgbcgBQ0zG_hkMk,12494
|
|
106
|
+
coretrace_python/reporters/__init__.py,sha256=MHTEfIj5q1KvFeIm6aAzt4mwL8oCZMkpYlaAGaq_cdo,764
|
|
107
|
+
coretrace_python/reporters/json_format.py,sha256=IvtyN2u3w-fYEtrTZtAJu_7L2NRr29B8IIVJBny9L88,1633
|
|
108
|
+
coretrace_python/reporters/report.py,sha256=V2_MQwtChhU65vyiVSBFi4tXs9YKdEMWD5MxQ3470UY,654
|
|
109
|
+
coretrace_python/reporters/sarif.py,sha256=FOmNX2_QzcEGRFMRwPHMt5ckJKp6UTKEwioOTTdD5tU,2125
|
|
110
|
+
coretrace_python/reporters/text.py,sha256=0X6PZYjYdpNlXnAovkH6g4kWZkcIUcT5-5tycM3RF7I,854
|
|
111
|
+
coretrace_python/semantic/__init__.py,sha256=_tjT9CgXfPbOMs8EFguhWrLeSmpyrqOHU_OSoQPiWYs,411
|
|
112
|
+
coretrace_python/semantic/identity.py,sha256=uQBdqEXrOtYmGIiR9hZu0Pimv52iW1rOOOvIdG0InNY,1472
|
|
113
|
+
coretrace_python/semantic/imports.py,sha256=389MZs8iTUc3CyUHG0VAgWFsypd7VPFKkLHmFz9L-N0,5673
|
|
114
|
+
coretrace_python/semantic/scopes.py,sha256=ZCSu2XRo042BC8Ksj-drMUDIQfpBgcM83x368H2M2kI,19526
|
|
115
|
+
coretrace_python/semantic/symbols.py,sha256=3JptnnX5_KBlSd00L_wcGlYZQdnmBvSBAhfivBF6DLo,3513
|
|
116
|
+
coretrace_python/source/__init__.py,sha256=0Y8fvtbkETnNCJR9Zq7RS5TSgF9c22pz3SSk1KdAXF0,301
|
|
117
|
+
coretrace_python/source/manager.py,sha256=JRmMOcWfS1nocbVrdcvfQTqEfIkmnb5JP857TpGywN4,2736
|
|
118
|
+
coretrace_python/source/model.py,sha256=FZnN5mlir3tzbIpWoxnn6YtRi9UcJ_y0sZM60tKr8U4,1727
|
|
119
|
+
coretrace_python/taint/__init__.py,sha256=D-NH3kx9wKTNeWASewawGAx7ChOkGMGhmjf-E4crHl0,1111
|
|
120
|
+
coretrace_python/taint/engine.py,sha256=NEDJryXqCgc0l8STZ3fSMx-aD-8BO5z8YZLnAgaC7Pw,32452
|
|
121
|
+
coretrace_python/taint/models.py,sha256=s7luO5vMaowxPcWoThkLTEdYuyw0JZZVkaKYW5o_xOI,10930
|
|
122
|
+
coretrace_python/taint/routes.py,sha256=0ICYweRBktlXC0nZYIPi9rxHYEddJXAg_sAc7f_8Ie4,3865
|
|
123
|
+
coretrace_python_analyzer-0.1.0.dist-info/METADATA,sha256=CI39rQWDZ48ltOrKGltLAkYRR-LFzz13stLxCBnP3Nk,3148
|
|
124
|
+
coretrace_python_analyzer-0.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
125
|
+
coretrace_python_analyzer-0.1.0.dist-info/entry_points.txt,sha256=wdozemiraOkbt65g_Y_zgspuZpoLxJdaCVMJt1Ft3c0,72
|
|
126
|
+
coretrace_python_analyzer-0.1.0.dist-info/RECORD,,
|