codejury 0.10.1__tar.gz → 0.10.2__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 (189) hide show
  1. {codejury-0.10.1 → codejury-0.10.2}/PKG-INFO +13 -13
  2. {codejury-0.10.1 → codejury-0.10.2}/README.md +12 -12
  3. {codejury-0.10.1 → codejury-0.10.2}/codejury/__init__.py +2 -2
  4. {codejury-0.10.1 → codejury-0.10.2}/codejury/agents/__init__.py +1 -1
  5. {codejury-0.10.1 → codejury-0.10.2}/codejury/agents/debate.py +3 -3
  6. {codejury-0.10.1 → codejury-0.10.2}/codejury/agents/mock.py +1 -1
  7. {codejury-0.10.1 → codejury-0.10.2}/codejury/agents/parsing.py +1 -1
  8. {codejury-0.10.1 → codejury-0.10.2}/codejury/agents/refuter.py +3 -3
  9. {codejury-0.10.1 → codejury-0.10.2}/codejury/agents/verifier.py +4 -4
  10. {codejury-0.10.1 → codejury-0.10.2}/codejury/analysis/__init__.py +1 -1
  11. {codejury-0.10.1 → codejury-0.10.2}/codejury/analysis/provenance.py +5 -5
  12. {codejury-0.10.1 → codejury-0.10.2}/codejury/analysis/taint.py +6 -6
  13. {codejury-0.10.1 → codejury-0.10.2}/codejury/assembly.py +1 -1
  14. {codejury-0.10.1 → codejury-0.10.2}/codejury/baseline.py +9 -9
  15. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/business_logic.yaml +1 -1
  16. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/dependency_config.yaml +3 -3
  17. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/excessive_agency.yaml +3 -3
  18. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/input_validation.yaml +6 -6
  19. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/insecure_output_handling.yaml +2 -2
  20. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/prompt_injection.yaml +2 -2
  21. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/secrets.yaml +5 -5
  22. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ag_fixed_enum_safe.yaml +1 -1
  23. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ag_model_confirmed_vuln.yaml +1 -1
  24. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/authn_sha256_checksum_safe.yaml +1 -1
  25. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/deserialize_json_safe.yaml +1 -1
  26. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/deserialize_pickle_vuln.yaml +1 -1
  27. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ioh_json_response_safe.yaml +2 -2
  28. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ioh_output_to_sql_vuln.yaml +1 -1
  29. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/pi_user_content_concat_safe.yaml +1 -1
  30. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/session_secure_cookie_safe.yaml +1 -1
  31. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/sql_constant_concat_safe.yaml +1 -1
  32. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ssrf_constant_url_safe.yaml +1 -1
  33. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/xfile_idor_no_check_vuln.yaml +2 -2
  34. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/xfile_idor_owner_checked_safe.yaml +1 -1
  35. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/xfile_path_sanitized_safe.yaml +2 -2
  36. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/xfile_path_tainted_vuln.yaml +2 -2
  37. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/xss_textcontent_safe.yaml +1 -1
  38. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/suppressions.yaml +1 -1
  39. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/taint.yaml +4 -4
  40. {codejury-0.10.1 → codejury-0.10.2}/codejury/domain/__init__.py +1 -1
  41. {codejury-0.10.1 → codejury-0.10.2}/codejury/domain/artifact.py +1 -1
  42. {codejury-0.10.1 → codejury-0.10.2}/codejury/domain/capability.py +2 -2
  43. {codejury-0.10.1 → codejury-0.10.2}/codejury/domain/context.py +1 -1
  44. {codejury-0.10.1 → codejury-0.10.2}/codejury/domain/observation.py +2 -2
  45. {codejury-0.10.1 → codejury-0.10.2}/codejury/domain/result.py +1 -1
  46. {codejury-0.10.1 → codejury-0.10.2}/codejury/evaluation.py +6 -6
  47. codejury-0.10.2/codejury/infrastructure/__init__.py +4 -0
  48. {codejury-0.10.1 → codejury-0.10.2}/codejury/infrastructure/cache.py +4 -4
  49. codejury-0.10.2/codejury/integrations/__init__.py +1 -0
  50. {codejury-0.10.1 → codejury-0.10.2}/codejury/orchestrators/__init__.py +1 -1
  51. {codejury-0.10.1 → codejury-0.10.2}/codejury/orchestrators/adaptive.py +2 -2
  52. {codejury-0.10.1 → codejury-0.10.2}/codejury/orchestrators/base.py +2 -2
  53. {codejury-0.10.1 → codejury-0.10.2}/codejury/orchestrators/challenge.py +1 -1
  54. {codejury-0.10.1 → codejury-0.10.2}/codejury/orchestrators/debate.py +1 -1
  55. {codejury-0.10.1 → codejury-0.10.2}/codejury/orchestrators/pipeline.py +1 -1
  56. {codejury-0.10.1 → codejury-0.10.2}/codejury/orchestrators/reflexion.py +1 -1
  57. {codejury-0.10.1 → codejury-0.10.2}/codejury/orchestrators/single.py +1 -1
  58. {codejury-0.10.1 → codejury-0.10.2}/codejury/orchestrators/taint_gate.py +3 -3
  59. {codejury-0.10.1 → codejury-0.10.2}/codejury/providers/__init__.py +1 -1
  60. {codejury-0.10.1 → codejury-0.10.2}/codejury/providers/anthropic.py +1 -1
  61. {codejury-0.10.1 → codejury-0.10.2}/codejury/providers/litellm.py +1 -1
  62. {codejury-0.10.1 → codejury-0.10.2}/codejury/providers/mock.py +1 -1
  63. {codejury-0.10.1 → codejury-0.10.2}/codejury/providers/openai.py +1 -1
  64. {codejury-0.10.1 → codejury-0.10.2}/codejury/providers/retry.py +5 -5
  65. {codejury-0.10.1 → codejury-0.10.2}/codejury/reporting.py +4 -4
  66. {codejury-0.10.1 → codejury-0.10.2}/codejury/sources/__init__.py +1 -1
  67. {codejury-0.10.1 → codejury-0.10.2}/codejury/sources/callers.py +6 -6
  68. {codejury-0.10.1 → codejury-0.10.2}/codejury/sources/chunker.py +3 -3
  69. {codejury-0.10.1 → codejury-0.10.2}/codejury/sources/diff.py +6 -6
  70. {codejury-0.10.1 → codejury-0.10.2}/codejury/sources/function.py +5 -5
  71. {codejury-0.10.1 → codejury-0.10.2}/codejury/sources/mock.py +1 -1
  72. {codejury-0.10.1 → codejury-0.10.2}/codejury/sources/repo.py +1 -1
  73. {codejury-0.10.1 → codejury-0.10.2}/codejury/suppression.py +8 -8
  74. {codejury-0.10.1 → codejury-0.10.2}/codejury/tasks/__init__.py +1 -1
  75. {codejury-0.10.1 → codejury-0.10.2}/codejury/tasks/base.py +2 -2
  76. {codejury-0.10.1 → codejury-0.10.2}/codejury.egg-info/PKG-INFO +13 -13
  77. {codejury-0.10.1 → codejury-0.10.2}/pyproject.toml +1 -1
  78. {codejury-0.10.1 → codejury-0.10.2}/tests/test_cache.py +1 -1
  79. {codejury-0.10.1 → codejury-0.10.2}/tests/test_taint.py +2 -2
  80. {codejury-0.10.1 → codejury-0.10.2}/tests/test_taint_gate.py +2 -2
  81. codejury-0.10.1/codejury/infrastructure/__init__.py +0 -4
  82. codejury-0.10.1/codejury/integrations/__init__.py +0 -1
  83. {codejury-0.10.1 → codejury-0.10.2}/LICENSE +0 -0
  84. {codejury-0.10.1 → codejury-0.10.2}/codejury/agents/base.py +0 -0
  85. {codejury-0.10.1 → codejury-0.10.2}/codejury/cli.py +0 -0
  86. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/authentication.yaml +0 -0
  87. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/authorization.yaml +0 -0
  88. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/crypto.yaml +0 -0
  89. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/data_protection.yaml +0 -0
  90. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/error_logging.yaml +0 -0
  91. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/output_encoding.yaml +0 -0
  92. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/capabilities/session.yaml +0 -0
  93. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ag_allowlist_safe.yaml +0 -0
  94. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ag_arbitrary_tool_vuln.yaml +0 -0
  95. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ag_destructive_no_confirm_vuln.yaml +0 -0
  96. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ag_human_approval_safe.yaml +0 -0
  97. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/authn_bcrypt_password.yaml +0 -0
  98. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/authn_jwt_noverify_vuln.yaml +0 -0
  99. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/authn_jwt_verified_safe.yaml +0 -0
  100. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/authn_sha256_password.yaml +0 -0
  101. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/authn_weak_hash_indirect_vuln.yaml +0 -0
  102. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/authz_idor_vuln.yaml +0 -0
  103. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/authz_owner_safe.yaml +0 -0
  104. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/business_logic_price_tamper_vuln.yaml +0 -0
  105. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/business_logic_server_checked_safe.yaml +0 -0
  106. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/cmdi_fixed_argv_safe.yaml +0 -0
  107. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/cmdi_ossystem_vuln.yaml +0 -0
  108. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/cmdi_subprocess_safe.yaml +0 -0
  109. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/crypto_aesgcm_safe.yaml +0 -0
  110. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/crypto_ecb_vuln.yaml +0 -0
  111. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/data_protection_plaintext_pii_vuln.yaml +0 -0
  112. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/data_protection_tokenized_safe.yaml +0 -0
  113. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/dependency_config_tls_verify_off_vuln.yaml +0 -0
  114. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/dependency_config_tls_verify_on_safe.yaml +0 -0
  115. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/error_logging_redacted_safe.yaml +0 -0
  116. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/error_logging_secret_leak_vuln.yaml +0 -0
  117. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ioh_escaped_output_safe.yaml +0 -0
  118. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ioh_exec_output_vuln.yaml +0 -0
  119. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ioh_innerhtml_output_vuln.yaml +0 -0
  120. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ioh_schema_validated_safe.yaml +0 -0
  121. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/literal_eval_safe.yaml +0 -0
  122. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/path_basename_safe.yaml +0 -0
  123. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/path_contained_safe.yaml +0 -0
  124. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/path_traversal_vuln.yaml +0 -0
  125. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/pi_delimited_data_safe.yaml +0 -0
  126. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/pi_format_role_vuln.yaml +0 -0
  127. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/pi_indirect_rag_vuln.yaml +0 -0
  128. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/pi_system_concat_vuln.yaml +0 -0
  129. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/pi_user_role_safe.yaml +0 -0
  130. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/secrets_env_safe.yaml +0 -0
  131. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/secrets_hardcoded_vuln.yaml +0 -0
  132. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/session_fixation_vuln.yaml +0 -0
  133. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/sqli_format_vuln.yaml +0 -0
  134. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/sqli_fstring_query.yaml +0 -0
  135. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/sqli_indirect_var_vuln.yaml +0 -0
  136. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/sqli_parameterized_query.yaml +0 -0
  137. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ssrf_allowlist_safe.yaml +0 -0
  138. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ssrf_substring_allowlist_bypass_vuln.yaml +0 -0
  139. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/ssrf_user_url_vuln.yaml +0 -0
  140. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/xss_innerhtml_constant_safe.yaml +0 -0
  141. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/golden/xss_innerhtml_vuln.yaml +0 -0
  142. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/tasks/audit_diff_debate.yaml +0 -0
  143. {codejury-0.10.1 → codejury-0.10.2}/codejury/data/tasks/quick_scan_single.yaml +0 -0
  144. {codejury-0.10.1 → codejury-0.10.2}/codejury/infrastructure/json_parse.py +0 -0
  145. {codejury-0.10.1 → codejury-0.10.2}/codejury/integrations/github.py +0 -0
  146. {codejury-0.10.1 → codejury-0.10.2}/codejury/providers/base.py +0 -0
  147. {codejury-0.10.1 → codejury-0.10.2}/codejury/providers/openai_format.py +0 -0
  148. {codejury-0.10.1 → codejury-0.10.2}/codejury/resources.py +0 -0
  149. {codejury-0.10.1 → codejury-0.10.2}/codejury/sources/base.py +0 -0
  150. {codejury-0.10.1 → codejury-0.10.2}/codejury/tasks/registry.py +0 -0
  151. {codejury-0.10.1 → codejury-0.10.2}/codejury.egg-info/SOURCES.txt +0 -0
  152. {codejury-0.10.1 → codejury-0.10.2}/codejury.egg-info/dependency_links.txt +0 -0
  153. {codejury-0.10.1 → codejury-0.10.2}/codejury.egg-info/entry_points.txt +0 -0
  154. {codejury-0.10.1 → codejury-0.10.2}/codejury.egg-info/requires.txt +0 -0
  155. {codejury-0.10.1 → codejury-0.10.2}/codejury.egg-info/top_level.txt +0 -0
  156. {codejury-0.10.1 → codejury-0.10.2}/setup.cfg +0 -0
  157. {codejury-0.10.1 → codejury-0.10.2}/tests/test_adaptive.py +0 -0
  158. {codejury-0.10.1 → codejury-0.10.2}/tests/test_anthropic_provider.py +0 -0
  159. {codejury-0.10.1 → codejury-0.10.2}/tests/test_assembly.py +0 -0
  160. {codejury-0.10.1 → codejury-0.10.2}/tests/test_audit_pipeline.py +0 -0
  161. {codejury-0.10.1 → codejury-0.10.2}/tests/test_baseline.py +0 -0
  162. {codejury-0.10.1 → codejury-0.10.2}/tests/test_callers.py +0 -0
  163. {codejury-0.10.1 → codejury-0.10.2}/tests/test_capability.py +0 -0
  164. {codejury-0.10.1 → codejury-0.10.2}/tests/test_challenge.py +0 -0
  165. {codejury-0.10.1 → codejury-0.10.2}/tests/test_cli_audit.py +0 -0
  166. {codejury-0.10.1 → codejury-0.10.2}/tests/test_context.py +0 -0
  167. {codejury-0.10.1 → codejury-0.10.2}/tests/test_debate_agents.py +0 -0
  168. {codejury-0.10.1 → codejury-0.10.2}/tests/test_debate_orchestrator.py +0 -0
  169. {codejury-0.10.1 → codejury-0.10.2}/tests/test_diff_source.py +0 -0
  170. {codejury-0.10.1 → codejury-0.10.2}/tests/test_evaluation.py +0 -0
  171. {codejury-0.10.1 → codejury-0.10.2}/tests/test_function_source.py +0 -0
  172. {codejury-0.10.1 → codejury-0.10.2}/tests/test_integrations.py +0 -0
  173. {codejury-0.10.1 → codejury-0.10.2}/tests/test_json_parse.py +0 -0
  174. {codejury-0.10.1 → codejury-0.10.2}/tests/test_litellm_provider.py +0 -0
  175. {codejury-0.10.1 → codejury-0.10.2}/tests/test_openai_provider.py +0 -0
  176. {codejury-0.10.1 → codejury-0.10.2}/tests/test_orchestrator.py +0 -0
  177. {codejury-0.10.1 → codejury-0.10.2}/tests/test_parsing.py +0 -0
  178. {codejury-0.10.1 → codejury-0.10.2}/tests/test_pipeline_orchestrator.py +0 -0
  179. {codejury-0.10.1 → codejury-0.10.2}/tests/test_provenance.py +0 -0
  180. {codejury-0.10.1 → codejury-0.10.2}/tests/test_reflexion_orchestrator.py +0 -0
  181. {codejury-0.10.1 → codejury-0.10.2}/tests/test_repo_source.py +0 -0
  182. {codejury-0.10.1 → codejury-0.10.2}/tests/test_reporting.py +0 -0
  183. {codejury-0.10.1 → codejury-0.10.2}/tests/test_retry_provider.py +0 -0
  184. {codejury-0.10.1 → codejury-0.10.2}/tests/test_review_fixes.py +0 -0
  185. {codejury-0.10.1 → codejury-0.10.2}/tests/test_sarif.py +0 -0
  186. {codejury-0.10.1 → codejury-0.10.2}/tests/test_suppression.py +0 -0
  187. {codejury-0.10.1 → codejury-0.10.2}/tests/test_taint_crossfile.py +0 -0
  188. {codejury-0.10.1 → codejury-0.10.2}/tests/test_tasks.py +0 -0
  189. {codejury-0.10.1 → codejury-0.10.2}/tests/test_verifier.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codejury
3
- Version: 0.10.1
3
+ Version: 0.10.2
4
4
  Summary: General-purpose Application Security AI audit framework -- five-layer architecture, capabilities as first-class data
5
5
  Author: AISecLabs
6
6
  License-Expression: MIT
@@ -32,22 +32,22 @@ Dynamic: license-file
32
32
 
33
33
  An AI security auditor for code whose knowledge lives in versioned YAML, not in
34
34
  prompts. It reviews a diff or a whole repository against the OWASP ASVS and
35
- reports a verdict per dimension -- both what is **vulnerable** and what is
35
+ reports a verdict per dimension: both what is **vulnerable** and what is
36
36
  **verified safe**.
37
37
 
38
- The name is the core idea: code goes before a "jury" of adversarial roles --
39
- Finder / Challenger / Judge -- that argue and converge on a verdict.
38
+ The name is the core idea: code goes before a "jury" of adversarial roles,
39
+ Finder / Challenger / Judge, that argue and converge on a verdict.
40
40
 
41
41
  Why it is built this way:
42
42
 
43
43
  - **Knowledge is data.** Each OWASP ASVS area (and now OWASP LLM Top 10 areas) is a YAML capability
44
- (safe patterns + anti-patterns, with CWE and examples) -- versioned, reviewable
44
+ (safe patterns + anti-patterns, with CWE and examples), versioned, reviewable
45
45
  in a PR, and editable by non-engineers. The framework core stays small.
46
46
  - **Verdicts, not just alerts.** Every capability yields `SECURE` / `VULNERABLE`
47
47
  / `PARTIAL` / `NOT_PRESENT`, so a report shows what was checked and *passed*,
48
48
  not only what failed.
49
49
  - **Composable.** Four orchestration strategies, four model backends, and
50
- diff / repo inputs are chosen per run -- mix and match.
50
+ diff / repo inputs are chosen per run; mix and match.
51
51
 
52
52
  ## Install
53
53
 
@@ -65,7 +65,7 @@ git diff origin/main... | codejury audit --fail-on high -
65
65
  # Post inline review comments on a GitHub pull request (needs GITHUB_TOKEN)
66
66
  git diff origin/main... | codejury audit --github your-org/your-repo#123 -
67
67
 
68
- # No API key needed -- prove the pipeline runs end to end with mock layers
68
+ # No API key needed: prove the pipeline runs end to end with mock layers
69
69
  codejury dry-run
70
70
 
71
71
  # A real audit: set a key, then review your staged changes
@@ -104,7 +104,7 @@ caller/callee context). It downgrades only on positive proof, so it removes fals
104
104
  positives without dropping real findings.
105
105
 
106
106
  `--orchestrator adaptive` keeps cost down: it runs the single verifier first and
107
- escalates to a full debate only for artifacts worth it -- any VULNERABLE verdict
107
+ escalates to a full debate only for artifacts worth it: any VULNERABLE verdict
108
108
  (verify a flag before reporting) or a low-confidence PARTIAL/UNKNOWN one. Clean,
109
109
  confident files pay a single call; only the rest pay for debate.
110
110
 
@@ -118,7 +118,7 @@ outside C/C++) are dropped by versioned rules in
118
118
 
119
119
  `codejury eval` takes `--dataset <dir>` (golden YAML directory), `--split <name>`
120
120
  (score only cases tagged with that `split:`, e.g. a held-out set), and
121
- `--format {text,json}` -- the JSON report is a stable schema (overall plus
121
+ `--format {text,json}`; the JSON report is a stable schema (overall plus
122
122
  per-capability confusion matrix and precision / recall / F1).
123
123
 
124
124
  Runs are deterministic: providers query at temperature 0, and `audit` / `scan`
@@ -139,7 +139,7 @@ codejury scan ./myrepo --only secrets,input_validation,crypto
139
139
  ## Configuration
140
140
 
141
141
  Provider keys are read from the environment (codejury does **not** auto-load
142
- `.env` -- copy `.env.example` and `source` it):
142
+ `.env`; copy `.env.example` and `source` it):
143
143
 
144
144
  | Variable | Used by |
145
145
  |---|---|
@@ -180,7 +180,7 @@ what `--only` and a task's `capabilities:` accept:
180
180
  `business_logic` · `dependency_config` · `prompt_injection` ·
181
181
  `insecure_output_handling` · `excessive_agency`
182
182
 
183
- To tune for your codebase, edit these files (add patterns / sharpen wording) --
183
+ To tune for your codebase, edit these files (add patterns / sharpen wording);
184
184
  no code change needed.
185
185
 
186
186
  ## Architecture
@@ -210,13 +210,13 @@ independently.
210
210
  can't see whether a value is attacker-controlled. Mitigations that add context
211
211
  but do not fully solve it: `scan --callers` (where this file's functions are
212
212
  called) and `scan --callees` (the called code it delegates to, so a sink in
213
- another file is visible) -- pair them for both directions; `--orchestrator
213
+ another file is visible); pair them for both directions; `--orchestrator
214
214
  challenge` (a recall-safe
215
215
  refutation pass that drops only provably-safe flags); `--only` to scope; or
216
216
  `--orchestrator debate`. Real taint precision still needs data-flow analysis,
217
217
  not model skepticism.
218
218
  - **`scan` cost scales as files x capabilities.** It is a periodic deep audit,
219
- not a quick check -- scope it with `--only`. Day to day, audit the diff.
219
+ not a quick check; scope it with `--only`. Day to day, audit the diff.
220
220
 
221
221
  ## Development
222
222
 
@@ -2,22 +2,22 @@
2
2
 
3
3
  An AI security auditor for code whose knowledge lives in versioned YAML, not in
4
4
  prompts. It reviews a diff or a whole repository against the OWASP ASVS and
5
- reports a verdict per dimension -- both what is **vulnerable** and what is
5
+ reports a verdict per dimension: both what is **vulnerable** and what is
6
6
  **verified safe**.
7
7
 
8
- The name is the core idea: code goes before a "jury" of adversarial roles --
9
- Finder / Challenger / Judge -- that argue and converge on a verdict.
8
+ The name is the core idea: code goes before a "jury" of adversarial roles,
9
+ Finder / Challenger / Judge, that argue and converge on a verdict.
10
10
 
11
11
  Why it is built this way:
12
12
 
13
13
  - **Knowledge is data.** Each OWASP ASVS area (and now OWASP LLM Top 10 areas) is a YAML capability
14
- (safe patterns + anti-patterns, with CWE and examples) -- versioned, reviewable
14
+ (safe patterns + anti-patterns, with CWE and examples), versioned, reviewable
15
15
  in a PR, and editable by non-engineers. The framework core stays small.
16
16
  - **Verdicts, not just alerts.** Every capability yields `SECURE` / `VULNERABLE`
17
17
  / `PARTIAL` / `NOT_PRESENT`, so a report shows what was checked and *passed*,
18
18
  not only what failed.
19
19
  - **Composable.** Four orchestration strategies, four model backends, and
20
- diff / repo inputs are chosen per run -- mix and match.
20
+ diff / repo inputs are chosen per run; mix and match.
21
21
 
22
22
  ## Install
23
23
 
@@ -35,7 +35,7 @@ git diff origin/main... | codejury audit --fail-on high -
35
35
  # Post inline review comments on a GitHub pull request (needs GITHUB_TOKEN)
36
36
  git diff origin/main... | codejury audit --github your-org/your-repo#123 -
37
37
 
38
- # No API key needed -- prove the pipeline runs end to end with mock layers
38
+ # No API key needed: prove the pipeline runs end to end with mock layers
39
39
  codejury dry-run
40
40
 
41
41
  # A real audit: set a key, then review your staged changes
@@ -74,7 +74,7 @@ caller/callee context). It downgrades only on positive proof, so it removes fals
74
74
  positives without dropping real findings.
75
75
 
76
76
  `--orchestrator adaptive` keeps cost down: it runs the single verifier first and
77
- escalates to a full debate only for artifacts worth it -- any VULNERABLE verdict
77
+ escalates to a full debate only for artifacts worth it: any VULNERABLE verdict
78
78
  (verify a flag before reporting) or a low-confidence PARTIAL/UNKNOWN one. Clean,
79
79
  confident files pay a single call; only the rest pay for debate.
80
80
 
@@ -88,7 +88,7 @@ outside C/C++) are dropped by versioned rules in
88
88
 
89
89
  `codejury eval` takes `--dataset <dir>` (golden YAML directory), `--split <name>`
90
90
  (score only cases tagged with that `split:`, e.g. a held-out set), and
91
- `--format {text,json}` -- the JSON report is a stable schema (overall plus
91
+ `--format {text,json}`; the JSON report is a stable schema (overall plus
92
92
  per-capability confusion matrix and precision / recall / F1).
93
93
 
94
94
  Runs are deterministic: providers query at temperature 0, and `audit` / `scan`
@@ -109,7 +109,7 @@ codejury scan ./myrepo --only secrets,input_validation,crypto
109
109
  ## Configuration
110
110
 
111
111
  Provider keys are read from the environment (codejury does **not** auto-load
112
- `.env` -- copy `.env.example` and `source` it):
112
+ `.env`; copy `.env.example` and `source` it):
113
113
 
114
114
  | Variable | Used by |
115
115
  |---|---|
@@ -150,7 +150,7 @@ what `--only` and a task's `capabilities:` accept:
150
150
  `business_logic` · `dependency_config` · `prompt_injection` ·
151
151
  `insecure_output_handling` · `excessive_agency`
152
152
 
153
- To tune for your codebase, edit these files (add patterns / sharpen wording) --
153
+ To tune for your codebase, edit these files (add patterns / sharpen wording);
154
154
  no code change needed.
155
155
 
156
156
  ## Architecture
@@ -180,13 +180,13 @@ independently.
180
180
  can't see whether a value is attacker-controlled. Mitigations that add context
181
181
  but do not fully solve it: `scan --callers` (where this file's functions are
182
182
  called) and `scan --callees` (the called code it delegates to, so a sink in
183
- another file is visible) -- pair them for both directions; `--orchestrator
183
+ another file is visible); pair them for both directions; `--orchestrator
184
184
  challenge` (a recall-safe
185
185
  refutation pass that drops only provably-safe flags); `--only` to scope; or
186
186
  `--orchestrator debate`. Real taint precision still needs data-flow analysis,
187
187
  not model skepticism.
188
188
  - **`scan` cost scales as files x capabilities.** It is a periodic deep audit,
189
- not a quick check -- scope it with `--only`. Day to day, audit the diff.
189
+ not a quick check; scope it with `--only`. Day to day, audit the diff.
190
190
 
191
191
  ## Development
192
192
 
@@ -1,6 +1,6 @@
1
- """codejury -- a general-purpose Application Security AI audit framework.
1
+ """codejury: a general-purpose Application Security AI audit framework.
2
2
 
3
- Five layers: Task / (Capability + Orchestrator + Source + Agent) / Provider / Infrastructure.
3
+ Five layers: Task, then Capability plus Orchestrator plus Source plus Agent, then Provider, then Infrastructure.
4
4
  Domain knowledge lives in YAML capability files as a first-class citizen,
5
5
  aligned with OWASP ASVS.
6
6
  """
@@ -1,4 +1,4 @@
1
- """codejury.agents -- the audit roles (finder / challenger / judge / verifier).
1
+ """codejury.agents: the audit roles (finder / challenger / judge / verifier).
2
2
 
3
3
  An agent reads an AnalysisContext and emits observations. It talks to a model
4
4
  only through a Provider, never a vendor SDK, so the role logic stays independent
@@ -35,8 +35,8 @@ _FINDING_SHAPE = (
35
35
 
36
36
  _DEEP_LENS = (
37
37
  "Look past surface patterns for the deepest flaw:\n"
38
- "- Trust anchors: what does this code trust to authenticate or authorize -- a key, token, header, "
39
- "signature, role, or caller -- and who controls that value? If the attacker supplies what is used to "
38
+ "- Trust anchors: what does this code trust to authenticate or authorize, such as a key, token, header, "
39
+ "signature, role, or caller, and who controls that value? If the attacker supplies what is used to "
40
40
  "verify them (e.g. their own public key, an unconfigured key that disables verification), passing the "
41
41
  "check proves nothing.\n"
42
42
  "- Order of operations: is an external, irreversible, or privileged action performed before the local "
@@ -101,7 +101,7 @@ class ChallengerAgent(_DebateAgent):
101
101
  def run(self, ctx: AnalysisContext) -> list[Observation]:
102
102
  parts = [
103
103
  "Challenge the findings below. For each one you believe is a false positive, write a rebuttal. "
104
- "Add new_findings for any real issue that was missed -- especially a deeper flaw the finder "
104
+ "Add new_findings for any real issue that was missed, especially a deeper flaw the finder "
105
105
  "stopped short of.",
106
106
  _DEEP_LENS,
107
107
  _code(ctx.artifact),
@@ -1,4 +1,4 @@
1
- """MockAgent -- a minimal Agent for the dry-run and tests.
1
+ """MockAgent: a minimal Agent for the dry-run and tests.
2
2
 
3
3
  It really calls the provider (so the dry-run exercises the agent -> provider
4
4
  path), then emits one Verdict per in-scope capability, parking the model's reply
@@ -1,7 +1,7 @@
1
1
  """Shared coercion from loosely-typed model JSON into domain values.
2
2
 
3
3
  Agents parse model output that may omit, mistype, or invent fields. These
4
- helpers coerce defensively -- they never raise on bad input, they fall back.
4
+ helpers coerce defensively: they never raise on bad input, they fall back.
5
5
  """
6
6
 
7
7
  import math
@@ -1,8 +1,8 @@
1
- """RefuterAgent -- a skeptic that tries to dismiss flagged verdicts as false positives.
1
+ """RefuterAgent: a skeptic that tries to dismiss flagged verdicts as false positives.
2
2
 
3
3
  Used by the challenge orchestrator: the verifier flags issues, then the refuter
4
4
  gets the code plus the VULNERABLE verdicts (via ``ctx.history``) and argues which
5
- are false positives -- e.g. a value that is not actually attacker-controlled or a
5
+ are false positives, e.g. a value that is not actually attacker-controlled or a
6
6
  sink that is not reachable. It returns a Concession per verdict it refutes.
7
7
 
8
8
  This is the cheap, focused alternative to a full debate: only flagged verdicts
@@ -53,7 +53,7 @@ class RefuterAgent(Agent):
53
53
  "is not attacker-controlled: a stored data field, or traced (here or in the call sites) to "
54
54
  "a trusted, config, or operator-supplied source. If its origin is not shown or could "
55
55
  "plausibly be external input, do NOT refute. For other issue types (hardcoded secrets, "
56
- "weak crypto, ...), a literal value is often the vulnerability itself -- do NOT refute "
56
+ "weak crypto, ...), a literal value is often the vulnerability itself; do NOT refute "
57
57
  "those just because a value is constant.\n\n"
58
58
  "Respond with a single JSON object exactly like:\n" + _JSON_SHAPE
59
59
  )
@@ -1,9 +1,9 @@
1
- """VerifierAgent -- check code against a capability's correct/anti patterns.
1
+ """VerifierAgent: check code against a capability's correct/anti patterns.
2
2
 
3
3
  It renders the capability into a prompt, calls the provider once per capability,
4
4
  and parses the JSON reply into Verdicts. It asks for one verdict per
5
5
  sub_capability including SECURE / NOT_PRESENT, so a report can say what was
6
- checked and what passed -- not only what failed.
6
+ checked and what passed, not only what failed.
7
7
 
8
8
  Parsing is defensive: a missing or malformed reply yields no verdicts rather
9
9
  than raising, and unknown status values fall back to UNKNOWN.
@@ -75,7 +75,7 @@ def _render_capability(cap: Capability) -> str:
75
75
  def _build_prompt(path: str, content: str, cap: Capability, context: str = "") -> str:
76
76
  sub_names = ", ".join(cap.sub_capabilities) or "(none)"
77
77
  context_block = (
78
- f"Related code (call sites / usages elsewhere -- for tracing where values come from, "
78
+ f"Related code (call sites / usages elsewhere, for tracing where values come from, "
79
79
  f"NOT under review):\n```\n{context}\n```\n\n"
80
80
  if context
81
81
  else ""
@@ -90,7 +90,7 @@ def _build_prompt(path: str, content: str, cap: Capability, context: str = "") -
90
90
  "For input-driven issues (injection, path traversal, SSRF), mark VULNERABLE only when "
91
91
  "untrusted/external input could plausibly reach the sink in the code shown. A constant, "
92
92
  "a stored data field, a value from trusted config, or a path or argument the operator "
93
- "supplies (e.g. a CLI argument) is not attacker-controlled -- do not flag it.\n\n"
93
+ "supplies (e.g. a CLI argument) is not attacker-controlled; do not flag it.\n\n"
94
94
  "Respond with a single JSON object exactly like:\n" + _JSON_SHAPE
95
95
  )
96
96
 
@@ -1,6 +1,6 @@
1
1
  """Static analysis for provenance (P1).
2
2
 
3
- The code-graph / data-flow engine that gives the verifier provenance -- whether a
3
+ The code-graph / data-flow engine that gives the verifier provenance: whether a
4
4
  value reaching a sink is attacker-controlled, sanitized, or a trusted constant.
5
5
  This is the real fix for the taint precision floor that single-file LLM review
6
6
  cannot reach (see ROADMAP P1). Python / AST based to start.
@@ -8,7 +8,7 @@ and literals a value derives from.
8
8
  The analysis is deliberately conservative and flow-insensitive: a name assigned
9
9
  more than once contributes the union of all its right-hand sides, so a possible
10
10
  source is never dropped (recall over precision). A value built only from literals
11
- is reported as ``is_constant`` -- the signal that distinguishes, for example,
11
+ is reported as ``is_constant``, the signal that distinguishes, for example,
12
12
  SQL concatenated from constants (safe) from SQL concatenated from a parameter.
13
13
 
14
14
  This module finds where a value comes from; it does not decide what is a source
@@ -43,7 +43,7 @@ class Origin:
43
43
 
44
44
  @property
45
45
  def is_constant(self) -> bool:
46
- """True when the value is built only from literals -- no param, call, attr,
46
+ """True when the value is built only from literals: no param, call, attr,
47
47
  free name, or unmodelled expression contributes."""
48
48
  return not (self.params or self.calls or self.attrs or self.globals_ or self.unknown)
49
49
 
@@ -65,7 +65,7 @@ def parse_function(source: str, name: str) -> ast.FunctionDef | ast.AsyncFunctio
65
65
 
66
66
 
67
67
  def find_calls(scope: ast.AST, callee: str) -> list[ast.Call]:
68
- """Every call within ``scope`` whose function is named ``callee`` -- matching a
68
+ """Every call within ``scope`` whose function is named ``callee``, matching a
69
69
  bare name (``open``) or the final attribute (``execute`` in ``cur.execute``)."""
70
70
  return [node for node in ast.walk(scope) if isinstance(node, ast.Call) and _call_name(node) == callee]
71
71
 
@@ -97,7 +97,7 @@ def trace_value(func: ast.FunctionDef | ast.AsyncFunctionDef, expr: ast.AST) ->
97
97
  on_param=lambda n: Origin(params=frozenset({n})),
98
98
  on_global=lambda n: Origin(globals_=frozenset({n})),
99
99
  on_constant=lambda: _LITERAL,
100
- on_cycle=Origin, # assignment cycle -- no new information
100
+ on_cycle=Origin, # assignment cycle, no new information
101
101
  )
102
102
 
103
103
 
@@ -182,7 +182,7 @@ def reduce_value(
182
182
  if isinstance(expr, (ast.List, ast.Tuple, ast.Set)):
183
183
  return combine([recurse(e) for e in expr.elts])
184
184
  if isinstance(expr, ast.Name):
185
- if expr.id in seen: # assignment cycle -- stop
185
+ if expr.id in seen: # assignment cycle, stop
186
186
  return on_cycle()
187
187
  if expr.id in params:
188
188
  return on_param(expr.id)
@@ -6,7 +6,7 @@ sanitizer makes it SANITIZED (taint stops), a propagator carries taint through t
6
6
  the result, and a trusted origin or a literal is clean.
7
7
 
8
8
  The point is to let a later layer (P1-04) downgrade a taint finding only when the
9
- value is *provably* not attacker-controlled -- ``classification in SAFE`` -- so
9
+ value is *provably* not attacker-controlled (``classification in SAFE``), so
10
10
  recall is preserved: anything uncertain is UNKNOWN or PARAM, never quietly safe.
11
11
 
12
12
  Two documented precision leans: a bare module-global name (e.g. ``STATIC_DIR``)
@@ -42,7 +42,7 @@ from codejury.resources import TAINT_FILE
42
42
 
43
43
  class Taint(str, Enum):
44
44
  EXTERNAL = "external" # derives from an attacker source, not sanitized
45
- UNKNOWN = "unknown" # an unknown call / access -- cannot prove either way
45
+ UNKNOWN = "unknown" # an unknown call / access; cannot prove either way
46
46
  PARAM = "param" # depends on a parameter; resolve at the call site (cross-file)
47
47
  SANITIZED = "sanitized" # had an external component, but a sanitizer neutralized it
48
48
  TRUSTED = "trusted" # operator/config/global origin
@@ -131,14 +131,14 @@ def taint_of(
131
131
  return Taint.TRUSTED
132
132
  if _callee_in(node, vocab.propagators) or _callee_in(node, vocab.safe_sinks):
133
133
  return _combine([recurse(a) for a in node.args])
134
- return Taint.UNKNOWN # unknown call -- a cross-file hop may resolve it later
134
+ return Taint.UNKNOWN # unknown call; a cross-file hop may resolve it later
135
135
  if isinstance(node, (ast.Attribute, ast.Subscript)):
136
136
  path = access_path(node)
137
137
  if path and _access_in(path, vocab.sources):
138
138
  return Taint.EXTERNAL
139
139
  if path and _access_in(path, vocab.trusted):
140
140
  return Taint.TRUSTED
141
- if access_root(node) in params: # attribute of a parameter -- resolve at the call site
141
+ if access_root(node) in params: # attribute of a parameter; resolve at the call site
142
142
  return on_param(access_root(node))
143
143
  return Taint.UNKNOWN # unknown object attribute (e.g. self.x): not provably safe
144
144
  return Taint.UNKNOWN
@@ -150,7 +150,7 @@ def taint_of(
150
150
  combine=_combine,
151
151
  leaf=leaf,
152
152
  on_param=on_param,
153
- on_global=lambda n: Taint.TRUSTED, # free module global / builtin -- conventionally a constant
153
+ on_global=lambda n: Taint.TRUSTED, # free module global / builtin; conventionally a constant
154
154
  on_constant=lambda: Taint.CONSTANT,
155
155
  on_cycle=lambda: Taint.CONSTANT, # assignment cycle: no new information
156
156
  )
@@ -261,7 +261,7 @@ def worst_sink_taint(content: str, files: dict[str, str], vocab: TaintVocab) ->
261
261
  A "potential sink" is any call that is not a safe sink, sanitizer, or
262
262
  propagator (those are not where injection happens). Each such call's argument
263
263
  taint is classified with the cross-file resolver. A safe sink that consumes
264
- tainted data (e.g. ``json.loads(request.data)``) contributes SANITIZED -- the
264
+ tainted data (e.g. ``json.loads(request.data)``) contributes SANITIZED: the
265
265
  data was handled safely. The worst contribution is returned.
266
266
 
267
267
  ``Taint.UNKNOWN`` when no inspectable sink is found (the artifact may still be
@@ -1,4 +1,4 @@
1
- """Assembly -- build an orchestration from a strategy name and run it over a source.
1
+ """Assembly: build an orchestration from a strategy name and run it over a source.
2
2
 
3
3
  Shared by the CLI and the task layer so the "which agents + which orchestrator"
4
4
  mapping and the per-artifact run loop live in one place.
@@ -1,16 +1,16 @@
1
- """Diff baseline -- report only findings new since a stored baseline report.
1
+ """Diff baseline: report only findings new since a stored baseline report.
2
2
 
3
- The keystone for PR-time noise control: run against a saved baseline report (the
4
- target branch's findings) and keep only the problem observations whose
3
+ The keystone for PR-time noise control: run against a saved baseline report, the
4
+ target branch's findings, and keep only the problem observations whose
5
5
  fingerprint is absent from the baseline, so a review shows what this change
6
- introduced -- not the codebase's pre-existing findings. Paired with --fail-on,
6
+ introduced rather than the codebase's pre-existing findings. Paired with --fail-on,
7
7
  CI then gates on new issues only.
8
8
 
9
- The fingerprint is line-number-tolerant (lines shift between versions): it keys
9
+ The fingerprint is line-number-tolerant because lines shift between versions: it keys
10
10
  on the capability, the kind/severity/status, the matched patterns, and the
11
- normalized evidence snippet -- never the line number. Only problem observations
12
- (Findings, VULNERABLE/PARTIAL Verdicts) are compared and dropped; SECURE /
13
- NOT_PRESENT verdicts and concessions are always kept.
11
+ normalized evidence snippet, never the line number. Only problem observations,
12
+ namely Findings and VULNERABLE/PARTIAL Verdicts, are compared and dropped; SECURE
13
+ and NOT_PRESENT verdicts and concessions are always kept.
14
14
  """
15
15
 
16
16
  from __future__ import annotations
@@ -52,7 +52,7 @@ def filter_new(results: Results, baseline: Results) -> tuple[Results, int]:
52
52
 
53
53
 
54
54
  def _evidence_sig(o: Observation) -> str:
55
- # fingerprints only the first evidence snippet -- enough to distinguish findings
55
+ # fingerprints only the first evidence snippet, enough to distinguish findings
56
56
  # in practice; two findings differing only in a later snippet would collide.
57
57
  evidence = getattr(o, "evidence", [])
58
58
  return " ".join(evidence[0].code.split()) if evidence and evidence[0].code else ""
@@ -1,7 +1,7 @@
1
1
  id: business_logic
2
2
  name: Business Logic
3
3
  asvs_chapter: V11
4
- description: Correctness of stateful workflows against abuse -- ordering, races, replay, and value validation.
4
+ description: Correctness of stateful workflows against abuse, covering ordering, races, replay, and value validation.
5
5
 
6
6
  sub_capabilities:
7
7
  state_and_sequence:
@@ -1,7 +1,7 @@
1
1
  id: dependency_config
2
2
  name: Dependencies and Configuration
3
3
  asvs_chapter: V14
4
- description: Software supply chain and deployment configuration -- known-vulnerable components and unsafe defaults.
4
+ description: Software supply chain and deployment configuration, covering known-vulnerable components and unsafe defaults.
5
5
 
6
6
  sub_capabilities:
7
7
  dependencies:
@@ -50,7 +50,7 @@ sub_capabilities:
50
50
  correct_patterns:
51
51
  - id: TLS-OK-1
52
52
  description: >-
53
- Leave TLS certificate verification at its secure default -- verify omitted or
53
+ Leave TLS certificate verification at its secure default: verify omitted or
54
54
  verify=True, the default SSL context, hostname checking on
55
55
  signals: ["verify=True", "create_default_context", "requests.get(", "requests.post("]
56
56
  why_ok: >-
@@ -63,7 +63,7 @@ sub_capabilities:
63
63
  cwe: CWE-295
64
64
  severity: HIGH
65
65
  description: >-
66
- Disable TLS certificate or hostname verification -- verify=False, CERT_NONE,
66
+ Disable TLS certificate or hostname verification: verify=False, CERT_NONE,
67
67
  check_hostname=False, or an unverified SSL context
68
68
  signals: ["verify=False", "CERT_NONE", "check_hostname = False", "_create_unverified_context"]
69
69
  why_bad: An unverified TLS connection is open to a man-in-the-middle despite https://
@@ -1,12 +1,12 @@
1
- # OWASP LLM Top 10 (2025) -- LLM06: Excessive Agency.
1
+ # OWASP LLM Top 10 (2025), LLM06: Excessive Agency.
2
2
  id: excessive_agency
3
3
  name: Excessive Agency
4
4
  asvs_chapter: "" # OWASP LLM06, not an ASVS chapter
5
5
  description: >-
6
6
  An LLM-driven agent acts on the world from model output. The risk is too much
7
7
  autonomy or privilege: a completion (which an attacker can steer via prompt
8
- injection) triggers a high-impact or irreversible action -- delete, transfer,
9
- send, run -- with no allowlist of permitted tools, no human confirmation, and
8
+ injection) triggers a high-impact or irreversible action, such as delete, transfer,
9
+ send, or run, with no allowlist of permitted tools, no human confirmation, and
10
10
  no least-privilege scoping. The fix is to gate actions: allowlist low-impact
11
11
  tools, require human approval for high-impact ones, and scope each tool's
12
12
  authority narrowly. This is about the action and its authority, not about
@@ -54,7 +54,7 @@ sub_capabilities:
54
54
  cwe: CWE-78
55
55
  severity: CRITICAL
56
56
  description: >-
57
- Pass interpolated input to an OS shell or subprocess -- os.system, os.popen,
57
+ Pass interpolated input to an OS shell or subprocess: os.system, os.popen,
58
58
  subprocess(..., shell=True), or eval/exec. A normal function, method, or
59
59
  library/API call is NOT this; flag only an actual shell or process invocation.
60
60
  signals: ["os.system(", "shell=True", "os.popen("]
@@ -80,7 +80,7 @@ sub_capabilities:
80
80
 
81
81
  - id: PATH-OK-2
82
82
  description: >-
83
- Use a path that is not attacker-controlled -- a data field, a directory read from
83
+ Use a path that is not attacker-controlled: a data field, a directory read from
84
84
  trusted config, or a path the operator passes on the command line
85
85
  why_ok: >-
86
86
  Traversal needs an external attacker to control the path. A path stored as a
@@ -114,7 +114,7 @@ sub_capabilities:
114
114
 
115
115
  - id: SSRF-OK-2
116
116
  description: >-
117
- Fetch a URL that is not attacker-controlled -- a constant, a value from trusted
117
+ Fetch a URL that is not attacker-controlled: a constant, a value from trusted
118
118
  config, or an operator-supplied argument
119
119
  why_ok: >-
120
120
  SSRF needs an external attacker to control the destination. A constant URL or one
@@ -130,7 +130,7 @@ sub_capabilities:
130
130
  constant URL, one from trusted config, or an operator-supplied argument.
131
131
  signals: ["requests.get(", "urllib.request.urlopen(", "httpx.", "request.args", "request.json"]
132
132
  why_bad: >-
133
- The server makes the request, so attacker input reaches internal-only targets --
133
+ The server makes the request, so attacker input reaches internal-only targets:
134
134
  cloud metadata, localhost admin ports, internal APIs behind the firewall.
135
135
  example_bad: |
136
136
  requests.get(request.args["url"]).text
@@ -143,7 +143,7 @@ sub_capabilities:
143
143
  correct_patterns:
144
144
  - id: DESER-OK-1
145
145
  description: >-
146
- Parse untrusted input with a data-only parser -- json.loads or yaml.safe_load --
146
+ Parse untrusted input with a data-only parser, json.loads or yaml.safe_load,
147
147
  that cannot instantiate arbitrary objects
148
148
  signals: ["json.loads", "yaml.safe_load"]
149
149
  why_ok: A data-only parser builds plain structures and has no code-execution path
@@ -153,7 +153,7 @@ sub_capabilities:
153
153
  cwe: CWE-502
154
154
  severity: CRITICAL
155
155
  description: >-
156
- Deserialize externally controlled bytes with an object-constructing deserializer --
156
+ Deserialize externally controlled bytes with an object-constructing deserializer:
157
157
  pickle, marshal, yaml.load (unsafe Loader), or jsonpickle. NOT this: a data-only
158
158
  parser like json.loads or yaml.safe_load.
159
159
  signals: ["pickle.loads", "pickle.load(", "yaml.load(", "marshal.loads", "jsonpickle.decode"]
@@ -1,11 +1,11 @@
1
- # OWASP LLM Top 10 (2025) -- LLM05: Improper Output Handling.
1
+ # OWASP LLM Top 10 (2025), LLM05: Improper Output Handling.
2
2
  id: insecure_output_handling
3
3
  name: Insecure Output Handling
4
4
  asvs_chapter: "" # OWASP LLM05, not an ASVS chapter
5
5
  description: >-
6
6
  Model output is untrusted. When a completion is passed to a downstream
7
7
  interpreter (eval/exec, a shell, SQL) or rendered as markup without validation
8
- or encoding, the model -- or an attacker who steered it via prompt injection --
8
+ or encoding, the model, or an attacker who steered it via prompt injection,
9
9
  can reach code execution or XSS. Constrain and validate model output before use;
10
10
  encode it before rendering.
11
11
 
@@ -1,9 +1,9 @@
1
- # OWASP LLM Top 10 (2025) -- LLM01: Prompt Injection.
1
+ # OWASP LLM Top 10 (2025), LLM01: Prompt Injection.
2
2
  id: prompt_injection
3
3
  name: Prompt Injection
4
4
  asvs_chapter: "" # OWASP LLM01, not an ASVS chapter
5
5
  description: >-
6
- Untrusted text (the end user's input, or content the app retrieves -- web pages,
6
+ Untrusted text (the end user's input, or content the app retrieves: web pages,
7
7
  documents, tool/function results, RAG chunks) reaches the model in a position
8
8
  where the model can treat it as instructions. The fix is separation and least
9
9
  authority: keep untrusted content as data, never concatenate it into the
@@ -11,13 +11,13 @@ sub_capabilities:
11
11
  signals: ["os.environ[", "os.getenv(", "secretsmanager", "vault"]
12
12
  why_ok: >-
13
13
  A variable that reads its value from the environment or a secret manager is the
14
- correct pattern, not a violation -- nothing secret is written in the source.
14
+ correct pattern, not a violation; nothing secret is written in the source.
15
15
 
16
16
  - id: SEC-OK-2
17
17
  description: Receive a secret as a function or constructor parameter (dependency injection)
18
18
  signals: ["def __init__(self, *, api_key", "api_key: str | None = None", "api_key=api_key"]
19
19
  why_ok: >-
20
- Accepting or forwarding a key through a parameter or variable is correct -- the value
20
+ Accepting or forwarding a key through a parameter or variable is correct; the value
21
21
  comes from the caller or the environment, not a literal in the source. Only an actual
22
22
  key string written in the code is a finding.
23
23
 
@@ -26,7 +26,7 @@ sub_capabilities:
26
26
  cwe: CWE-798
27
27
  severity: HIGH
28
28
  description: >-
29
- Assign a literal credential string -- an actual key/token value written in the source.
29
+ Assign a literal credential string: an actual key/token value written in the source.
30
30
  A variable, parameter, env lookup, or a non-credential string (e.g. a model name or
31
31
  URL) that merely holds or forwards a value is NOT this.
32
32
  signals: ['api_key = "sk', 'token = "ghp_', 'aws_secret_access_key = "']
@@ -34,8 +34,8 @@ sub_capabilities:
34
34
  example_bad: |
35
35
  API_KEY = "sk_live_51HxQ....actual-secret-value" # literal secret in source
36
36
  example_good: |
37
- api_key = os.environ["API_KEY"] # read from env -- fine
38
- client = Client(api_key=api_key) # passed as a parameter -- fine
37
+ api_key = os.environ["API_KEY"] # read from env, fine
38
+ client = Client(api_key=api_key) # passed as a parameter, fine
39
39
 
40
40
  - id: SEC-BAD-2
41
41
  cwe: CWE-259
@@ -1,5 +1,5 @@
1
1
  # Adversarial negative: the model chooses an action, but only among a fixed set
2
- # of low-impact, read-only actions -- no arbitrary dispatch, no high-impact op.
2
+ # of low-impact, read-only actions: no arbitrary dispatch, no high-impact op.
3
3
  capability: excessive_agency
4
4
  vulnerable: false
5
5
  expected_verdict: SECURE
@@ -1,5 +1,5 @@
1
1
  # Adversarial positive: looks gated, but the "confirmation" is set by the model
2
- # itself -- not a human -- so it is no gate at all.
2
+ # itself, not a human, so it is no gate at all.
3
3
  capability: excessive_agency
4
4
  vulnerable: true
5
5
  expected_verdict: VULNERABLE
@@ -2,5 +2,5 @@ capability: authn
2
2
  vulnerable: false
3
3
  code: |
4
4
  def file_dedup_key(data: bytes) -> str:
5
- # content hash for cache dedup -- NOT a password
5
+ # content hash for cache dedup, NOT a password
6
6
  return hashlib.sha256(data).hexdigest()