ansede-static 2.3.0.dev0__tar.gz → 2.3.1__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.
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/CHANGELOG.md +49 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/PKG-INFO +55 -64
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/README.md +54 -63
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/pyproject.toml +1 -1
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/__init__.py +63 -5
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/cli.py +159 -14
- ansede_static-2.3.1/src/ansede_static/engine/audit.py +967 -0
- ansede_static-2.3.1/src/ansede_static/engine/llm_triage.py +461 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine_version.py +6 -3
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/ir/global_graph.py +56 -2
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_analyzer.py +9 -2
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_ast_analyzer.py +96 -7
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/common.py +5 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/project.py +30 -3
- ansede_static-2.3.1/src/ansede_static/js_engine/project_context.py +297 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/routes.py +44 -17
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/structure.py +17 -4
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/taint_checks.py +13 -0
- ansede_static-2.3.1/src/ansede_static/profiler.py +98 -0
- ansede_static-2.3.1/tests/test_audit_engine.py +284 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_community_rules.py +20 -0
- ansede_static-2.3.1/tests/test_js_minified_project_index.py +53 -0
- ansede_static-2.3.1/tests/test_js_pratt_parser.py +41 -0
- ansede_static-2.3.1/tests/test_js_structure_cache.py +28 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_quality_benchmark.py +2 -2
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/.gitignore +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/LICENSE +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/_types.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/cache/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/cache/incremental.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/cache/sqlite_store.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/config.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/cpg/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/cpg/builder.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/cpg/graph.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/cpg/taint_engine.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/csharp_analyzer.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/async_scanner.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/ci_baseline.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/clustering.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/confidence.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/cvss.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/dump_failures.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/explain.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/learning_triage.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/nuclei.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/remediation.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/semgrep_.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/shadow_scan.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/symbolic_guards.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/engine/triage.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/entropy.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/go_engine/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/go_engine/go_analyzer.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/go_engine/go_parser.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/hardening.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/ir/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/ir/issues.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/ir/stir.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/java_analyzer.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/backends.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/constants.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/context_checks.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/minified_scanner.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/module_resolver.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/pattern_rules.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/pratt/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/pratt/ast_nodes.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/pratt/lexer.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/pratt/parser.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/pratt_analyzer.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/react.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/source_map_resolver.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/sourcemap_rescanner.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/js_engine/taint.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/licensing.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/lsp_server.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/monorepo.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/php_analyzer.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/pypi_validator.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/python_analyzer.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/aiohttp_web.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/angular_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/api_security.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/archive_extraction_py.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/aspnet_core.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/axios_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/boto3_aws.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/celery.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/cloud_security.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/community.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/cryptography_lib.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/deserialization_py.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/django.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/django_rest.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/express_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/fastapi.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/flask.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/graphql_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/graphql_py.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/jwt_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/jwt_py.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/knex_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/ldap_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/ldap_py.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/loader.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/mongoose_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/mysql2_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/nestjs_framework.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/nextjs_framework.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/nodejs_core.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/pg_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/prisma_orm.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/prototype_pollution_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/pug_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/pydantic.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/pymongo.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/race_condition_py.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/react_frontend.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/redis_py.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/requests_lib.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/second_order_sql.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/sequelize_orm.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/sharded_loader.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/socketio.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/spring_boot.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/sqlalchemy.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/subprocess_lib.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/supply_chain.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/template_engines_py.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/tornado_web.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/typeorm_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/vue_js.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/xml_parsers.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry/yaml_load.yaml +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/registry.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/reporters.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/ruby_analyzer.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/rules.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/rulesets/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/rulesets/datascience.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/sanitizers.json +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/sarif_validator.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/sbom.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/schema.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/schemas/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/schemas/ansede.schema.json +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/taint_specs.json +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/template_transpiler.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/baseline.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/call_graph.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/engine.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/ifds.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/interprocedural_taint.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/model.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/nodes.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/normalizer.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rule_protocol.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/javascript/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/javascript/crypto.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/javascript/framework.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/javascript/injection.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/javascript/xss.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/python/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/python/auth.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/python/crypto.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/python/deserialization.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/python/framework.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/python/injection.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/python/logging_.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/python/path_traversal.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/python/secrets.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/python/ssrf.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/shared/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/rules/shared/sql_injection.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/suppression.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/v2/taint.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/src/ansede_static/yaml_rules.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/__init__.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/conftest.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_async_scanner.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_cache.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_cli.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_confidence.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_config.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_corpus_offline.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_cpg.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_cvss.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_datascience.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_entropy.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_explain.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_external_corpus.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_ifds.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_ifds_e2e_integration.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_ifds_ide_lattice.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_ifds_realistic_scenarios.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_incremental.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_interprocedural_taint.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_java_csharp_analyzers.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_js.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_js_ast.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_lsp_server.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_noise_policies.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_phase2_registry_expansion.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_phase4_diagnostics.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_python.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_real_world_compare.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_remediation.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_reporters.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_rules.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_symbolic_guards.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_triage.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_web_wild_harness.py +0 -0
- {ansede_static-2.3.0.dev0 → ansede_static-2.3.1}/tests/test_yaml_rules.py +0 -0
|
@@ -3,6 +3,55 @@
|
|
|
3
3
|
All notable changes to ansede-static are documented here.
|
|
4
4
|
Format follows [Keep a Changelog](https://keepachangelog.com/).
|
|
5
5
|
|
|
6
|
+
## [2.3.1] — 2026-05-26
|
|
7
|
+
|
|
8
|
+
### Changed — Honest Metrics & Documentation Overhaul
|
|
9
|
+
|
|
10
|
+
- **Replaced all benchmarks with honest real-world data.** Old curated/synthetic metrics replaced with fresh 10-repo + prior 25-repo real open-source benchmarks (35 unique repos, 71.25 MB, 5 languages, 4,649 findings).
|
|
11
|
+
- **Updated README.md** — badges, comparison table, verified performance, and detection coverage now reflect actual measurements.
|
|
12
|
+
- **Updated BENCHMARKS.md** — complete rewrite with raw unfiltered real-world metrics, honest caveats, and reproducible methodology.
|
|
13
|
+
- **Updated final_scorecard.json** — now reflects real-world scan data instead of curated metrics.
|
|
14
|
+
- **Updated CHANGELOG.md** — this entry.
|
|
15
|
+
- **Version bumped to 2.3.1** for PyPI release.
|
|
16
|
+
|
|
17
|
+
### Performance — Second Speed Pass
|
|
18
|
+
|
|
19
|
+
- **63.6% faster overall** (226.4s → 82.5s on 25-repo benchmark).
|
|
20
|
+
- JS project index reuse: structural analyzer passes its `project` to the classic fallback instead of rebuilding.
|
|
21
|
+
- Route-block `@lru_cache`: 6 cached functions in `routes.py` prevent 11 checkers from recomputing the same route data.
|
|
22
|
+
- `GlobalGraph._normalize_path()` memoized with `@lru_cache(maxsize=32768)`.
|
|
23
|
+
- `GlobalGraph.load_summary()` remembers absent keys to skip redundant SQLite queries.
|
|
24
|
+
- All metrics (findings, clustering, noise quotient) unchanged — verified by before/after benchmark comparison.
|
|
25
|
+
|
|
26
|
+
## [2.3.0] — 2026-05-22
|
|
27
|
+
|
|
28
|
+
### Added — LLM-Assisted Triage Engine
|
|
29
|
+
- **`--llm` flag** — local Ollama integration (gemma3:4b) for classifying remaining NEEDS_REVIEW findings. Zero cloud dependency.
|
|
30
|
+
- **Persistent Few-Shot Memory** (`~/.ansede/llm_memory.json`) — 354 curated examples across 26 CWE/agent groups. Automatically trains on high-confidence LLM verdicts.
|
|
31
|
+
- **`--audit` pipeline boost** — heuristic + LLM combo now achieves ~96% auto-classification across 6 scanned production repos (5,575 files, 7 languages).
|
|
32
|
+
|
|
33
|
+
### Added — Training Pipeline
|
|
34
|
+
- **Batch scanning framework** — `scan_repos.py` pattern for automated scanning, auditing, and LLM triage across multiple repositories.
|
|
35
|
+
- **Confidence-gated memory** — only stores entries with confidence >= 0.75 with dedup and smart eviction (keeps highest-quality per group).
|
|
36
|
+
- **Cross-language coverage** — memory entries span Ruby, JavaScript, TypeScript, Go, PHP, and Python analyzers.
|
|
37
|
+
|
|
38
|
+
### Performance
|
|
39
|
+
- Heuristic classification: ~72-94% (language-dependent)
|
|
40
|
+
- LLM + Heuristic combo: **~93-100%** across all scanned repos
|
|
41
|
+
- pocketbase (Go/JS): 93%
|
|
42
|
+
- docuseal (Ruby/JS): 97%
|
|
43
|
+
- monica (PHP): 93%
|
|
44
|
+
- gogs (Go): ✅
|
|
45
|
+
- hoppscotch (JS/TS): 97%
|
|
46
|
+
- hedgedoc (JS/TS): 100%
|
|
47
|
+
- fastapi (Python): 100%
|
|
48
|
+
- LLM triage throughput: ~2 sec/finding on RTX 5070 (12GB)
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
- `check_ollama_available()` — updated for ollama Python library v0.6.2 API (ListResponse.models, Model.model)
|
|
52
|
+
- Reduced confidence thresholds for gemma3:4b compatibility (memory gate: 0.75, triage gate: 0.70)
|
|
53
|
+
- `--audit` flag now properly recognized via `python -m ansede_static.cli`
|
|
54
|
+
|
|
6
55
|
## [2.2.1] — 2026-05-18
|
|
7
56
|
|
|
8
57
|
### Added — Master Engineering Directive: World-Best Finalization
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ansede-static
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.1
|
|
4
4
|
Summary: AST-based SAST for Python and JavaScript — detects IDOR, auth bypass, and ownership flaws that Bandit misses.
|
|
5
5
|
Project-URL: Homepage, https://github.com/mattybellx/Ansede
|
|
6
6
|
Project-URL: Repository, https://github.com/mattybellx/Ansede
|
|
@@ -55,8 +55,8 @@ Description-Content-Type: text/markdown
|
|
|
55
55
|
</p>
|
|
56
56
|
|
|
57
57
|
<p align="center">
|
|
58
|
-
<strong>
|
|
59
|
-
Zero dependencies.
|
|
58
|
+
<strong>Offline static application security testing engine.</strong><br>
|
|
59
|
+
Zero dependencies. Real-world validated. 5 languages. LLM-assisted triage. Ships as a single <code>.exe</code>.
|
|
60
60
|
</p>
|
|
61
61
|
|
|
62
62
|
<p align="center">
|
|
@@ -64,8 +64,9 @@ Description-Content-Type: text/markdown
|
|
|
64
64
|
<a href="https://pypi.org/project/ansede-static/"><img src="https://img.shields.io/pypi/v/ansede-static?label=pypi&color=0078D4" alt="PyPI"></a>
|
|
65
65
|
<a href="https://pypi.org/project/ansede-static/"><img src="https://img.shields.io/pypi/dm/ansede-static?label=downloads&color=107C10" alt="Downloads"></a>
|
|
66
66
|
<a href="https://github.com/mattybellx/Ansede/actions/workflows/ci.yml"><img src="https://github.com/mattybellx/Ansede/actions/workflows/ci.yml/badge.svg?branch=master" alt="CI"></a>
|
|
67
|
-
<a href="https://github.com/mattybellx/Ansede/blob/master/BENCHMARKS.md"><img src="https://img.shields.io/badge/
|
|
68
|
-
<a href="https://github.com/mattybellx/Ansede/blob/master/BENCHMARKS.md"><img src="https://img.shields.io/badge/
|
|
67
|
+
<a href="https://github.com/mattybellx/Ansede/blob/master/BENCHMARKS.md"><img src="https://img.shields.io/badge/Real%20Repos%20Scanned-35-blue" alt="35 real repos scanned"></a>
|
|
68
|
+
<a href="https://github.com/mattybellx/Ansede/blob/master/BENCHMARKS.md"><img src="https://img.shields.io/badge/CWE%20Types-33%2B-yellow" alt="33+ CWE types"></a>
|
|
69
|
+
<a href="https://github.com/mattybellx/Ansede/blob/master/BENCHMARKS.md"><img src="https://img.shields.io/badge/LLM%20Triage-96%25%20auto-yellowgreen" alt="LLM Auto 96%"></a>
|
|
69
70
|
<a href="https://github.com/mattybellx/Ansede/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-yellow.svg" alt="License MIT"></a>
|
|
70
71
|
<a href="https://github.com/mattybellx/Ansede/stargazers"><img src="https://img.shields.io/github/stars/mattybellx/Ansede?style=social" alt="Stars"></a>
|
|
71
72
|
</p>
|
|
@@ -150,7 +151,7 @@ def delete_post(post_id):
|
|
|
150
151
|
# no if post.author_id != current_user.id: abort(403)
|
|
151
152
|
```
|
|
152
153
|
|
|
153
|
-
**ansede-static models routes, decorators, auth guards, and ownership patterns at the AST level.** This is how it
|
|
154
|
+
**ansede-static models routes, decorators, auth guards, and ownership patterns at the AST level.** This is how it catches access-control vulnerabilities that regex-only tools miss.
|
|
154
155
|
|
|
155
156
|
---
|
|
156
157
|
|
|
@@ -184,71 +185,59 @@ ansede-static src/ --incremental
|
|
|
184
185
|
|
|
185
186
|
## Verified Performance — May 2026
|
|
186
187
|
|
|
187
|
-
|
|
188
|
-
|---|---|
|
|
189
|
-
| Regression suite | **919 tests passed** |
|
|
190
|
-
| NVD CVE recall | **81/82 (98.78%)** |
|
|
191
|
-
| NVD CVE precision | **96.43%** |
|
|
192
|
-
| False positive rate | **3.57%** |
|
|
193
|
-
| Web-wild recall | **100.00%** |
|
|
194
|
-
| Web-wild precision | **95.00%** |
|
|
195
|
-
| External real-world corpus | **15/15 cases, 30/30 checks (100%)** |
|
|
196
|
-
| Noise quotient | **0.861 findings / kLOC** |
|
|
197
|
-
| Raw engine speed | **~0.02s per 100k LOC** |
|
|
198
|
-
| Languages | Python · JavaScript · TypeScript · Go · Java · C# |
|
|
199
|
-
| World-Best Audit | ✅ All quality gates passed |
|
|
188
|
+
For the full methodology and raw data, see [`BENCHMARKS.md`](BENCHMARKS.md).
|
|
200
189
|
|
|
201
|
-
|
|
190
|
+
### Real-World Validation — 35 Repos Scanned
|
|
202
191
|
|
|
203
|
-
|
|
192
|
+
ansede-static has been run against **35 real open-source repos** totaling over **71 MB of supported source code** across **5 languages**. Every finding was classified by the audit engine.
|
|
204
193
|
|
|
205
|
-
|
|
194
|
+
| Metric | 25 Small (≤2MB) | 10 Medium (2-10MB) | **Combined** |
|
|
195
|
+
|---|---|---:|---:|
|
|
196
|
+
| Repos scanned | 25 | 10 | **35** |
|
|
197
|
+
| Zero failures | ✅ | ✅ | **✅ 35/35** |
|
|
198
|
+
| Files scanned | 2,873 | 9,499 | **12,372** |
|
|
199
|
+
| Lines scanned | 333,811 | 1,426,143 | **1,759,954** |
|
|
200
|
+
| Source MB | 12.30 | 58.95 | **71.25 MB** |
|
|
201
|
+
| Total findings | 1,037 | 3,612 | **4,649** |
|
|
202
|
+
| Findings per kLOC | 3.11 | 2.53 | **2.64** |
|
|
203
|
+
| CWE types detected | 25+ | 33 | **35+** |
|
|
204
|
+
| True Positives | — | 11 | **11+** |
|
|
205
|
+
| NEEDS_REVIEW | — | 1,224 | **1,224+** |
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
**Top CWEs detected across all repos:** CWE-862 (missing auth), CWE-1333 (ReDoS), CWE-798 (hardcoded creds), CWE-352 (CSRF), CWE-95 (eval injection), CWE-79 (XSS), CWE-89 (SQLi).
|
|
208
|
+
|
|
209
|
+
### Synthetic Benchmarks
|
|
210
|
+
|
|
211
|
+
| Benchmark | Result |
|
|
208
212
|
|---|---|
|
|
209
|
-
|
|
|
210
|
-
|
|
|
211
|
-
|
|
|
212
|
-
|
|
|
213
|
-
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
**Key real-world discoveries:**
|
|
218
|
-
|
|
219
|
-
| Repo | Stars | Confirmed Vulns | Types Found |
|
|
220
|
-
|------|-------|----------------|-------------|
|
|
221
|
-
| **uptime-kuma** | ⭐ 60k | **16** 🔥 | Path traversal, SSRF, XSS, code injection |
|
|
222
|
-
| **pocketbase** | ⭐ 42k | **11** 🔥 | SQLi, path traversal, SSRF, command injection |
|
|
223
|
-
| **hoppscotch** | ⭐ 68k | **9** 🔥 | XSS, SQLi in OAuth, path traversal |
|
|
224
|
-
| **dashy** | ⭐ 20k | **7** | Dynamic require, path traversal, SSRF |
|
|
225
|
-
| **speedtest** | ⭐ 14k | **6** | Path traversal, open redirect, SSRF |
|
|
226
|
-
| **stackedit** | ⭐ 22k | **2** | Open redirect, eval injection |
|
|
227
|
-
| **docuseal** | — | **2** | XSS, SSRF |
|
|
228
|
-
| **appwrite** | ⭐ 37k | **1** | Path traversal |
|
|
229
|
-
| **linkding** | — | **1** | SQL injection |
|
|
230
|
-
| NodeGoat, dvna | — | 7 | Validation targets |
|
|
231
|
-
|
|
232
|
-
All confirmed findings were disclosed responsibly via GitHub Issues from `@mattybellx`.
|
|
233
|
-
|
|
234
|
-
> **Verdict:** The structural taint engine is genuinely **world-class** — **zero false positives** on interprocedural taint analysis across 8 languages. The YAML registry rules (context-free regex patterns) have higher FP rates and are being progressively tuned via the new `confidence` and `path_exclude` rule schema features. See [`tools/responsible_disclosure.py`](tools/responsible_disclosure.py) for the automated disclosure pipeline.
|
|
213
|
+
| NVD CVE snippet recall | **100%** (115/115 synthetic cases) |
|
|
214
|
+
| Web-wild recall | **100%** (6/6 vulnerable-by-design apps) |
|
|
215
|
+
| Web-wild F1 | **92.31%** |
|
|
216
|
+
| LLM auto-classification | **95.9%** across 632 findings, 7 languages |
|
|
217
|
+
| Languages | Python · JavaScript · TypeScript · Go · Java · C# |
|
|
218
|
+
|
|
219
|
+
**Honest note:** CVE snippet benchmarks measure pattern coverage, not real-world field performance. The real-world benchmark data above is the best measure of actual field behavior.
|
|
235
220
|
|
|
236
221
|
---
|
|
237
222
|
|
|
238
223
|
## Detection Coverage
|
|
239
224
|
|
|
240
|
-
| Category | CWEs detected | Example |
|
|
241
|
-
|
|
242
|
-
|
|
|
243
|
-
|
|
|
244
|
-
|
|
|
245
|
-
| Path Traversal & SSRF | CWE-22, CWE-918 | Unsanitized `os.path.join`, user-controlled URLs in `requests.get()` |
|
|
246
|
-
| Cross-Site Issues | CWE-79, CWE-352 | `innerHTML` with user data, missing CSRF tokens |
|
|
247
|
-
| Deserialization | CWE-502 | `pickle.loads()` on untrusted input |
|
|
248
|
-
| Open Redirect | CWE-601 | User-controlled `next` parameter in `redirect()` |
|
|
249
|
-
| Log Injection | CWE-117 | Unsanitized user input in log messages |
|
|
225
|
+
| Category | CWEs detected (verified in fresh benchmark) | Example |
|
|
226
|
+
|---|---|---|---|
|
|
227
|
+
| Missing Authentication | CWE-862, CWE-287 | Route missing `@login_required` |
|
|
228
|
+
| IDOR / Broken Access Control | CWE-639, CWE-285 | No ownership check on DB query |
|
|
229
|
+
| Injection (SQL, Command, Eval) | CWE-89, CWE-78, CWE-95, CWE-94 | SQLi via f-string, `subprocess(shell=True)`, eval injection |
|
|
250
230
|
| ReDoS | CWE-1333 | Catastrophic backtracking in regex patterns |
|
|
251
|
-
|
|
|
231
|
+
| Hardcoded Credentials | CWE-798 | API tokens, AWS keys, passwords in source |
|
|
232
|
+
| CSRF | CWE-352 | Missing CSRF tokens on mutating routes |
|
|
233
|
+
| XSS | CWE-79 | `innerHTML` with user data |
|
|
234
|
+
| Path Traversal & SSRF | CWE-22, CWE-918 | Unsanitized `os.path.join`, user-controlled URLs |
|
|
235
|
+
| Open Redirect | CWE-601 | User-controlled `next` in `redirect()` |
|
|
236
|
+
| Deserialization | CWE-502 | `pickle.loads()` on untrusted input |
|
|
237
|
+
| Prototype Pollution | CWE-1321 | Unsafe object merge |
|
|
238
|
+
| Log Injection | CWE-117 | Unsanitized input in log messages |
|
|
239
|
+
| Weak Cryptography | CWE-327, CWE-328 | MD5/SHA1 for passwords |
|
|
240
|
+
| And more | 33+ CWE types detected in one 10-repo run | See `ansede-static --list-rules` |
|
|
252
241
|
|
|
253
242
|
---
|
|
254
243
|
|
|
@@ -306,15 +295,17 @@ All confirmed findings were disclosed responsibly via GitHub Issues from `@matty
|
|
|
306
295
|
|
|
307
296
|
| | ansede-static | Bandit OSS | Semgrep OSS | CodeQL CLI |
|
|
308
297
|
|---|---|---|---|---|
|
|
309
|
-
|
|
|
310
|
-
|
|
|
298
|
+
| Real repos validated | **35** | 1 (Python only) | Community | Limited |
|
|
299
|
+
| CWE types detected | **33+** in one run | ~10 | ~15-25 | ~25-40 |
|
|
300
|
+
| Interprocedural taint | **Full** | ❌ | ❌ (Pro only) | ✅ |
|
|
301
|
+
| Route/auth analysis | **11 checkers** | ❌ | Basic patterns | Limited |
|
|
302
|
+
| Auto-triage + clustering | **✅ 49% reduction** | ❌ | ❌ | ❌ |
|
|
311
303
|
| Offline (no network) | ✓ | ✓ | ✗ | ✗ |
|
|
312
304
|
| Zero dependencies | ✓ | ✗ | ✗ | ✗ |
|
|
313
305
|
| Single binary (.exe) | ✓ | ✗ | ✗ | ✗ |
|
|
314
|
-
| IDOR / Auth bypass |
|
|
306
|
+
| IDOR / Auth bypass | **✓** | ✗ | Partial | Partial |
|
|
315
307
|
| Languages | 5 | 1 | 20+ | 7 |
|
|
316
308
|
| Install size | <5 MB | ~15 MB | ~200 MB | ~600 MB |
|
|
317
|
-
| Speed (scan_file) | **0.02s/100k LOC** | 0.5s | 3s | 10s |
|
|
318
309
|
|
|
319
310
|
---
|
|
320
311
|
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
|
-
<strong>
|
|
11
|
-
Zero dependencies.
|
|
10
|
+
<strong>Offline static application security testing engine.</strong><br>
|
|
11
|
+
Zero dependencies. Real-world validated. 5 languages. LLM-assisted triage. Ships as a single <code>.exe</code>.
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
<p align="center">
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
<a href="https://pypi.org/project/ansede-static/"><img src="https://img.shields.io/pypi/v/ansede-static?label=pypi&color=0078D4" alt="PyPI"></a>
|
|
17
17
|
<a href="https://pypi.org/project/ansede-static/"><img src="https://img.shields.io/pypi/dm/ansede-static?label=downloads&color=107C10" alt="Downloads"></a>
|
|
18
18
|
<a href="https://github.com/mattybellx/Ansede/actions/workflows/ci.yml"><img src="https://github.com/mattybellx/Ansede/actions/workflows/ci.yml/badge.svg?branch=master" alt="CI"></a>
|
|
19
|
-
<a href="https://github.com/mattybellx/Ansede/blob/master/BENCHMARKS.md"><img src="https://img.shields.io/badge/
|
|
20
|
-
<a href="https://github.com/mattybellx/Ansede/blob/master/BENCHMARKS.md"><img src="https://img.shields.io/badge/
|
|
19
|
+
<a href="https://github.com/mattybellx/Ansede/blob/master/BENCHMARKS.md"><img src="https://img.shields.io/badge/Real%20Repos%20Scanned-35-blue" alt="35 real repos scanned"></a>
|
|
20
|
+
<a href="https://github.com/mattybellx/Ansede/blob/master/BENCHMARKS.md"><img src="https://img.shields.io/badge/CWE%20Types-33%2B-yellow" alt="33+ CWE types"></a>
|
|
21
|
+
<a href="https://github.com/mattybellx/Ansede/blob/master/BENCHMARKS.md"><img src="https://img.shields.io/badge/LLM%20Triage-96%25%20auto-yellowgreen" alt="LLM Auto 96%"></a>
|
|
21
22
|
<a href="https://github.com/mattybellx/Ansede/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-yellow.svg" alt="License MIT"></a>
|
|
22
23
|
<a href="https://github.com/mattybellx/Ansede/stargazers"><img src="https://img.shields.io/github/stars/mattybellx/Ansede?style=social" alt="Stars"></a>
|
|
23
24
|
</p>
|
|
@@ -102,7 +103,7 @@ def delete_post(post_id):
|
|
|
102
103
|
# no if post.author_id != current_user.id: abort(403)
|
|
103
104
|
```
|
|
104
105
|
|
|
105
|
-
**ansede-static models routes, decorators, auth guards, and ownership patterns at the AST level.** This is how it
|
|
106
|
+
**ansede-static models routes, decorators, auth guards, and ownership patterns at the AST level.** This is how it catches access-control vulnerabilities that regex-only tools miss.
|
|
106
107
|
|
|
107
108
|
---
|
|
108
109
|
|
|
@@ -136,71 +137,59 @@ ansede-static src/ --incremental
|
|
|
136
137
|
|
|
137
138
|
## Verified Performance — May 2026
|
|
138
139
|
|
|
139
|
-
|
|
140
|
-
|---|---|
|
|
141
|
-
| Regression suite | **919 tests passed** |
|
|
142
|
-
| NVD CVE recall | **81/82 (98.78%)** |
|
|
143
|
-
| NVD CVE precision | **96.43%** |
|
|
144
|
-
| False positive rate | **3.57%** |
|
|
145
|
-
| Web-wild recall | **100.00%** |
|
|
146
|
-
| Web-wild precision | **95.00%** |
|
|
147
|
-
| External real-world corpus | **15/15 cases, 30/30 checks (100%)** |
|
|
148
|
-
| Noise quotient | **0.861 findings / kLOC** |
|
|
149
|
-
| Raw engine speed | **~0.02s per 100k LOC** |
|
|
150
|
-
| Languages | Python · JavaScript · TypeScript · Go · Java · C# |
|
|
151
|
-
| World-Best Audit | ✅ All quality gates passed |
|
|
140
|
+
For the full methodology and raw data, see [`BENCHMARKS.md`](BENCHMARKS.md).
|
|
152
141
|
|
|
153
|
-
|
|
142
|
+
### Real-World Validation — 35 Repos Scanned
|
|
154
143
|
|
|
155
|
-
|
|
144
|
+
ansede-static has been run against **35 real open-source repos** totaling over **71 MB of supported source code** across **5 languages**. Every finding was classified by the audit engine.
|
|
156
145
|
|
|
157
|
-
|
|
146
|
+
| Metric | 25 Small (≤2MB) | 10 Medium (2-10MB) | **Combined** |
|
|
147
|
+
|---|---|---:|---:|
|
|
148
|
+
| Repos scanned | 25 | 10 | **35** |
|
|
149
|
+
| Zero failures | ✅ | ✅ | **✅ 35/35** |
|
|
150
|
+
| Files scanned | 2,873 | 9,499 | **12,372** |
|
|
151
|
+
| Lines scanned | 333,811 | 1,426,143 | **1,759,954** |
|
|
152
|
+
| Source MB | 12.30 | 58.95 | **71.25 MB** |
|
|
153
|
+
| Total findings | 1,037 | 3,612 | **4,649** |
|
|
154
|
+
| Findings per kLOC | 3.11 | 2.53 | **2.64** |
|
|
155
|
+
| CWE types detected | 25+ | 33 | **35+** |
|
|
156
|
+
| True Positives | — | 11 | **11+** |
|
|
157
|
+
| NEEDS_REVIEW | — | 1,224 | **1,224+** |
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
**Top CWEs detected across all repos:** CWE-862 (missing auth), CWE-1333 (ReDoS), CWE-798 (hardcoded creds), CWE-352 (CSRF), CWE-95 (eval injection), CWE-79 (XSS), CWE-89 (SQLi).
|
|
160
|
+
|
|
161
|
+
### Synthetic Benchmarks
|
|
162
|
+
|
|
163
|
+
| Benchmark | Result |
|
|
160
164
|
|---|---|
|
|
161
|
-
|
|
|
162
|
-
|
|
|
163
|
-
|
|
|
164
|
-
|
|
|
165
|
-
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
**Key real-world discoveries:**
|
|
170
|
-
|
|
171
|
-
| Repo | Stars | Confirmed Vulns | Types Found |
|
|
172
|
-
|------|-------|----------------|-------------|
|
|
173
|
-
| **uptime-kuma** | ⭐ 60k | **16** 🔥 | Path traversal, SSRF, XSS, code injection |
|
|
174
|
-
| **pocketbase** | ⭐ 42k | **11** 🔥 | SQLi, path traversal, SSRF, command injection |
|
|
175
|
-
| **hoppscotch** | ⭐ 68k | **9** 🔥 | XSS, SQLi in OAuth, path traversal |
|
|
176
|
-
| **dashy** | ⭐ 20k | **7** | Dynamic require, path traversal, SSRF |
|
|
177
|
-
| **speedtest** | ⭐ 14k | **6** | Path traversal, open redirect, SSRF |
|
|
178
|
-
| **stackedit** | ⭐ 22k | **2** | Open redirect, eval injection |
|
|
179
|
-
| **docuseal** | — | **2** | XSS, SSRF |
|
|
180
|
-
| **appwrite** | ⭐ 37k | **1** | Path traversal |
|
|
181
|
-
| **linkding** | — | **1** | SQL injection |
|
|
182
|
-
| NodeGoat, dvna | — | 7 | Validation targets |
|
|
183
|
-
|
|
184
|
-
All confirmed findings were disclosed responsibly via GitHub Issues from `@mattybellx`.
|
|
185
|
-
|
|
186
|
-
> **Verdict:** The structural taint engine is genuinely **world-class** — **zero false positives** on interprocedural taint analysis across 8 languages. The YAML registry rules (context-free regex patterns) have higher FP rates and are being progressively tuned via the new `confidence` and `path_exclude` rule schema features. See [`tools/responsible_disclosure.py`](tools/responsible_disclosure.py) for the automated disclosure pipeline.
|
|
165
|
+
| NVD CVE snippet recall | **100%** (115/115 synthetic cases) |
|
|
166
|
+
| Web-wild recall | **100%** (6/6 vulnerable-by-design apps) |
|
|
167
|
+
| Web-wild F1 | **92.31%** |
|
|
168
|
+
| LLM auto-classification | **95.9%** across 632 findings, 7 languages |
|
|
169
|
+
| Languages | Python · JavaScript · TypeScript · Go · Java · C# |
|
|
170
|
+
|
|
171
|
+
**Honest note:** CVE snippet benchmarks measure pattern coverage, not real-world field performance. The real-world benchmark data above is the best measure of actual field behavior.
|
|
187
172
|
|
|
188
173
|
---
|
|
189
174
|
|
|
190
175
|
## Detection Coverage
|
|
191
176
|
|
|
192
|
-
| Category | CWEs detected | Example |
|
|
193
|
-
|
|
194
|
-
|
|
|
195
|
-
|
|
|
196
|
-
|
|
|
197
|
-
| Path Traversal & SSRF | CWE-22, CWE-918 | Unsanitized `os.path.join`, user-controlled URLs in `requests.get()` |
|
|
198
|
-
| Cross-Site Issues | CWE-79, CWE-352 | `innerHTML` with user data, missing CSRF tokens |
|
|
199
|
-
| Deserialization | CWE-502 | `pickle.loads()` on untrusted input |
|
|
200
|
-
| Open Redirect | CWE-601 | User-controlled `next` parameter in `redirect()` |
|
|
201
|
-
| Log Injection | CWE-117 | Unsanitized user input in log messages |
|
|
177
|
+
| Category | CWEs detected (verified in fresh benchmark) | Example |
|
|
178
|
+
|---|---|---|---|
|
|
179
|
+
| Missing Authentication | CWE-862, CWE-287 | Route missing `@login_required` |
|
|
180
|
+
| IDOR / Broken Access Control | CWE-639, CWE-285 | No ownership check on DB query |
|
|
181
|
+
| Injection (SQL, Command, Eval) | CWE-89, CWE-78, CWE-95, CWE-94 | SQLi via f-string, `subprocess(shell=True)`, eval injection |
|
|
202
182
|
| ReDoS | CWE-1333 | Catastrophic backtracking in regex patterns |
|
|
203
|
-
|
|
|
183
|
+
| Hardcoded Credentials | CWE-798 | API tokens, AWS keys, passwords in source |
|
|
184
|
+
| CSRF | CWE-352 | Missing CSRF tokens on mutating routes |
|
|
185
|
+
| XSS | CWE-79 | `innerHTML` with user data |
|
|
186
|
+
| Path Traversal & SSRF | CWE-22, CWE-918 | Unsanitized `os.path.join`, user-controlled URLs |
|
|
187
|
+
| Open Redirect | CWE-601 | User-controlled `next` in `redirect()` |
|
|
188
|
+
| Deserialization | CWE-502 | `pickle.loads()` on untrusted input |
|
|
189
|
+
| Prototype Pollution | CWE-1321 | Unsafe object merge |
|
|
190
|
+
| Log Injection | CWE-117 | Unsanitized input in log messages |
|
|
191
|
+
| Weak Cryptography | CWE-327, CWE-328 | MD5/SHA1 for passwords |
|
|
192
|
+
| And more | 33+ CWE types detected in one 10-repo run | See `ansede-static --list-rules` |
|
|
204
193
|
|
|
205
194
|
---
|
|
206
195
|
|
|
@@ -258,15 +247,17 @@ All confirmed findings were disclosed responsibly via GitHub Issues from `@matty
|
|
|
258
247
|
|
|
259
248
|
| | ansede-static | Bandit OSS | Semgrep OSS | CodeQL CLI |
|
|
260
249
|
|---|---|---|---|---|
|
|
261
|
-
|
|
|
262
|
-
|
|
|
250
|
+
| Real repos validated | **35** | 1 (Python only) | Community | Limited |
|
|
251
|
+
| CWE types detected | **33+** in one run | ~10 | ~15-25 | ~25-40 |
|
|
252
|
+
| Interprocedural taint | **Full** | ❌ | ❌ (Pro only) | ✅ |
|
|
253
|
+
| Route/auth analysis | **11 checkers** | ❌ | Basic patterns | Limited |
|
|
254
|
+
| Auto-triage + clustering | **✅ 49% reduction** | ❌ | ❌ | ❌ |
|
|
263
255
|
| Offline (no network) | ✓ | ✓ | ✗ | ✗ |
|
|
264
256
|
| Zero dependencies | ✓ | ✗ | ✗ | ✗ |
|
|
265
257
|
| Single binary (.exe) | ✓ | ✗ | ✗ | ✗ |
|
|
266
|
-
| IDOR / Auth bypass |
|
|
258
|
+
| IDOR / Auth bypass | **✓** | ✗ | Partial | Partial |
|
|
267
259
|
| Languages | 5 | 1 | 20+ | 7 |
|
|
268
260
|
| Install size | <5 MB | ~15 MB | ~200 MB | ~600 MB |
|
|
269
|
-
| Speed (scan_file) | **0.02s/100k LOC** | 0.5s | 3s | 10s |
|
|
270
261
|
|
|
271
262
|
---
|
|
272
263
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ansede-static"
|
|
7
|
-
version = "2.3.
|
|
7
|
+
version = "2.3.1"
|
|
8
8
|
description = "AST-based SAST for Python and JavaScript — detects IDOR, auth bypass, and ownership flaws that Bandit misses."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -20,7 +20,9 @@ from ansede_static.python_analyzer import analyze_python, analyze_file as _py_fi
|
|
|
20
20
|
from ansede_static.js_engine.backends import list_js_backends, run_js_analysis
|
|
21
21
|
from ansede_static import yaml_rules as _yaml_rules
|
|
22
22
|
|
|
23
|
+
from functools import lru_cache
|
|
23
24
|
from pathlib import Path
|
|
25
|
+
from types import SimpleNamespace
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
__all__ = [
|
|
@@ -46,6 +48,65 @@ _RUBY_EXTS = frozenset({".rb", ".rake", ".gemspec"})
|
|
|
46
48
|
_PHP_EXTS = frozenset({".php", ".phtml", ".php3", ".php4", ".php5", ".php7", ".phps"})
|
|
47
49
|
|
|
48
50
|
|
|
51
|
+
def _rule_mtime(path: Path) -> int:
|
|
52
|
+
try:
|
|
53
|
+
return path.stat().st_mtime_ns
|
|
54
|
+
except OSError:
|
|
55
|
+
return -1
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _community_rules_token() -> tuple[tuple[str, int], ...]:
|
|
59
|
+
try:
|
|
60
|
+
rule_dir = Path(_yaml_rules.default_community_rules_dir()).resolve(strict=False)
|
|
61
|
+
except (OSError, TypeError, ValueError):
|
|
62
|
+
return tuple()
|
|
63
|
+
|
|
64
|
+
if not rule_dir.is_dir():
|
|
65
|
+
return tuple()
|
|
66
|
+
|
|
67
|
+
entries: list[tuple[str, int]] = []
|
|
68
|
+
for child in sorted(rule_dir.iterdir()):
|
|
69
|
+
if child.is_file() and child.suffix.lower() in {".yaml", ".yml", ".json"}:
|
|
70
|
+
entries.append((str(child.resolve(strict=False)), _rule_mtime(child)))
|
|
71
|
+
return tuple(entries)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@lru_cache(maxsize=64)
|
|
75
|
+
def _load_runtime_rules_cached(
|
|
76
|
+
workspace_root: str,
|
|
77
|
+
custom_rules_file: str,
|
|
78
|
+
custom_rules_mtime: int,
|
|
79
|
+
community_rules_token: tuple[tuple[str, int], ...],
|
|
80
|
+
) -> tuple[object, ...]:
|
|
81
|
+
config_stub = SimpleNamespace(custom_rules_file=custom_rules_file) if custom_rules_file else None
|
|
82
|
+
return tuple(_yaml_rules.load_runtime_rules(config=config_stub, workspace_root=Path(workspace_root)))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _get_runtime_rules(
|
|
86
|
+
config: AnsedeConfig | None,
|
|
87
|
+
*,
|
|
88
|
+
workspace_root: Path,
|
|
89
|
+
) -> list[object]:
|
|
90
|
+
resolved_root = str(workspace_root.resolve(strict=False))
|
|
91
|
+
custom_rules_file = str(getattr(config, "custom_rules_file", "") or "").strip() if config else ""
|
|
92
|
+
custom_rules_path = ""
|
|
93
|
+
custom_rules_mtime = -1
|
|
94
|
+
if custom_rules_file:
|
|
95
|
+
custom_path = Path(custom_rules_file)
|
|
96
|
+
if not custom_path.is_absolute():
|
|
97
|
+
custom_path = (workspace_root / custom_path).resolve(strict=False)
|
|
98
|
+
custom_rules_path = str(custom_path)
|
|
99
|
+
custom_rules_mtime = _rule_mtime(custom_path)
|
|
100
|
+
return list(
|
|
101
|
+
_load_runtime_rules_cached(
|
|
102
|
+
resolved_root,
|
|
103
|
+
custom_rules_path,
|
|
104
|
+
custom_rules_mtime,
|
|
105
|
+
_community_rules_token(),
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
49
110
|
def _apply_runtime_and_registry_rules(
|
|
50
111
|
code: str,
|
|
51
112
|
*,
|
|
@@ -89,13 +150,10 @@ def scan_file(
|
|
|
89
150
|
"""
|
|
90
151
|
p = Path(path)
|
|
91
152
|
ext = p.suffix.lower()
|
|
92
|
-
runtime_rules =
|
|
153
|
+
runtime_rules = _get_runtime_rules(config, workspace_root=Path.cwd())
|
|
93
154
|
code = p.read_text(encoding="utf-8", errors="replace")
|
|
94
155
|
|
|
95
156
|
# Create a shared GlobalGraph for IFDS-based interprocedural taint transfer.
|
|
96
|
-
# Both Python and JS analyzers feed summaries into it and query it during
|
|
97
|
-
# helper-call resolution, giving JS the same IDE-lattice-powered cross-file
|
|
98
|
-
# taint tracking that Python already uses.
|
|
99
157
|
try:
|
|
100
158
|
from ansede_static.ir.global_graph import GlobalGraph # noqa: PLC0415
|
|
101
159
|
shared_graph = GlobalGraph()
|
|
@@ -152,7 +210,7 @@ def scan_code(
|
|
|
152
210
|
Raises:
|
|
153
211
|
ValueError: if language is not supported.
|
|
154
212
|
"""
|
|
155
|
-
runtime_rules =
|
|
213
|
+
runtime_rules = _get_runtime_rules(config, workspace_root=Path.cwd())
|
|
156
214
|
with temporary_analyzer_config(config):
|
|
157
215
|
if language == "python":
|
|
158
216
|
result = analyze_python(code, filename=filename)
|