coretrace-python-analyzer 0.20.0__tar.gz → 0.22.0__tar.gz

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.
Files changed (334) hide show
  1. coretrace_python_analyzer-0.22.0/AUTHORS.md +7 -0
  2. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/CHANGELOG.md +59 -0
  3. coretrace_python_analyzer-0.22.0/CODE_OF_CONDUCT.md +130 -0
  4. coretrace_python_analyzer-0.22.0/CONTRIBUTING.md +17 -0
  5. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/PKG-INFO +10 -1
  6. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/README.md +9 -0
  7. coretrace_python_analyzer-0.22.0/SECURITY.md +15 -0
  8. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/docs/plugins.md +29 -4
  9. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/docs/usage.md +151 -10
  10. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/pyproject.toml +1 -1
  11. coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/analysis.stderr +0 -0
  12. coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/findings.json +5470 -0
  13. coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/rapport.md +260 -0
  14. coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/sbom.json +1486 -0
  15. coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/triage.csv +88 -0
  16. coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/verification.txt +13 -0
  17. coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/vex.json +33 -0
  18. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/__init__.py +1 -1
  19. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/reachable_vulnerability.py +19 -13
  20. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/vulnerable_dependency.py +33 -9
  21. coretrace_python_analyzer-0.22.0/src/coretrace_python/bundled/security/command_injection/command_injection.py +1042 -0
  22. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/command_injection/plugin.toml +1 -1
  23. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cache.py +38 -4
  24. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cli.py +51 -9
  25. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/advisories.py +36 -1
  26. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/correlation.py +151 -13
  27. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/graph.py +71 -34
  28. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/vex.py +5 -2
  29. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/engine.py +38 -7
  30. coretrace_python_analyzer-0.22.0/src/coretrace_python/findings/baseline.py +333 -0
  31. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/model.py +3 -2
  32. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/suppressions.py +11 -3
  33. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/frontend/ast_adapter.py +27 -1
  34. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/frontend/parser.py +3 -0
  35. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/interprocedural/__init__.py +2 -0
  36. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/interprocedural/callgraph.py +131 -5
  37. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/lowering.py +4 -1
  38. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/model.py +8 -0
  39. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/__init__.py +2 -1
  40. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/detectors.py +30 -4
  41. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/secrets.py +231 -36
  42. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/reporters/json_format.py +14 -7
  43. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/reporters/report.py +7 -2
  44. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/reporters/sarif.py +19 -12
  45. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/reporters/text.py +5 -4
  46. coretrace_python_analyzer-0.22.0/src/coretrace_python/source/__init__.py +17 -0
  47. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/source/manager.py +16 -0
  48. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/source/model.py +20 -0
  49. coretrace_python_analyzer-0.22.0/src/coretrace_python/source/positions.py +420 -0
  50. coretrace_python_analyzer-0.22.0/src/coretrace_python/taint/commands.py +45 -0
  51. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/models.py +10 -7
  52. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/full-stack-fastapi-template.json +0 -6
  53. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/healthchecks.json +0 -18
  54. coretrace_python_analyzer-0.22.0/tests/test_argument_present_conditions.py +205 -0
  55. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_baseline.py +4 -3
  56. coretrace_python_analyzer-0.22.0/tests/test_baseline_digests.py +155 -0
  57. coretrace_python_analyzer-0.22.0/tests/test_baseline_key.py +412 -0
  58. coretrace_python_analyzer-0.22.0/tests/test_baseline_schema_1.py +100 -0
  59. coretrace_python_analyzer-0.22.0/tests/test_command_arguments.py +278 -0
  60. coretrace_python_analyzer-0.22.0/tests/test_command_decided_cases.py +48 -0
  61. coretrace_python_analyzer-0.22.0/tests/test_command_injection_nature.py +92 -0
  62. coretrace_python_analyzer-0.22.0/tests/test_config_value_spans.py +67 -0
  63. coretrace_python_analyzer-0.22.0/tests/test_deep_nesting.py +92 -0
  64. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_detectors.py +9 -1
  65. coretrace_python_analyzer-0.22.0/tests/test_entry_point_suffixes.py +259 -0
  66. coretrace_python_analyzer-0.22.0/tests/test_file_locations.py +213 -0
  67. coretrace_python_analyzer-0.22.0/tests/test_folded_secret_literals.py +124 -0
  68. coretrace_python_analyzer-0.22.0/tests/test_line_numbering.py +136 -0
  69. coretrace_python_analyzer-0.22.0/tests/test_lock_dependency_maps.py +86 -0
  70. coretrace_python_analyzer-0.22.0/tests/test_lock_positions.py +108 -0
  71. coretrace_python_analyzer-0.22.0/tests/test_password_hashes.py +73 -0
  72. coretrace_python_analyzer-0.22.0/tests/test_powershell_file_operand.py +47 -0
  73. coretrace_python_analyzer-0.22.0/tests/test_relative_root.py +111 -0
  74. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_release.py +1 -1
  75. coretrace_python_analyzer-0.22.0/tests/test_sarif_injection.py +58 -0
  76. coretrace_python_analyzer-0.22.0/tests/test_sequence_conditions.py +461 -0
  77. coretrace_python_analyzer-0.22.0/tests/test_structured_positions.py +196 -0
  78. coretrace_python_analyzer-0.22.0/tests/test_tar_implementations.py +69 -0
  79. coretrace_python_analyzer-0.22.0/tests/test_url_secret_placeholders.py +66 -0
  80. coretrace_python_analyzer-0.20.0/src/coretrace_python/bundled/security/command_injection/command_injection.py +0 -17
  81. coretrace_python_analyzer-0.20.0/src/coretrace_python/findings/baseline.py +0 -99
  82. coretrace_python_analyzer-0.20.0/src/coretrace_python/source/__init__.py +0 -13
  83. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/.github/workflows/ci.yml +0 -0
  84. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/.github/workflows/release.yml +0 -0
  85. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/.gitignore +0 -0
  86. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/LICENSE +0 -0
  87. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/NOTICE +0 -0
  88. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/docs/architecture.md +0 -0
  89. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/examples/add.py +0 -0
  90. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/examples/canonical_symbols.py +0 -0
  91. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/__main__.py +0 -0
  92. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/__init__.py +0 -0
  93. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/constants.py +0 -0
  94. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/heap.py +0 -0
  95. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/ranges.py +0 -0
  96. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/strings.py +0 -0
  97. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/values.py +0 -0
  98. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/analysis/__init__.py +0 -0
  99. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/analysis/manager.py +0 -0
  100. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/analysis/provider.py +0 -0
  101. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/dependency_policy/dependency_policy.py +0 -0
  102. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/dependency_policy/plugin.toml +0 -0
  103. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/plugin.toml +0 -0
  104. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/sample_advisories/plugin.toml +0 -0
  105. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/sample_advisories/sample_advisories.py +0 -0
  106. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/plugin.toml +0 -0
  107. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/aiohttp/aiohttp_models.py +0 -0
  108. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/aiohttp/plugin.toml +0 -0
  109. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/bottle/bottle_models.py +0 -0
  110. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/bottle/plugin.toml +0 -0
  111. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/cli/cli_models.py +0 -0
  112. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/cli/plugin.toml +0 -0
  113. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/credentials/credential_models.py +0 -0
  114. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/credentials/plugin.toml +0 -0
  115. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/db_drivers/db_driver_models.py +0 -0
  116. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/db_drivers/plugin.toml +0 -0
  117. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/django/django_models.py +0 -0
  118. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/django/plugin.toml +0 -0
  119. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/fastapi/fastapi_models.py +0 -0
  120. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/fastapi/plugin.toml +0 -0
  121. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/flask/flask_models.py +0 -0
  122. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/flask/plugin.toml +0 -0
  123. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/http_clients/http_client_models.py +0 -0
  124. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/http_clients/plugin.toml +0 -0
  125. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/python_stdlib/plugin.toml +0 -0
  126. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/python_stdlib/python_stdlib.py +0 -0
  127. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/sqlalchemy/plugin.toml +0 -0
  128. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/sqlalchemy/sqlalchemy_models.py +0 -0
  129. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/tornado/plugin.toml +0 -0
  130. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/tornado/tornado_models.py +0 -0
  131. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/secrets/config_secrets/config_secrets.py +0 -0
  132. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/secrets/config_secrets/plugin.toml +0 -0
  133. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/hardcoded_secrets.py +0 -0
  134. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/plugin.toml +0 -0
  135. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/code_injection/code_injection.py +0 -0
  136. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/code_injection/plugin.toml +0 -0
  137. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/insecure_deserialization/insecure_deserialization.py +0 -0
  138. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/insecure_deserialization/plugin.toml +0 -0
  139. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/nosql_injection/nosql_injection.py +0 -0
  140. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/nosql_injection/plugin.toml +0 -0
  141. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/open_redirect/open_redirect.py +0 -0
  142. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/open_redirect/plugin.toml +0 -0
  143. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/path_traversal/path_traversal.py +0 -0
  144. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/path_traversal/plugin.toml +0 -0
  145. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/plaintext_credentials/plaintext_credentials.py +0 -0
  146. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/plaintext_credentials/plugin.toml +0 -0
  147. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/sql_injection/plugin.toml +0 -0
  148. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/sql_injection/sql_injection.py +0 -0
  149. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/ssrf/plugin.toml +0 -0
  150. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/ssrf/ssrf.py +0 -0
  151. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/xss/plugin.toml +0 -0
  152. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/xss/xss.py +0 -0
  153. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/dangerous_eval/dangerous_eval.py +0 -0
  154. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/dangerous_eval/plugin.toml +0 -0
  155. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/flask_debug/flask_debug.py +0 -0
  156. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/flask_debug/plugin.toml +0 -0
  157. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/insecure_tempfile.py +0 -0
  158. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/plugin.toml +0 -0
  159. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/insecure_tls/insecure_tls.py +0 -0
  160. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/insecure_tls/plugin.toml +0 -0
  161. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/missing_timeout/missing_timeout.py +0 -0
  162. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/missing_timeout/plugin.toml +0 -0
  163. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/unsafe_archive/plugin.toml +0 -0
  164. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/unsafe_archive/unsafe_archive.py +0 -0
  165. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/unsafe_xml/plugin.toml +0 -0
  166. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/unsafe_xml/unsafe_xml.py +0 -0
  167. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/weak_crypto/plugin.toml +0 -0
  168. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/weak_crypto/weak_crypto.py +0 -0
  169. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/weak_random/plugin.toml +0 -0
  170. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/weak_random/weak_random.py +0 -0
  171. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cfg/__init__.py +0 -0
  172. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cfg/builder.py +0 -0
  173. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cfg/dominance.py +0 -0
  174. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cfg/model.py +0 -0
  175. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dataflow/__init__.py +0 -0
  176. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dataflow/lattice.py +0 -0
  177. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dataflow/solver.py +0 -0
  178. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/__init__.py +0 -0
  179. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/policy.py +0 -0
  180. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/sbom.py +0 -0
  181. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/__init__.py +0 -0
  182. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/coverage.py +0 -0
  183. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/provenance.py +0 -0
  184. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/refutation.py +0 -0
  185. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/frontend/__init__.py +0 -0
  186. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/hir/__init__.py +0 -0
  187. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/hir/nodes.py +0 -0
  188. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/hir/visitors.py +0 -0
  189. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/interprocedural/modulegraph.py +0 -0
  190. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/interprocedural/summaries.py +0 -0
  191. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/__init__.py +0 -0
  192. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/defuse.py +0 -0
  193. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/printer.py +0 -0
  194. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/ssa.py +0 -0
  195. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/api.py +0 -0
  196. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/loader.py +0 -0
  197. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/manifest.py +0 -0
  198. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/registry.py +0 -0
  199. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/reporters/__init__.py +0 -0
  200. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/semantic/__init__.py +0 -0
  201. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/semantic/identity.py +0 -0
  202. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/semantic/imports.py +0 -0
  203. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/semantic/scopes.py +0 -0
  204. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/semantic/symbols.py +0 -0
  205. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/__init__.py +0 -0
  206. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/engine.py +0 -0
  207. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/routes.py +0 -0
  208. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/templates.py +0 -0
  209. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/urls.py +0 -0
  210. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/Chatbot.json +0 -0
  211. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/DjangoGoat.json +0 -0
  212. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/Flask-Image-Editing-Website.json +0 -0
  213. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/InsecureGram.json +0 -0
  214. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/MiniBookApiServer.json +0 -0
  215. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/NPL-IA.json +0 -0
  216. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/Spam-Detection-Project.json +0 -0
  217. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/Vulnerable_fastapi.json +0 -0
  218. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/dvpwa.json +0 -0
  219. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/httpie.json +0 -0
  220. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/luigi.json +0 -0
  221. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/my_gdb.json +0 -0
  222. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/network-topologer.json +0 -0
  223. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/pygoat.json +0 -0
  224. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/uploadbox-cloud-storage-solution.json +0 -0
  225. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/vulnerable-flask.json +0 -0
  226. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/yt-fts.json +0 -0
  227. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/fixtures/vulnerable-flask/README.md +0 -0
  228. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/fixtures/vulnerable-flask/app.py +0 -0
  229. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/fixtures/vulnerable-flask/requirements.txt +0 -0
  230. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/fixtures/vulnerable-flask/vulnerable_services.py +0 -0
  231. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/repositories.toml +0 -0
  232. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_advisory_evidence.py +0 -0
  233. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_advisory_feeds.py +0 -0
  234. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_advisory_url_host.py +0 -0
  235. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_aiohttp_models.py +0 -0
  236. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_analysis_manager.py +0 -0
  237. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_architecture.py +0 -0
  238. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_argument_conditions.py +0 -0
  239. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_attacker_arguments.py +0 -0
  240. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_audit_detectors.py +0 -0
  241. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_base_patterns.py +0 -0
  242. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_block_super.py +0 -0
  243. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_cache.py +0 -0
  244. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_cfg.py +0 -0
  245. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_class_keywords_with_targets.py +0 -0
  246. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_cli.py +0 -0
  247. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_closures.py +0 -0
  248. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_code_injection.py +0 -0
  249. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_config_secrets_coverage.py +0 -0
  250. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_constants.py +0 -0
  251. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_correlation.py +0 -0
  252. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_credential_context.py +0 -0
  253. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_dataflow.py +0 -0
  254. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_declared_entry_points.py +0 -0
  255. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_dependencies.py +0 -0
  256. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_discovery.py +0 -0
  257. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_django_http_clients.py +0 -0
  258. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_django_routes.py +0 -0
  259. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_django_safe_values.py +0 -0
  260. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_docs.py +0 -0
  261. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_dominance.py +0 -0
  262. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_emit_ir.py +0 -0
  263. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_entry_point_aliases.py +0 -0
  264. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_exceptions.py +0 -0
  265. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_factories_match_loop_else.py +0 -0
  266. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_fail_on.py +0 -0
  267. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_fastapi_cli_precision.py +0 -0
  268. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_frameworks.py +0 -0
  269. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_frontend_gaps.py +0 -0
  270. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_function_aliases_api.py +0 -0
  271. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_heap.py +0 -0
  272. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_hex_digests.py +0 -0
  273. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_hir_builder.py +0 -0
  274. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_imports.py +0 -0
  275. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_interprocedural.py +0 -0
  276. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_interprocedural_taint.py +0 -0
  277. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_ir.py +0 -0
  278. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_key_taint.py +0 -0
  279. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_keyword_name_conditions.py +0 -0
  280. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_match_patterns.py +0 -0
  281. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_members.py +0 -0
  282. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_module_identity.py +0 -0
  283. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_module_level.py +0 -0
  284. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_nonlocal_writeback.py +0 -0
  285. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_nosql_injection.py +0 -0
  286. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_open_redirect_destinations.py +0 -0
  287. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_operator_sources.py +0 -0
  288. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_packaging.py +0 -0
  289. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_parallel.py +0 -0
  290. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_parser.py +0 -0
  291. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_plaintext_credentials.py +0 -0
  292. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_plugins.py +0 -0
  293. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_project.py +0 -0
  294. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_project_models.py +0 -0
  295. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_project_validators.py +0 -0
  296. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_provenance.py +0 -0
  297. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_pyir_imports.py +0 -0
  298. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_read_entry_points.py +0 -0
  299. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_real_code_precision.py +0 -0
  300. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_redirect_targets.py +0 -0
  301. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_refutation.py +0 -0
  302. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_refutation_evidence.py +0 -0
  303. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_regression.py +0 -0
  304. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_relative_paths.py +0 -0
  305. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_remaining_limits.py +0 -0
  306. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_reporters.py +0 -0
  307. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_safe_arguments.py +0 -0
  308. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_scale.py +0 -0
  309. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_scopes.py +0 -0
  310. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_secrets_sbom.py +0 -0
  311. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_self_state.py +0 -0
  312. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_settings_scope.py +0 -0
  313. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_source_manager.py +0 -0
  314. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_ssa.py +0 -0
  315. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_ssrf_destinations.py +0 -0
  316. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_ssrf_targets.py +0 -0
  317. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_summary_sanitizers.py +0 -0
  318. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_suppressions.py +0 -0
  319. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_symbol_resolution.py +0 -0
  320. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_symbols.py +0 -0
  321. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_syntactic_rules.py +0 -0
  322. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_syntax_control_flow.py +0 -0
  323. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_syntax_coverage.py +0 -0
  324. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_syntax_expressions.py +0 -0
  325. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_taint.py +0 -0
  326. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_template_context_flows.py +0 -0
  327. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_template_escaping.py +0 -0
  328. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_template_filter_calls.py +0 -0
  329. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_template_filter_overrides.py +0 -0
  330. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_template_request_processor.py +0 -0
  331. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_tornado_bottle_models.py +0 -0
  332. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_unreadable_templates.py +0 -0
  333. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_url_proof.py +0 -0
  334. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_vex.py +0 -0
@@ -0,0 +1,7 @@
1
+ # Authors
2
+
3
+ ## Maintainers
4
+
5
+ - Hugo Payet ([@SizzleUnrlsd](https://github.com/SizzleUnrlsd))
6
+
7
+ Other contributors are credited in this repository's Git history and pull requests.
@@ -1,5 +1,64 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.22.0 (2026-10-08)
4
+
5
+ ### Compatibility and migration
6
+
7
+ - Baselines change format twice in this release, and no baseline is ever converted or rewritten on its own. Without a key, baselines are recorded in schema 3, whose entries hold digests of the text a finding covers instead of that text (#226); with a key, in schema 4, keyed with HMAC-SHA-256 (#235). Schema 1 and 2 files are still read without a key, with exact matching only: an entry identifies a finding on a single line as before, a finding over several lines is reported new, and every run warns on standard error that the file may contain secrets in plain text. While a key is given, only a schema 4 baseline is read: an unkeyed one (schema 1, 2 or 3) stops the check with exit status 2. To migrate, review the findings, then record the baseline explicitly with `--record-baseline` (schema 3, or schema 4 with a key); the old file's secrets remain in the history of a repository that committed it.
8
+ - A keyed baseline needs its key: from the file `--baseline-key-file` names, which must lie outside the analysed directory and be another file than the baseline, or else from `CORETRACE_BASELINE_KEY`; the file comes first. The key is at least 16 bytes, trailing line breaks are not part of it, and an empty variable is an error. Without the key, or with another one, the check stops with exit status 2 and records nothing; recording over a schema 4 baseline without its key is refused too. Rotating the key is an explicit `--record-baseline` under the new key. Generate the key at random (`python -c "import secrets; print(secrets.token_hex(32))"`) and keep it out of the repository: a key a person chooses can be guessed from the baseline (#225).
9
+ - Findings may move or reappear once: dependency and configuration findings of a check given a relative root are now located relative to that root (`uv.lock`, not `proj/uv.lock`) (#212); findings in JSON, TOML and lock files are located at their own line or by a JSON pointer (#222); a vulnerable package pinned in a lock file is located at its own `[[package]]` entry. Baselines recorded before should be recorded again after review.
10
+ - A finding whose line cannot be established has a file location: in the JSON report its `line`, `column`, `end_line` and `end_column` are `null` and a `pointer` field names the value (RFC 6901); its SARIF location has no `region`, the pointer under the location's `properties`; the text report shows `path:` without a line. Inline suppressions apply only to findings at a verified line (#222).
11
+ - `command-injection` severities change: an element of an argument list run without a shell is reported by what the input controls there, `medium` by default, `high` when an option of the program runs it, refuted when a constant prefix keeps it from being an option or an option keeps it as data (#217). The rule id is unchanged; the message of an option injection is titled `Option injection` (#232). Existing suppressions and baselines of the rule keep matching by rule id; baselined findings whose severity changed are still baselined.
12
+ - A file whose syntax is nested more than 200 levels deep (a long chain of `+` or chained calls, which only generated code writes) is reported as a `syntax-error` and not analysed, instead of aborting the whole scan (#234).
13
+ - The cache format changes (14): caches built by an earlier version miss once.
14
+ - Plugin API: `Finding.span` is a `Location`, a `SourceSpan` or a `FileLocation` (#222); `Assessment` gains optional `title` and `metadata` fields (#232). Plugins that read `finding.span.start_line` should check for a `SourceSpan` first.
15
+
16
+ ### Baseline
17
+
18
+ - `--record-baseline` records the current findings as the baseline even when the file exists; the file (the target of a symbolic link) is replaced atomically, keeping its permissions, only once the analysis succeeded and the report is rendered, so the previous baseline stays in place when the check fails (#235).
19
+ - `--baseline-key-file FILE` gives the key of a schema 4 baseline; `CORETRACE_BASELINE_KEY` gives it otherwise. The key never appears in a report, message or file; a `key_check` value in the baseline tells the key apart without revealing it (#235).
20
+ - An entry is recognised by a digest of the text of every line its finding covers: a secret written over several lines, whose first line does not hold it, is new once its body changes (#223, #226). A finding at a file location is recognised by digests of its value and of its pointer, whose keys may themselves be secrets (#222, #226).
21
+ - Line numbers follow one rule everywhere, as Python counts lines (`\n`, `\r\n` or a lone `\r`, never U+2028 or a form feed), so a fingerprint or a suppression never refers to another line (#222).
22
+
23
+ ### Secrets
24
+
25
+ - A string expression whose parts are all constant (`+` of strings, `sep.join` of a list or tuple of strings, an f-string whose parts are all constant) is judged as one value, reported once at the whole expression with the strongest finding of the value and its pieces; `PASSWORD = "Zx81kQpL" + "w0RtY7vB" + …` and `TOKEN = "ghp_" + "…"` are now reported. When the whole value is no secret, its pieces are judged on their own, as before (#231).
26
+ - A `.env`, YAML, INI or properties value that continues past its key's line (an open quote, a trailing backslash, deeper indentation) is located over every line it continues on (#226).
27
+ - Password hashes are no longer reported as hardcoded credentials: modular crypt and PHC strings, bcrypt, Werkzeug's `scrypt:`/`pbkdf2:` and Django's encodings; an identifier followed by text of another shape is still a plaintext password (#214).
28
+ - The `url` pattern no longer reports placeholders (`?token=...`, `<token>`) nor an IP address or `localhost` and a port before `@` (proxy specifications); a password runs to the last `@` before the host. A `SecretPattern` may name a `secret` group, which the placeholder check then judges (#215).
29
+ - In `package-lock.json` and `npm-shrinkwrap.json`, the keys of dependency, `requires` and `bin` maps are package or command names, not credential names (#216).
30
+
31
+ ### Command injection
32
+
33
+ - The command a process starter runs (`subprocess.run`, `call`, `check_call`, `check_output`, `Popen`) is read element by element, with a documented option model for git, ssh, tar, rsync, find, rm, cmd, PowerShell, the shells and the interpreters, wrappers such as sudo, env, xargs and timeout read again with their program's model; the evidence says what the input controls (#217).
34
+ - The finding's `injection` metadata says what the input is when the rule establishes it: `command` (it runs or chooses what runs) or `option` (an option, or the value of an option not established to run it), in the JSON report and as the only `properties` of the SARIF result; it is absent when the kind cannot be established (#232, #236).
35
+ - The script after `pwsh -File` is a file name, however it is spelled (#229). `gtar` is read as GNU tar, `bsdtar` as libarchive's (`-I` names a file of patterns), and a bare `tar`'s `-I`, `--to-command` and `--checkpoint-action` are `high` and kept for review (#230).
36
+
37
+ ### Dependencies
38
+
39
+ - A vulnerable package pinned in `uv.lock` or `poetry.lock` is located at its own entry, and the message states the evidence: `werkzeug 3.1.5, pinned in uv.lock, is in <3.1.6 (required by flask)` (#222). Requirements of `pyproject.toml` are located at their own element or key, or given a file location.
40
+ - `--advisories` and `--policy` paths, and the root itself, are resolved once, so their findings and notes are located relative to the root whatever the working directory (#212).
41
+
42
+ ### Frontend
43
+
44
+ - Syntax nested deeper than the analysis follows is rejected before PyHIR is built, and Python 3.11's parser recursion is a parse error of the file, so the rest of the project is still analysed (#234).
45
+
46
+ ### Documentation
47
+
48
+ - `docs/usage.md` documents keyed baselines, `--record-baseline`, `--baseline-key-file`, file locations and the `injection` metadata; `docs/plugins.md` documents `FileLocation`, `Assessment.title` and `metadata`, and the `secret` group of a `SecretPattern`. Repository governance files (contributing, conduct, authors, security) are added (#204).
49
+
50
+ ## 0.21.0 (2026-09-30)
51
+
52
+ ### Advisories
53
+
54
+ - An `argument` condition may carry `present: true`: the argument being passed at all, whatever its value, is the condition, as a `\r` in `web.Response(reason=…)` needs `reason` given, constant or not. It names the argument by keyword or position as today and excludes `values` and `default`. A call giving the argument — positionally, by keyword, or through a `**` literal with constant keys, folded into the keywords — meets it even when the value is unknown, so attacker input there makes the call exploitable; a call surely not giving it is ruled out (`app:5 python.aiohttp.web.Response(reason absent)`) and a project passing only such calls stays `not_affected`; a call unpacking `*args` or a `**mapping` whose keys are not written leaves it pending review (#195).
55
+ - A curated entry point may declare `suffixes`, for receivers the engine cannot type: `Item.objects.annotate(...)` derives the project's own `python.app.models.Item.objects.annotate`, which the canonical `python.django.db.models.QuerySet.annotate` entry point never matches. A suffix matches any symbol of the project's own modules ending with a dot plus the suffix, on dot boundaries as a `SuffixSink` matches, never another package's symbol; a queryset chain is declared explicitly (`objects.filter.annotate`), and a suffix is at least two dot-separated names. The finding keeps the advisory's symbol as `entry_point` and the derived one as `symbol`; conditions, `attacker_arguments` and the ruled-out evidence of contradicted calls apply through a suffix as through the exact symbol. An exact advisory sink whose symbol a bundled suffix sink also matches (`objects.extra`) now composes its kinds with the suffix sink's instead of shadowing them (#197).
56
+ - An advisory condition of kind `sequence` says the flaw spans two calls on one receiver: the first call leaves state on the object the entry point — the second call — reuses. It names the `method` the first call must be, by canonical name or `.`-suffix, and, optionally, the argument that call must carry (`{"kind": "sequence", "method": "Session.get", "argument": "verify", "values": ["False"], ...}`), so `s = requests.Session(); s.get(url, verify=False); s.get(other)` marks the second `get` reachable with the prior call as evidence (requests CVE-2024-35195). A receiver followed whole — bound once to the result of a call or a `with` and used only to call its methods — with no matching call on every path to the entry call rules it out (`app.fetch:6 python.requests.Session.get(no prior Session.get on the receiver)`), and a project with only such calls stays `not_affected`. A receiver the engine cannot follow (a parameter, a module-level instance, one passed to another function or mutated through an attribute), a matching call only in a branch or textually later, an unpacking that leaves the first call's arguments undecided, or an entry call that itself carries the named argument — its own prior across the iterations of a loop — leaves the condition pending review (#194).
57
+
58
+ ### Plugins
59
+
60
+ - `CallSite.prior_calls` records, for a receiver the engine follows whole, the other external calls on the same receiver (`PriorCall`: symbol, location, arguments, and whether it surely executes before this one), in source order; `CallGraph.prior_calls_at` reads it by location, and `check_conditions` takes it to decide `sequence` conditions. The cache format changes.
61
+
3
62
  ## 0.20.0 (2026-09-30)
4
63
 
5
64
  ### Advisories
@@ -0,0 +1,130 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ This policy applies to the CoreTrace Python Analyzer repository and its community spaces.
4
+
5
+ ## Our Pledge
6
+
7
+ We as members, contributors, and leaders pledge to make participation in our
8
+ community a harassment-free experience for everyone, regardless of age, body
9
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
10
+ identity and expression, level of experience, education, socio-economic status,
11
+ nationality, personal appearance, race, religion, or sexual identity
12
+ and orientation.
13
+
14
+ We pledge to act and interact in ways that contribute to an open, welcoming,
15
+ diverse, inclusive, and healthy community.
16
+
17
+ ## Our Standards
18
+
19
+ Examples of behavior that contributes to a positive environment for our
20
+ community include:
21
+
22
+ * Demonstrating empathy and kindness toward other people
23
+ * Being respectful of differing opinions, viewpoints, and experiences
24
+ * Giving and gracefully accepting constructive feedback
25
+ * Accepting responsibility and apologizing to those affected by our mistakes,
26
+ and learning from the experience
27
+ * Focusing on what is best not just for us as individuals, but for the
28
+ overall community
29
+
30
+ Examples of unacceptable behavior include:
31
+
32
+ * The use of sexualized language or imagery, and sexual attention or
33
+ advances of any kind
34
+ * Trolling, insulting or derogatory comments, and personal or political attacks
35
+ * Public or private harassment
36
+ * Publishing others' private information, such as a physical or email
37
+ address, without their explicit permission
38
+ * Other conduct which could reasonably be considered inappropriate in a
39
+ professional setting
40
+
41
+ ## Enforcement Responsibilities
42
+
43
+ Community leaders are responsible for clarifying and enforcing our standards of
44
+ acceptable behavior and will take appropriate and fair corrective action in
45
+ response to any behavior that they deem inappropriate, threatening, offensive,
46
+ or harmful.
47
+
48
+ Community leaders have the right and responsibility to remove, edit, or reject
49
+ comments, commits, code, wiki edits, issues, and other contributions that are
50
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
51
+ decisions when appropriate.
52
+
53
+ ## Scope
54
+
55
+ This Code of Conduct applies within all community spaces, and also applies when
56
+ an individual is officially representing the community in public spaces.
57
+ Examples of representing our community include using an official e-mail address,
58
+ posting via an official social media account, or acting as an appointed
59
+ representative at an online or offline event.
60
+
61
+ ## Enforcement
62
+
63
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
64
+ reported to the community leaders responsible for enforcement at
65
+ hugo.payet@epitech.eu.
66
+ All complaints will be reviewed and investigated promptly and fairly.
67
+
68
+ All community leaders are obligated to respect the privacy and security of the
69
+ reporter of any incident.
70
+
71
+ ## Enforcement Guidelines
72
+
73
+ Community leaders will follow these Community Impact Guidelines in determining
74
+ the consequences for any action they deem in violation of this Code of Conduct:
75
+
76
+ ### 1. Correction
77
+
78
+ **Community Impact**: Use of inappropriate language or other behavior deemed
79
+ unprofessional or unwelcome in the community.
80
+
81
+ **Consequence**: A private, written warning from community leaders, providing
82
+ clarity around the nature of the violation and an explanation of why the
83
+ behavior was inappropriate. A public apology may be requested.
84
+
85
+ ### 2. Warning
86
+
87
+ **Community Impact**: A violation through a single incident or series
88
+ of actions.
89
+
90
+ **Consequence**: A warning with consequences for continued behavior. No
91
+ interaction with the people involved, including unsolicited interaction with
92
+ those enforcing the Code of Conduct, for a specified period of time. This
93
+ includes avoiding interactions in community spaces as well as external channels
94
+ like social media. Violating these terms may lead to a temporary or
95
+ permanent ban.
96
+
97
+ ### 3. Temporary Ban
98
+
99
+ **Community Impact**: A serious violation of community standards, including
100
+ sustained inappropriate behavior.
101
+
102
+ **Consequence**: A temporary ban from any sort of interaction or public
103
+ communication with the community for a specified period of time. No public or
104
+ private interaction with the people involved, including unsolicited interaction
105
+ with those enforcing the Code of Conduct, is allowed during this period.
106
+ Violating these terms may lead to a permanent ban.
107
+
108
+ ### 4. Permanent Ban
109
+
110
+ **Community Impact**: Demonstrating a pattern of violation of community
111
+ standards, including sustained inappropriate behavior, harassment of an
112
+ individual, or aggression toward or disparagement of classes of individuals.
113
+
114
+ **Consequence**: A permanent ban from any sort of public interaction within
115
+ the community.
116
+
117
+ ## Attribution
118
+
119
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
120
+ version 2.0, available at
121
+ https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
122
+
123
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct
124
+ enforcement ladder](https://github.com/mozilla/diversity).
125
+
126
+ [homepage]: https://www.contributor-covenant.org
127
+
128
+ For answers to common questions about this code of conduct, see the FAQ at
129
+ https://www.contributor-covenant.org/faq. Translations are available at
130
+ https://www.contributor-covenant.org/translations.
@@ -0,0 +1,17 @@
1
+ # Contributing to CoreTrace Python Analyzer
2
+
3
+ ## Local setup
4
+
5
+ Python 3.11 or newer is required. Create a virtual environment and install the development dependencies:
6
+
7
+ ```bash
8
+ python3 -m venv .venv
9
+ .venv/bin/python -m pip install -e '.[dev]'
10
+ .venv/bin/python -m mypy
11
+ .venv/bin/python -m pytest
12
+ .venv/bin/python -m ruff check .
13
+ ```
14
+
15
+ The [README](README.md#development) explains the separate network-dependent regression corpus. Update documentation when changing rules, reports or plugin contracts, and describe the checks you ran in your pull request. Keep changes focused and use an English Conventional Commit subject.
16
+
17
+ Report suspected vulnerabilities through [SECURITY.md](SECURITY.md) rather than a public issue.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: coretrace-python-analyzer
3
- Version: 0.20.0
3
+ Version: 0.22.0
4
4
  Summary: Static security analysis infrastructure for Python code
5
5
  Project-URL: Homepage, https://github.com/CoreTrace/coretrace-python-analyzer
6
6
  Project-URL: Repository, https://github.com/CoreTrace/coretrace-python-analyzer
@@ -53,6 +53,15 @@ semantic resolution of imports and scopes, lowering to a small intermediate
53
53
  representation (PyIR), control-flow graphs, SSA, data-flow and abstract interpretation,
54
54
  interprocedural summaries, taint and refutation, then plugins and reporters.
55
55
 
56
+ ## Repository documents
57
+
58
+ - [CONTRIBUTING.md](CONTRIBUTING.md)
59
+ - [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
60
+ - [AUTHORS.md](AUTHORS.md)
61
+ - [CHANGELOG.md](CHANGELOG.md)
62
+ - [LICENSE](LICENSE)
63
+ - [SECURITY.md](SECURITY.md)
64
+
56
65
  ## Development
57
66
 
58
67
  ```bash
@@ -23,6 +23,15 @@ semantic resolution of imports and scopes, lowering to a small intermediate
23
23
  representation (PyIR), control-flow graphs, SSA, data-flow and abstract interpretation,
24
24
  interprocedural summaries, taint and refutation, then plugins and reporters.
25
25
 
26
+ ## Repository documents
27
+
28
+ - [CONTRIBUTING.md](CONTRIBUTING.md)
29
+ - [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
30
+ - [AUTHORS.md](AUTHORS.md)
31
+ - [CHANGELOG.md](CHANGELOG.md)
32
+ - [LICENSE](LICENSE)
33
+ - [SECURITY.md](SECURITY.md)
34
+
26
35
  ## Development
27
36
 
28
37
  ```bash
@@ -0,0 +1,15 @@
1
+ # Security Policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes target `main` and the latest tagged release, when one exists. Older tags are not maintained. Include the exact tag or commit in a report.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Report privately through [GitHub private vulnerability reporting](https://github.com/CoreTrace/coretrace-python-analyzer/security/advisories/new). Do not publish a suspected vulnerability in an issue or pull request.
10
+
11
+ Include reproduction steps, expected and observed behavior, the affected platform and version, and the possible impact. Remove credentials and other sensitive data from examples.
12
+
13
+ ## Scope
14
+
15
+ CoreTrace Python Analyzer parses and analyzes source trees and dependency metadata. Reports about crafted input, unsafe file access or report generation should include a sanitized sample and the command used.
@@ -127,6 +127,19 @@ judges by its own criteria. The refutation's
127
127
  verdict, which other consumers of the flow such as the advisory correlation read, does
128
128
  not change; a rule reading more analyses declares them in its `requires`.
129
129
 
130
+ A rule that tells cases of its sinks apart by severity too overrides `assess(ctx,
131
+ function, flow, verdict)`, which returns an `Assessment` of the verdict and the
132
+ severity; by default it pairs `judge`'s verdict with the rule's `severity`. A `hotspot`
133
+ verdict lowers the confidence of the finding, never its severity. An `Assessment` may
134
+ also carry a `title` for the finding's message instead of the rule's, and `metadata`
135
+ the finding carries besides the flow's; the rule id never changes, so suppressions and
136
+ baselines keep matching. `command-injection`
137
+ reads there the command a flow reaches (`coretrace_python.taint.commands`): a shell
138
+ string or the program is `high`; an element of an argument list run without a shell is
139
+ an option, `medium` unless a documented option of the program runs a command it chooses.
140
+ It sets the `injection` metadata (`command` or `option`, the latter titled `Option
141
+ injection`) only when it establishes what the input is.
142
+
130
143
  ### Security models: `ModelPlugin`
131
144
 
132
145
  Declares sources, sinks and sanitizers for a library or a framework. A model plugin
@@ -195,8 +208,12 @@ A model plugin may also carry `advisories`, a tuple of `Advisory` values
195
208
  symbols, as the shipped `sample-advisories` plugin does. Requirements matching them are
196
209
  reported, calls to the affected symbols become reachable vulnerabilities and tainted
197
210
  calls become exploitable ones. An advisory's entry points carry `conditions`, of kind
198
- `argument`, `host`, `semantic` or `keyword_name`, and `attacker_arguments`, decided as
199
- the [usage guide](usage.md) describes.
211
+ `argument` (on the value, or with `present` on the argument being passed at all),
212
+ `host`, `semantic`, `keyword_name` or `sequence`, and `attacker_arguments`, decided as
213
+ the [usage guide](usage.md) describes. An entry point may also declare `suffixes`,
214
+ matched against the tail of a derived symbol of the project's own modules on dot
215
+ boundaries, as a `SuffixSink` matches, for receivers the engine cannot type (see the
216
+ usage guide).
200
217
 
201
218
  ### Reclassifying findings: `ProjectPlugin.refine`
202
219
 
@@ -251,6 +268,10 @@ class InternalSecrets(SecretDetector):
251
268
  credential_names: ClassVar[tuple[str, ...]] = (*DEFAULT_CREDENTIAL_NAMES, "acme_key")
252
269
  ```
253
270
 
271
+ A pattern whose regex names a `secret` group (`(?P<secret>...)`) is judged on that group:
272
+ a match whose secret is a placeholder (`...`, `<token>`, `${VAR}`, fewer than four
273
+ characters) is not reported, as with credential names.
274
+
254
275
  `entropy_threshold`, `hex_entropy_threshold` and `minimum_length` tune the high-entropy
255
276
  rule. Findings carry a redacted preview only.
256
277
 
@@ -304,8 +325,12 @@ any analysis result: `SSAAnalysis` (`coretrace_python.ir.ssa`) for the code,
304
325
  ## Findings
305
326
 
306
327
  A `Finding` (`coretrace_python.findings`) has a `rule_id`, a `message`, a `Severity`, a
307
- `Confidence`, a `SourceSpan` (file, start and end line and column), the enclosing
308
- `function` and string `metadata`. Rule ids are lower-case words joined by dashes.
328
+ `Confidence`, a location, the enclosing `function` and string `metadata`. Rule ids are
329
+ lower-case words joined by dashes. The location (`span`) is a `SourceSpan` (file, start
330
+ and end line and column) when the line is established, or a `FileLocation` (file and the
331
+ JSON pointer of a value) for a value of a structured file whose line cannot be: a plugin
332
+ that reads a finding's line checks which it has, and never invents a line for a
333
+ `FileLocation` (`coretrace_python.source.positions` places JSON and TOML values).
309
334
 
310
335
  ## Testing a plugin
311
336
 
@@ -56,6 +56,8 @@ coretrace-python-analyzer [--check | --emit-ir [--ssa]] [options] [path]
56
56
  | `--import-advisories SRC OUT` | Convert an OSV dump into the local advisory file `OUT`, then exit. |
57
57
  | `--fail-on SEVERITY` | Exit with status 1 only when a finding of this severity or above was reported: `info`, `low`, `medium`, `high` or `critical`. Default: any finding. |
58
58
  | `--baseline PATH` | The accepted findings: written on the first run, then only findings not recorded there fail the check. |
59
+ | `--baseline-key-file FILE` | With `--baseline`, the file holding the key of a keyed baseline (schema 4), kept out of the analysed directory; read before `CORETRACE_BASELINE_KEY`. |
60
+ | `--record-baseline` | With `--baseline`, record the current findings as the baseline, replacing the file only once the check succeeded. |
59
61
  | `--emit-ir` | Print the intermediate representation of `path` instead of checking it. |
60
62
  | `--ssa` | With `--emit-ir`, print the static single assignment form. |
61
63
  | `--help` | Show the options and exit. |
@@ -84,7 +86,10 @@ get_asgi_application()` in `asgi.py` or `email = forms.EmailField()` in a form c
84
86
  calls the analyzer sees, and a module-level `os.system(input())` is a finding in `<module>`.
85
87
  A function using syntax outside the supported subset is reported as an
86
88
  `unsupported-syntax` note and the other functions are still analysed; a file Python
87
- itself cannot parse is reported as a `syntax-error`. The coverage line and the JSON
89
+ itself cannot parse is reported as a `syntax-error`, and so is a file whose syntax is
90
+ nested more than 200 levels deep (a chain of hundreds of `+` or chained calls, which only
91
+ generated code writes), which the analyzer does not follow; the other files are still
92
+ analysed. The coverage line and the JSON
88
93
  report's per-file detail tell "no findings" from "nothing analysed".
89
94
 
90
95
  Taint follows values between functions and across files through function summaries,
@@ -115,7 +120,7 @@ variable is not treated that way yet.
115
120
 
116
121
  | Rule | Reached sink |
117
122
  |---|---|
118
- | `command-injection` | Shell or process execution (`os.system`, `subprocess` with a string, …). |
123
+ | `command-injection` | Shell or process execution (`os.system`, `subprocess` with a string, …), judged on what the input controls in the command. A string a shell runs, a string naming the program, the program itself, or an operand the program runs as a command (after the host for `ssh`, the program of `sudo`, `env`, `xargs`, `timeout`…, any argument of a batch file) is `high`. The script an interpreter runs (`bash run.sh`, `python tool.py`, its first operand when no option such as `-c` gives the code), or the module of `python -m`, is `high` and kept for review: execution is possible, and its exploitability depends on the file the input chooses. The arguments after a script or code are the script's own: options of unknown meaning, reported `medium` (a hotspot after an option of the script), refuted behind a constant prefix. Otherwise an element of an argument list run without a shell can only be read as an option: `medium`, or `high` when a documented option of the program runs a command it chooses (`git push --receive-pack=…`, `ssh -o ProxyCommand=…`). A value a documented option takes is judged by what the option does with it, whatever its prefix: run it (`sh -c`, `cmd /c`, `python -c`: `high`), keep it as data (`git commit -m`: refuted). After an option the rule does not know, the finding stays a hotspot to review. A constant prefix that keeps a standalone input from being an option (`f"v{version}"`), or an operand after `--` for a program that honours it, is refuted. Every case keeps the rule id `command-injection`, so suppressions and baselines match whatever the case. When the rule reads the command element by element and establishes what the input is there, the finding's `injection` metadata (in the JSON report, and as the only property of its SARIF result) says so: `command` when the input runs or chooses what runs (a shell string, the program, an operand run as a command, the value of an option that runs it); `option` when it can only reach the program as an option or as the value of an option not established to run it, and the message is then titled `Option injection`. When that cannot be established (an option whose effect is to review, an unknown program or element before the input, a command that is not a list or tuple display, a sink such as `os.system` the rule does not read element by element), the metadata is absent and the title stays `Command injection`. |
119
124
  | `code-injection` | The code `eval` or `exec` runs; the globals and locals passed with it are data. `dangerous-eval` reports every such call, this rule the ones attacker input reaches. |
120
125
  | `sql-injection` | A database statement (`cursor.execute`, SQLAlchemy `text`, Django `raw`, …). Parameters of a parameterised query are not statements. |
121
126
  | `nosql-injection` | A NoSQL query, such as a MongoDB filter, given attacker input that may hold a structure: a JSON body giving `{"$ne": null}` matches any value. The input that may hold a structure is JSON, the raw bodies a `json.loads` decodes, files, WebSocket messages and standard input. Text cannot hold an operator: form fields, query parameters, headers, cookies, URL parameters, the command line, the environment, and an entry-point parameter annotated with scalars (`str`, `int`, `Optional[str]`, `Annotated[str, Query()]`, `list[str]`, …), which FastAPI validates. A Django, REST framework, aiohttp or tornado view reads a request object: its text attributes (`GET`, `POST`, `headers`, `query_params`, `query`, `match_info`, `arguments`, …) and the URL parameters after it are text, its body, files and `data` are not. Limits: a helper function the request is passed to reads it as a whole; the keys of a dict are not followed, so a string concatenated into `$where` is not reported. The analyzer ships no NoSQL sink: model plugins declare them. |
@@ -215,7 +220,8 @@ The comment also works in requirements files, where a line
215
220
  `pyyaml==5.3.1 # coretrace: ignore[vulnerable-dependency]` silences that requirement's
216
221
  finding. Suppressed findings are kept apart: the text report counts them, the JSON report
217
222
  lists them under `suppressed`, the SARIF log marks them as suppressed in source, and
218
- they never affect the exit status.
223
+ they never affect the exit status. A comment only suppresses a finding located at a
224
+ verified line; a finding with a file location (see Reports) is never suppressed this way.
219
225
 
220
226
  ## Adopting the analyzer on an existing code base
221
227
 
@@ -227,12 +233,62 @@ coretrace-python-analyzer --check src/ --baseline coretrace-baseline.json
227
233
 
228
234
  The first run writes the file with every current finding and passes. Later runs set the
229
235
  recorded findings apart and fail only on new ones. A finding is recognised by its file,
230
- its rule, its function and the text of its line, not by its line number, so code inserted
231
- above it does not make it new; a change to the line itself does. Commit the file and
232
- shrink it as findings are fixed: an entry without a matching finding is simply unused.
236
+ its rule, its function and the text of every line it covers, not by its line number, so
237
+ code inserted above it does not make it new; a change to its text does, on any of its
238
+ lines, such as the body of a key written over several lines. Commit the file and shrink
239
+ it as findings are fixed: an entry without a matching finding is simply unused.
233
240
  Baselined findings are counted in the text report, listed under `baselined` in the JSON
234
241
  report and marked `baselineState: unchanged` in the SARIF log, where new results are
235
- marked `new`.
242
+ marked `new`. A finding with a file location is recognised by the JSON pointer of its
243
+ value and its value instead of the text of a line, so a new value at the same place is a
244
+ new finding. Entries hold a digest of that text, value and pointer, never the text
245
+ itself, so no accepted secret is stored in plain text. That does not make the file
246
+ confidential: a digest does not hide a weak secret from whoever guesses it, since a
247
+ guessed password, hashed with its line, can be checked against the file. Treat the
248
+ baseline as a possibly sensitive file, or key it.
249
+
250
+ A keyed baseline does not let candidate values be tested without its key. The key comes
251
+ from the file `--baseline-key-file` names, or else from the `CORETRACE_BASELINE_KEY`
252
+ environment variable, as a CI secret; the file comes first when both are given. The check
253
+ refuses a key file inside the analysed directory, however its path is spelled, or the
254
+ baseline itself; keep it out of the whole repository too, which the check cannot tell
255
+ (a hard link escapes it as well). Generate the key at random, for instance with
256
+ `python -c "import secrets; print(secrets.token_hex(32))"`, and share it as a secret
257
+ (a CI secret, a password manager): a key a person chooses can be guessed from the
258
+ baseline. It is at least 16 bytes long, and trailing line breaks are not part of it, from
259
+ the file or the variable alike; an empty variable is an error, as a CI job whose secret
260
+ is missing passes one. Every process of the check, plugins and `--jobs` workers included,
261
+ can read the variable. With a key, the
262
+ baseline is recorded in schema 4: every digest is an HMAC-SHA-256 under the key, and a
263
+ check value, never the key, tells which key recorded it. The key appears in no report,
264
+ message or file the check writes. A schema 4 baseline needs its key: without it, or
265
+ with another, the check stops with an explicit error, exit status 2, and records
266
+ nothing. Recording over a schema 4 baseline without its key is refused too, rather than
267
+ turning it back into an unkeyed one: delete the file to do that explicitly. Without a
268
+ key, baselines are recorded in schema 3, with the guarantee above.
269
+
270
+ `--record-baseline` records the current findings as the baseline even when the file
271
+ exists, under the key given, if any; the file (the target of a symbolic link) is
272
+ replaced at once, keeping its permissions, only once the analysis succeeded and its
273
+ report is rendered, so the previous baseline stays in place when the check fails. Review the findings
274
+ before recording: they all become accepted. Rotating the key is such a record under the
275
+ new key, once the findings are reviewed; the old key then no longer reads the baseline.
276
+
277
+ Baselines are written in schema 3, or in schema 4 with a key. A file written by an
278
+ earlier version, in schema 1 or 2, is still read and never rewritten, and the check warns
279
+ on standard error, once per run, that it may contain secrets in plain text: its entries
280
+ hold the text of each
281
+ finding's first line. They match exactly as they did a finding on a single line; a
282
+ finding over several lines, whose other lines they do not hold, is reported as new, and
283
+ so is a finding in a JSON, TOML or lock file that a schema 1 entry, recorded with the
284
+ text of its key's first line, cannot identify with certainty. The exit status depends
285
+ on the findings only. Review such a baseline and its new findings, then migrate it
286
+ explicitly with `--record-baseline`, to schema 3, or to schema 4 with a key. While a key
287
+ is given, only a schema 4 baseline is read: an unkeyed one (schema 1, 2 or 3) stops the
288
+ check with an error, so that it cannot stand in for the keyed one; review it, then record
289
+ it in schema 4 with `--record-baseline`. No baseline is ever converted or rewritten
290
+ without `--record-baseline`. The
291
+ old file's secrets remain in the history of a repository that committed it.
236
292
 
237
293
  ## Reports
238
294
 
@@ -247,7 +303,7 @@ the directory of the checked file; a path outside it is printed as it is.
247
303
  ```json
248
304
  {
249
305
  "schema_version": 1,
250
- "tool": {"name": "coretrace-python-analyzer", "version": "0.20.0"},
306
+ "tool": {"name": "coretrace-python-analyzer", "version": "0.22.0"},
251
307
  "root": "/home/me/project",
252
308
  "findings": [
253
309
  {
@@ -267,6 +323,17 @@ the directory of the checked file; a path outside it is printed as it is.
267
323
  }
268
324
  ```
269
325
 
326
+ Lines are counted as Python counts them, by `\n`, `\r\n` or a lone `\r` (never U+2028
327
+ or a form feed), in every report, suppression and baseline. A value of a JSON or TOML
328
+ file, a package of a lock file, or a requirement of `pyproject.toml`, is located at its own line,
329
+ which a separate component establishes from the value's structural path and checks
330
+ against the value. When it cannot (a dotted TOML key, an inline table, a multi-line
331
+ value), the finding gets a file location instead of a guessed line: `line`, `column`,
332
+ `end_line` and `end_column` are `null`, and `pointer` gives the JSON pointer of the value
333
+ in the file (`"/tool/app/api_token"`). The SARIF log gives such a result no `region`,
334
+ with the pointer under the location's `properties`, and the text report shows the file
335
+ alone (`settings.toml: high hardcoded-credential: …`).
336
+
270
337
  `root` is the directory the paths are relative to. A file's `status` is `analysed`,
271
338
  `ambiguous` (analysed, but another file has its module name, see above), `syntax-error`
272
339
  or `unreadable`; only `analysed` files count in `files_analysed`.
@@ -281,7 +348,7 @@ bytes. A single-file check lists no components.
281
348
 
282
349
  ```json
283
350
  "tool": {
284
- "name": "coretrace-python-analyzer", "version": "0.20.0",
351
+ "name": "coretrace-python-analyzer", "version": "0.22.0",
285
352
  "components": [
286
353
  {"kind": "plugin", "name": "curated-advisories", "version": "2026.09.25", "digest": "sha256:…"},
287
354
  {"kind": "advisories", "name": "advisories.json", "digest": "sha256:…"}
@@ -370,6 +437,29 @@ it is reachable, called or not — `request.form['name']`, `for key in request.f
370
437
  `request.form.get('name')` all read it. A function reading it several times is reported
371
438
  once, where it first reads it.
372
439
 
440
+ An entry point may declare `suffixes`, for receivers the engine cannot type. A project
441
+ reaches `python.django.db.models.QuerySet.annotate` through a manager on its own model,
442
+ `Item.objects.annotate(...)`, whose call derives the project's own symbol
443
+ `python.app.models.Item.objects.annotate` — `Item` is a project class, `objects` an
444
+ attribute the engine does not type — so the canonical entry point never matches. A
445
+ suffix matches any symbol of the project's own modules ending with a dot plus the
446
+ suffix:
447
+
448
+ ```json
449
+ {"symbol": "python.django.db.models.QuerySet.annotate", "justification": "…",
450
+ "suffixes": ["objects.annotate", "objects.filter.annotate"]}
451
+ ```
452
+
453
+ A queryset chain is declared explicitly: `Item.objects.filter(...).annotate(...)`
454
+ derives `…objects.filter.annotate`, which only the second suffix matches. A suffix is
455
+ at least two dot-separated names, so a bare method name, matching every project method
456
+ of that name, cannot be declared; another package's symbol, such as
457
+ `other_lib.objects.annotate`, never matches. The finding names the advisory's symbol as
458
+ `entry_point` and the derived one as `symbol`, and the entry point's conditions and
459
+ `attacker_arguments` apply through a suffix as through the exact symbol. A project
460
+ attribute chain genuinely ending with a declared suffix matches too — the vulnerable
461
+ version range and the conditions still gate what is reported.
462
+
373
463
  A filter of Django's own libraries that a project template applies is a call to the
374
464
  function behind it, placed at the template's line: `{{ bio|striptags }}` calls
375
465
  `python.django.template.defaultfilters.striptags`, and so do filters in tag arguments
@@ -471,6 +561,16 @@ a call passing a variable, or unpacking `*args` or `**kwargs`, leaves the condit
471
561
  pending review. A `semantic` condition — the document's tags, the platform, the
472
562
  template's origin — cannot be decided and is always pending review, never dropped.
473
563
 
564
+ An `argument` condition with `"present": true` says the argument being passed at all,
565
+ whatever its value, is the condition, as a `\r` in `web.Response(reason=…)` needs
566
+ `reason` given, constant or not: `{"kind": "argument", "text": "…", "argument":
567
+ "reason", "position": 1, "present": true}`, exclusive with `values` and `default`. A
568
+ call giving the argument — positionally, by keyword, or through a `**` literal with
569
+ constant keys, which is folded into the keywords — meets it even when the value is
570
+ unknown; a call surely not giving it does not reach the vulnerability and is ruled out
571
+ (`(reason absent)`); a call unpacking `*args` or a `**mapping` whose keys the engine
572
+ cannot read leaves it pending review.
573
+
474
574
  A `host` condition says the attacker must choose the host of the URL passed as
475
575
  `argument` (or at `position`), as credentials leaking to the host of a crafted URL
476
576
  need: `{"kind": "host", "text": "…", "argument": "url", "position": 0}`. It is
@@ -514,6 +614,47 @@ Keys passed through a project wrapper stay pending, and `mapping.update(other)`,
514
614
  taint. A literal the function fills after building it (`m = {}; m[alias] = expr`)
515
615
  has keys the literal does not write, so the call is not ruled out.
516
616
 
617
+ A `sequence` condition says the flaw spans two calls on one receiver: a first call
618
+ leaves state on the object, and the entry point — the second call — reuses it, as
619
+ `Session.get(url, verify=False)` disables certificate verification for the pooled
620
+ connection a later `Session.get(other)` on the same session reuses (requests
621
+ CVE-2024-35195). It names the `method` the first call must be, by canonical name or
622
+ `.`-suffix, and, optionally, the argument that call must carry, read as an argument
623
+ condition reads it:
624
+
625
+ ```json
626
+ {
627
+ "kind": "sequence",
628
+ "text": "a prior call on the same session disabled certificate verification",
629
+ "method": "Session.get",
630
+ "argument": "verify",
631
+ "values": ["False"]
632
+ }
633
+ ```
634
+
635
+ The engine follows a receiver bound once in the analysed function to the result of a
636
+ call or a `with` and used only to call its methods. The outcome has three cases:
637
+
638
+ - A prior call on the same receiver, on every path to the entry call, matches the
639
+ method and carries a value in `values` (`default` for an absent argument): the
640
+ condition is met, and the evidence names that call's line.
641
+ - The receiver's whole lifetime is visible and no such prior call can precede — one
642
+ call alone on the receiver, or the two calls on different receivers: the condition
643
+ is contradicted, the call is ruled out
644
+ (`app.fetch:6 python.requests.Session.get(no prior Session.get on the receiver)`)
645
+ and a project with only such calls stays `not_affected`.
646
+ - Otherwise the condition stays pending review: a receiver the engine cannot follow —
647
+ a parameter, a module-level instance, one passed to another function or mutated
648
+ through an attribute such as `s.verify = False` — a prior call whose arguments a
649
+ `*`/`**` unpacking leaves undecided, or a flow reaching the entry point inside a
650
+ callee.
651
+
652
+ Only a prior call on every path to the entry call counts as before it: a matching
653
+ call in a branch that may not run, or a textually later one, leaves the condition
654
+ pending, since a loop may bring it before the entry call. A call that itself carries
655
+ what the condition requires of the first call is never ruled out either: across the
656
+ iterations of a loop it is its own prior.
657
+
517
658
  Every dependency finding records the highest level of evidence established in its
518
659
  `level` metadata: `declared` (the requirement allows a vulnerable version), `imported`
519
660
  (a module of the package is imported somewhere), `reachable` (an entry point or affected
@@ -577,7 +718,7 @@ project's behalf would go unseen. Without a lock file, a package is never
577
718
  `not_affected`. The document's `@id` derives from its statements, so two runs with the
578
719
  same result share it; its `author` is `Unknown Author`, as OpenVEX tools write when they
579
720
  cannot know it. Its `tooling` names the analyzer and each component with its digest
580
- (`coretrace-python-analyzer 0.20.0; curated-advisories 2026.09.25 (sha256:…)`), so the
721
+ (`coretrace-python-analyzer 0.22.0; curated-advisories 2026.09.25 (sha256:…)`), so the
581
722
  `@id` changes with the advisory data a statement was decided with.
582
723
 
583
724
  ## Large projects
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "coretrace-python-analyzer"
7
- version = "0.20.0"
7
+ version = "0.22.0"
8
8
  description = "Static security analysis infrastructure for Python code"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"