codejury 0.17.1__tar.gz → 0.19.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codejury-0.19.0/PKG-INFO +147 -0
- codejury-0.19.0/README.md +116 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/__init__.py +3 -2
- {codejury-0.17.1 → codejury-0.19.0}/codejury/cli.py +1 -1
- codejury-0.19.0/codejury/data/detection.yaml +17 -0
- codejury-0.19.0/codejury/data/frameworks/go/echo.md +31 -0
- codejury-0.19.0/codejury/data/frameworks/go/gin.md +34 -0
- codejury-0.19.0/codejury/data/frameworks/javascript/express.md +36 -0
- codejury-0.19.0/codejury/data/frameworks/javascript/nestjs.md +36 -0
- codejury-0.19.0/codejury/data/frameworks/python/celery.md +36 -0
- {codejury-0.17.1/codejury/data/frameworks → codejury-0.19.0/codejury/data/frameworks/python}/django.md +10 -7
- codejury-0.19.0/codejury/data/frameworks/python/fastapi.md +37 -0
- codejury-0.19.0/codejury/data/frameworks/python/flask.md +37 -0
- codejury-0.19.0/codejury/data/languages/go.md +35 -0
- codejury-0.19.0/codejury/data/languages/javascript.md +34 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/data/languages/python.md +4 -4
- codejury-0.19.0/codejury/data/languages/typescript.md +28 -0
- codejury-0.19.0/codejury/data/methodologies/repo-review.md +229 -0
- {codejury-0.17.1/codejury/data/methodology → codejury-0.19.0/codejury/data/methodologies}/security-review-memory.md +4 -4
- codejury-0.19.0/codejury/data/protocols/oauth.md +55 -0
- codejury-0.19.0/codejury/data/vulnerabilities/SKILL.md +59 -0
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/code-injection.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/cross-site-request-forgery.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/cross-site-scripting.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/http-response-splitting.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/improper-authentication.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/information-exposure.md +5 -5
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/insecure-cryptography.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/insecure-deserialization.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/insecure-direct-object-reference.md +2 -2
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/insecure-transport.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/mass-assignment.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/open-redirect.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/path-traversal.md +3 -3
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/race-condition.md +3 -3
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/replay-attack.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/server-side-request-forgery.md +2 -2
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/server-side-template-injection.md +3 -3
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/session-fixation.md +2 -2
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/sql-injection.md +1 -1
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/xml-external-entity.md +2 -2
- codejury-0.19.0/codejury/detection.py +56 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/diff/debate.py +6 -6
- {codejury-0.17.1 → codejury-0.19.0}/codejury/diff/debate_prompts.py +7 -7
- {codejury-0.17.1 → codejury-0.19.0}/codejury/diff/engine.py +6 -6
- {codejury-0.17.1 → codejury-0.19.0}/codejury/diff/findings_filter.py +2 -21
- {codejury-0.17.1 → codejury-0.19.0}/codejury/diff/prompts.py +5 -5
- {codejury-0.17.1 → codejury-0.19.0}/codejury/diff/runner.py +1 -1
- codejury-0.19.0/codejury/diff/vulnerabilities.py +75 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/domain/__init__.py +1 -1
- codejury-0.19.0/codejury/guides.py +120 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/mddoc.py +10 -8
- {codejury-0.17.1 → codejury-0.19.0}/codejury/providers/__init__.py +1 -1
- codejury-0.19.0/codejury/repo/model.py +103 -0
- codejury-0.19.0/codejury/repo/scaffold.py +204 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/resources.py +4 -2
- codejury-0.19.0/codejury.egg-info/PKG-INFO +147 -0
- codejury-0.19.0/codejury.egg-info/SOURCES.txt +97 -0
- {codejury-0.17.1 → codejury-0.19.0}/pyproject.toml +1 -1
- codejury-0.19.0/tests/test_detection.py +35 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_diff_engine.py +3 -3
- codejury-0.19.0/tests/test_guides.py +56 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_repo_model.py +14 -3
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_repo_scaffold.py +45 -8
- codejury-0.17.1/tests/test_rules.py → codejury-0.19.0/tests/test_vulnerabilities.py +31 -31
- codejury-0.17.1/PKG-INFO +0 -135
- codejury-0.17.1/README.md +0 -104
- codejury-0.17.1/codejury/data/methodology/repo-review.md +0 -140
- codejury-0.17.1/codejury/data/rules/SKILL.md +0 -58
- codejury-0.17.1/codejury/diff/rules.py +0 -74
- codejury-0.17.1/codejury/guides.py +0 -81
- codejury-0.17.1/codejury/repo/model.py +0 -61
- codejury-0.17.1/codejury/repo/scaffold.py +0 -117
- codejury-0.17.1/codejury.egg-info/PKG-INFO +0 -135
- codejury-0.17.1/codejury.egg-info/SOURCES.txt +0 -83
- codejury-0.17.1/tests/test_guides.py +0 -34
- {codejury-0.17.1 → codejury-0.19.0}/LICENSE +0 -0
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/business-logic.md +0 -0
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/command-injection.md +0 -0
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/hardcoded-secrets.md +0 -0
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/jwt-validation.md +0 -0
- {codejury-0.17.1/codejury/data/rules → codejury-0.19.0/codejury/data/vulnerabilities}/missing-authorization.md +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/diff/__init__.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/domain/finding.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/json_parse.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/providers/anthropic.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/providers/base.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/providers/factory.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/providers/litellm.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/providers/mock.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/providers/openai.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/providers/openai_format.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/providers/retry.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/repo/__init__.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury/report.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury.egg-info/dependency_links.txt +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury.egg-info/entry_points.txt +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury.egg-info/requires.txt +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/codejury.egg-info/top_level.txt +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/setup.cfg +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_anthropic_provider.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_cli_audit.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_diff_debate.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_json_parse.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_litellm_provider.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_mddoc.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_openai_format.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_openai_provider.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_report.py +0 -0
- {codejury-0.17.1 → codejury-0.19.0}/tests/test_retry_provider.py +0 -0
codejury-0.19.0/PKG-INFO
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codejury
|
|
3
|
+
Version: 0.19.0
|
|
4
|
+
Summary: AI code security review: an adversarial diff-audit engine and an agent-driven whole-repo review methodology, with security knowledge as rich rules
|
|
5
|
+
Author: AISecLabs
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/aiseclabs/codejury
|
|
8
|
+
Project-URL: Repository, https://github.com/aiseclabs/codejury
|
|
9
|
+
Keywords: security,appsec,static analysis,llm,owasp,asvs,code review
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Security
|
|
13
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: pyyaml>=6.0
|
|
20
|
+
Requires-Dist: json-repair>=0.30
|
|
21
|
+
Provides-Extra: anthropic
|
|
22
|
+
Requires-Dist: anthropic>=0.40; extra == "anthropic"
|
|
23
|
+
Provides-Extra: openai
|
|
24
|
+
Requires-Dist: openai>=1.0; extra == "openai"
|
|
25
|
+
Provides-Extra: litellm
|
|
26
|
+
Requires-Dist: litellm>=1.0; extra == "litellm"
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
29
|
+
Requires-Dist: jsonschema>=4.0; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
██████╗ ██████╗ ██████╗ ███████╗ ██╗██╗ ██╗██████╗ ██╗ ██╗
|
|
34
|
+
██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██║██║ ██║██╔══██╗╚██╗ ██╔╝
|
|
35
|
+
██║ ██║ ██║██║ ██║█████╗ ██║██║ ██║██████╔╝ ╚████╔╝
|
|
36
|
+
██║ ██║ ██║██║ ██║██╔══╝ ██ ██║██║ ██║██╔══██╗ ╚██╔╝
|
|
37
|
+
╚██████╗╚██████╔╝██████╔╝███████╗╚█████╔╝╚██████╔╝██║ ██║ ██║
|
|
38
|
+
╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> AI code security review for diffs and whole repositories.
|
|
42
|
+
|
|
43
|
+
It runs two paths matched to their nature.
|
|
44
|
+
|
|
45
|
+
- **Diff Review** is coded. It audits a pull request diff for newly introduced
|
|
46
|
+
exploitable risk, as a single balanced LLM call or an adversarial Finder,
|
|
47
|
+
Challenger, and Judge pass that trades roughly 3x the cost for extra recall on
|
|
48
|
+
subtle flaws that span files.
|
|
49
|
+
- **Repo Review** is agent driven. It is a methodology an interactive agent such
|
|
50
|
+
as Claude Code or Codex runs to map a codebase attack surface, trace inputs to
|
|
51
|
+
sinks across files, verify issues with a real PoC, and iterate over rounds with
|
|
52
|
+
a persistent memory. A whole repository is too large for one LLM call, so it
|
|
53
|
+
ships the methodology and scaffolds the workspace instead of running a
|
|
54
|
+
pipeline.
|
|
55
|
+
|
|
56
|
+
Security knowledge lives in rich vulnerability classes under `codejury/data/vulnerabilities/*.md`, with a
|
|
57
|
+
vulnerable and a secure example per language, injected into the audit prompt
|
|
58
|
+
rather than buried in code.
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install codejury # core
|
|
64
|
+
pip install "codejury[anthropic]" # add a backend, also openai or litellm
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Diff Review
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# audit a diff file
|
|
71
|
+
codejury review diff --diff-file changes.diff
|
|
72
|
+
|
|
73
|
+
# audit a git range in a repo
|
|
74
|
+
codejury review diff --repo /path/to/app --git-range origin/main...HEAD
|
|
75
|
+
|
|
76
|
+
# from stdin
|
|
77
|
+
git diff HEAD~1 | codejury review diff
|
|
78
|
+
|
|
79
|
+
# adversarial mode, more recall on subtle flaws, about 3x the cost
|
|
80
|
+
codejury review diff --diff-file changes.diff --mode adversarial
|
|
81
|
+
|
|
82
|
+
# CI gate and SARIF
|
|
83
|
+
codejury review diff --diff-file changes.diff --format sarif --fail-on high
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Configure a backend with `--provider`, `--model`, `--api-key`, `--api-base`, or
|
|
87
|
+
the `CODEJURY_API_KEY`, `CODEJURY_MODEL`, and `CODEJURY_API_BASE` environment
|
|
88
|
+
variables. `codejury review diff --dry-run` exercises the engine with a mock
|
|
89
|
+
provider and no key, and falls back to a built in demo diff when you pass none.
|
|
90
|
+
|
|
91
|
+
### Choosing a Model and Mode
|
|
92
|
+
|
|
93
|
+
Detection quality is dominated by the model first, then the mode. On real diff
|
|
94
|
+
probes:
|
|
95
|
+
|
|
96
|
+
- A strong model at the Claude Sonnet tier in standard mode caught every planted
|
|
97
|
+
vulnerability with almost no false positives. A weaker model raised false
|
|
98
|
+
positives in both modes, so the model is the lever that matters most.
|
|
99
|
+
- Adversarial mode did not lower false positives over standard on those probes
|
|
100
|
+
and costs about 3x. Reach for it to gain recall on subtle logic that spans
|
|
101
|
+
files, not as a way to cut false positives.
|
|
102
|
+
|
|
103
|
+
Default to standard mode with a strong model, set with `--model` or
|
|
104
|
+
`CODEJURY_MODEL`. False positives are held down by the do not report list and the
|
|
105
|
+
post filter, not by the mode.
|
|
106
|
+
|
|
107
|
+
### Use in CI with GitHub Actions
|
|
108
|
+
|
|
109
|
+
Audit every pull request and surface findings in the code scanning tab. Copy
|
|
110
|
+
`examples/codejury-pr-review.yml` into `.github/workflows/`, add a
|
|
111
|
+
`CODEJURY_API_KEY` repository secret, and it will
|
|
112
|
+
|
|
113
|
+
1. diff the pull request against its base with `--git-range origin/<base>...HEAD`,
|
|
114
|
+
2. write SARIF and upload it with `github/codeql-action/upload-sarif`,
|
|
115
|
+
3. fail the check on a HIGH or CRITICAL finding with `--fail-on high`.
|
|
116
|
+
|
|
117
|
+
The job makes one model call per pull request in standard mode. The SARIF is
|
|
118
|
+
uploaded even when the gate fails, so findings always show up on the pull
|
|
119
|
+
request.
|
|
120
|
+
|
|
121
|
+
## Repo Review
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
codejury review repo /path/to/your/repo
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This scaffolds a review workspace with `entrypoints/`, `issues/`, `analysis/`,
|
|
128
|
+
and a `security-review-memory.md`, seeds the entrypoint inventory from a
|
|
129
|
+
deterministic scan, and prints the methodology. Run it with an interactive agent.
|
|
130
|
+
It reads the methodology and the vulnerability classes, maps the attack surface, traces inputs to
|
|
131
|
+
sinks across files, records high confidence issues with a PoC, and asks you to
|
|
132
|
+
confirm credentials or false positives along the way. Nothing runs against
|
|
133
|
+
production.
|
|
134
|
+
|
|
135
|
+
## Findings
|
|
136
|
+
|
|
137
|
+
Each finding carries a file and line, a severity and category, a concrete exploit
|
|
138
|
+
scenario, a recommendation, and a confidence. A false positive filter drops test
|
|
139
|
+
paths, mock paths, and low confidence noise. The model is also told not to report
|
|
140
|
+
dependency CVEs, style notes, speculation, or risks that only matter when
|
|
141
|
+
production config leaks.
|
|
142
|
+
|
|
143
|
+
## Extending
|
|
144
|
+
|
|
145
|
+
Add a vulnerability class by dropping a new file `codejury/data/vulnerabilities/<class>.md`
|
|
146
|
+
with the standard frontmatter of title, impact, tags, and triggers plus a
|
|
147
|
+
vulnerable and a secure example. It is data, no code change needed.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
```
|
|
2
|
+
██████╗ ██████╗ ██████╗ ███████╗ ██╗██╗ ██╗██████╗ ██╗ ██╗
|
|
3
|
+
██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██║██║ ██║██╔══██╗╚██╗ ██╔╝
|
|
4
|
+
██║ ██║ ██║██║ ██║█████╗ ██║██║ ██║██████╔╝ ╚████╔╝
|
|
5
|
+
██║ ██║ ██║██║ ██║██╔══╝ ██ ██║██║ ██║██╔══██╗ ╚██╔╝
|
|
6
|
+
╚██████╗╚██████╔╝██████╔╝███████╗╚█████╔╝╚██████╔╝██║ ██║ ██║
|
|
7
|
+
╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
> AI code security review for diffs and whole repositories.
|
|
11
|
+
|
|
12
|
+
It runs two paths matched to their nature.
|
|
13
|
+
|
|
14
|
+
- **Diff Review** is coded. It audits a pull request diff for newly introduced
|
|
15
|
+
exploitable risk, as a single balanced LLM call or an adversarial Finder,
|
|
16
|
+
Challenger, and Judge pass that trades roughly 3x the cost for extra recall on
|
|
17
|
+
subtle flaws that span files.
|
|
18
|
+
- **Repo Review** is agent driven. It is a methodology an interactive agent such
|
|
19
|
+
as Claude Code or Codex runs to map a codebase attack surface, trace inputs to
|
|
20
|
+
sinks across files, verify issues with a real PoC, and iterate over rounds with
|
|
21
|
+
a persistent memory. A whole repository is too large for one LLM call, so it
|
|
22
|
+
ships the methodology and scaffolds the workspace instead of running a
|
|
23
|
+
pipeline.
|
|
24
|
+
|
|
25
|
+
Security knowledge lives in rich vulnerability classes under `codejury/data/vulnerabilities/*.md`, with a
|
|
26
|
+
vulnerable and a secure example per language, injected into the audit prompt
|
|
27
|
+
rather than buried in code.
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install codejury # core
|
|
33
|
+
pip install "codejury[anthropic]" # add a backend, also openai or litellm
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Diff Review
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# audit a diff file
|
|
40
|
+
codejury review diff --diff-file changes.diff
|
|
41
|
+
|
|
42
|
+
# audit a git range in a repo
|
|
43
|
+
codejury review diff --repo /path/to/app --git-range origin/main...HEAD
|
|
44
|
+
|
|
45
|
+
# from stdin
|
|
46
|
+
git diff HEAD~1 | codejury review diff
|
|
47
|
+
|
|
48
|
+
# adversarial mode, more recall on subtle flaws, about 3x the cost
|
|
49
|
+
codejury review diff --diff-file changes.diff --mode adversarial
|
|
50
|
+
|
|
51
|
+
# CI gate and SARIF
|
|
52
|
+
codejury review diff --diff-file changes.diff --format sarif --fail-on high
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Configure a backend with `--provider`, `--model`, `--api-key`, `--api-base`, or
|
|
56
|
+
the `CODEJURY_API_KEY`, `CODEJURY_MODEL`, and `CODEJURY_API_BASE` environment
|
|
57
|
+
variables. `codejury review diff --dry-run` exercises the engine with a mock
|
|
58
|
+
provider and no key, and falls back to a built in demo diff when you pass none.
|
|
59
|
+
|
|
60
|
+
### Choosing a Model and Mode
|
|
61
|
+
|
|
62
|
+
Detection quality is dominated by the model first, then the mode. On real diff
|
|
63
|
+
probes:
|
|
64
|
+
|
|
65
|
+
- A strong model at the Claude Sonnet tier in standard mode caught every planted
|
|
66
|
+
vulnerability with almost no false positives. A weaker model raised false
|
|
67
|
+
positives in both modes, so the model is the lever that matters most.
|
|
68
|
+
- Adversarial mode did not lower false positives over standard on those probes
|
|
69
|
+
and costs about 3x. Reach for it to gain recall on subtle logic that spans
|
|
70
|
+
files, not as a way to cut false positives.
|
|
71
|
+
|
|
72
|
+
Default to standard mode with a strong model, set with `--model` or
|
|
73
|
+
`CODEJURY_MODEL`. False positives are held down by the do not report list and the
|
|
74
|
+
post filter, not by the mode.
|
|
75
|
+
|
|
76
|
+
### Use in CI with GitHub Actions
|
|
77
|
+
|
|
78
|
+
Audit every pull request and surface findings in the code scanning tab. Copy
|
|
79
|
+
`examples/codejury-pr-review.yml` into `.github/workflows/`, add a
|
|
80
|
+
`CODEJURY_API_KEY` repository secret, and it will
|
|
81
|
+
|
|
82
|
+
1. diff the pull request against its base with `--git-range origin/<base>...HEAD`,
|
|
83
|
+
2. write SARIF and upload it with `github/codeql-action/upload-sarif`,
|
|
84
|
+
3. fail the check on a HIGH or CRITICAL finding with `--fail-on high`.
|
|
85
|
+
|
|
86
|
+
The job makes one model call per pull request in standard mode. The SARIF is
|
|
87
|
+
uploaded even when the gate fails, so findings always show up on the pull
|
|
88
|
+
request.
|
|
89
|
+
|
|
90
|
+
## Repo Review
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
codejury review repo /path/to/your/repo
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
This scaffolds a review workspace with `entrypoints/`, `issues/`, `analysis/`,
|
|
97
|
+
and a `security-review-memory.md`, seeds the entrypoint inventory from a
|
|
98
|
+
deterministic scan, and prints the methodology. Run it with an interactive agent.
|
|
99
|
+
It reads the methodology and the vulnerability classes, maps the attack surface, traces inputs to
|
|
100
|
+
sinks across files, records high confidence issues with a PoC, and asks you to
|
|
101
|
+
confirm credentials or false positives along the way. Nothing runs against
|
|
102
|
+
production.
|
|
103
|
+
|
|
104
|
+
## Findings
|
|
105
|
+
|
|
106
|
+
Each finding carries a file and line, a severity and category, a concrete exploit
|
|
107
|
+
scenario, a recommendation, and a confidence. A false positive filter drops test
|
|
108
|
+
paths, mock paths, and low confidence noise. The model is also told not to report
|
|
109
|
+
dependency CVEs, style notes, speculation, or risks that only matter when
|
|
110
|
+
production config leaks.
|
|
111
|
+
|
|
112
|
+
## Extending
|
|
113
|
+
|
|
114
|
+
Add a vulnerability class by dropping a new file `codejury/data/vulnerabilities/<class>.md`
|
|
115
|
+
with the standard frontmatter of title, impact, tags, and triggers plus a
|
|
116
|
+
vulnerable and a secure example. It is data, no code change needed.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""AI code security review tool.
|
|
2
2
|
|
|
3
3
|
Two paths matched to their nature: a coded diff-audit engine (standard single
|
|
4
4
|
call or adversarial Finder/Challenger/Judge), and a whole-repo review run as a
|
|
5
5
|
methodology by an interactive agent. Security knowledge lives in rich markdown
|
|
6
|
-
|
|
6
|
+
vulnerability classes (data/vulnerabilities) injected into the audit prompt, not
|
|
7
|
+
in a rendered schema.
|
|
7
8
|
"""
|
|
8
9
|
|
|
9
10
|
from importlib.metadata import PackageNotFoundError, version
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# File and path classification, across ecosystems: what the engine treats as a
|
|
2
|
+
# source file, a dependency manifest, a noise directory, or test code. Kept here
|
|
3
|
+
# so the implementation enumerates no language itself, adding a language is a
|
|
4
|
+
# data edit. This is distinct from a guide's stack detection, which decides which
|
|
5
|
+
# language, framework, or protocol applies.
|
|
6
|
+
|
|
7
|
+
skip_dirs: [".git", ".venv", "venv", "node_modules", "__pycache__", ".mypy_cache", ".pytest_cache"]
|
|
8
|
+
|
|
9
|
+
source_extensions: [".py", ".js", ".ts", ".tsx", ".jsx", ".mjs", ".go", ".rb", ".java", ".kt", ".php", ".cs", ".scala", ".rs"]
|
|
10
|
+
|
|
11
|
+
config_extensions: [".yaml", ".yml", ".toml", ".ini", ".cfg", ".conf", ".env"]
|
|
12
|
+
|
|
13
|
+
manifests: ["requirements.txt", "requirements-dev.txt", "pyproject.toml", "setup.py", "Pipfile", "package.json", "go.mod", "Gemfile", "pom.xml", "build.gradle", "Cargo.toml", "composer.json"]
|
|
14
|
+
|
|
15
|
+
test_dirs: ["test", "tests", "__tests__", "__mocks__", "mocks", "fixtures", "testdata", "e2e", "spec", "specs"]
|
|
16
|
+
|
|
17
|
+
test_name_patterns: ["test_*", "*_test.*", "*.test.*", "*.spec.*"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: echo
|
|
3
|
+
title: Echo
|
|
4
|
+
kind: framework
|
|
5
|
+
language: go
|
|
6
|
+
detect:
|
|
7
|
+
manifest: ["labstack/echo"]
|
|
8
|
+
imports: ["github.com/labstack/echo"]
|
|
9
|
+
entrypoint_files: ["*main.go", "*/handlers/*.go", "*/handler/*.go", "*/api/*.go", "*/routes/*.go", "*/controllers/*.go"]
|
|
10
|
+
entrypoint_markers: ["echo.New(", "echo.Context", "e.GET", "e.POST", ".GET(", ".POST(", ".Group(", "c.Param", "c.QueryParam", "c.Bind"]
|
|
11
|
+
logic_layers: ["*/service/*.go", "*/services/*.go", "*/usecase/*.go", "*/repository/*.go", "*/repo/*.go", "*/store/*.go", "*/dao/*.go", "*/model/*.go"]
|
|
12
|
+
---
|
|
13
|
+
# Echo Review Notes
|
|
14
|
+
|
|
15
|
+
## Entrypoints
|
|
16
|
+
- Handlers have the signature `func(c echo.Context) error`, registered with
|
|
17
|
+
`e.GET`, `.POST`, and grouped under `e.Group`. Input comes from `c.Param`,
|
|
18
|
+
`c.QueryParam`, `c.FormValue`, `c.Request().Header`, and `c.Bind` into a struct.
|
|
19
|
+
|
|
20
|
+
## Authorization / IDOR
|
|
21
|
+
- Auth is middleware, applied globally, on a `Group`, or per route. The flaw to
|
|
22
|
+
hunt is a route registered outside the authenticated group, inheriting no
|
|
23
|
+
check. Compare grouped routes against routes on the bare instance.
|
|
24
|
+
- IDOR: a record loaded by `c.Param("id")` with no owner or tenant scope.
|
|
25
|
+
|
|
26
|
+
## Common Sinks / Gotchas
|
|
27
|
+
- SQL: `fmt.Sprintf` into `db.Query` or `db.Exec`, instead of placeholders.
|
|
28
|
+
- Command: `exec.Command` built from input.
|
|
29
|
+
- Path: `c.File` or `c.Attachment` and `filepath.Join` on a path from input.
|
|
30
|
+
- `c.Bind` into a struct with privileged fields is mass assignment.
|
|
31
|
+
- A returned `error` that the caller drops can hide a failed auth or validation.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: gin
|
|
3
|
+
title: Gin
|
|
4
|
+
kind: framework
|
|
5
|
+
language: go
|
|
6
|
+
detect:
|
|
7
|
+
manifest: ["gin-gonic/gin"]
|
|
8
|
+
imports: ["github.com/gin-gonic/gin"]
|
|
9
|
+
entrypoint_files: ["*main.go", "*/handlers/*.go", "*/handler/*.go", "*/api/*.go", "*/routes/*.go", "*/controllers/*.go"]
|
|
10
|
+
entrypoint_markers: ["gin.Default(", "gin.New(", "*gin.Context", "router.GET", "router.POST", ".GET(", ".POST(", ".Group(", "c.Param", "c.Query", "c.ShouldBind"]
|
|
11
|
+
logic_layers: ["*/service/*.go", "*/services/*.go", "*/usecase/*.go", "*/repository/*.go", "*/repo/*.go", "*/store/*.go", "*/dao/*.go", "*/model/*.go"]
|
|
12
|
+
---
|
|
13
|
+
# Gin Review Notes
|
|
14
|
+
|
|
15
|
+
## Entrypoints
|
|
16
|
+
- Handlers have the signature `func(c *gin.Context)`, registered with
|
|
17
|
+
`router.GET`, `.POST`, and grouped under `router.Group`. Input comes from
|
|
18
|
+
`c.Param`, `c.Query`, `c.PostForm`, `c.GetHeader`, and `c.ShouldBindJSON` or
|
|
19
|
+
`c.Bind` into a struct.
|
|
20
|
+
|
|
21
|
+
## Authorization / IDOR
|
|
22
|
+
- Auth is middleware, applied globally, on a `Group`, or per route. The classic
|
|
23
|
+
flaw is a route registered outside the authenticated group, so it inherits no
|
|
24
|
+
check. Compare a group's routes against the routes registered on the bare
|
|
25
|
+
engine.
|
|
26
|
+
- IDOR: a record loaded by `c.Param("id")` with no owner or tenant scope.
|
|
27
|
+
|
|
28
|
+
## Common Sinks / Gotchas
|
|
29
|
+
- SQL: `fmt.Sprintf` into `db.Query` or `db.Exec`, instead of placeholders.
|
|
30
|
+
- Command: `exec.Command` built from input.
|
|
31
|
+
- Path: `c.File` or `filepath.Join` on a path from input, the traversal sink.
|
|
32
|
+
- `c.ShouldBindJSON` into a struct with privileged fields is mass assignment.
|
|
33
|
+
- A handler that ignores the error from a bind or an auth call proceeds as if it
|
|
34
|
+
passed.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: express
|
|
3
|
+
title: Express
|
|
4
|
+
kind: framework
|
|
5
|
+
language: javascript
|
|
6
|
+
detect:
|
|
7
|
+
manifest: ["express"]
|
|
8
|
+
imports: ["require('express')", "require(\"express\")", "from 'express'"]
|
|
9
|
+
entrypoint_files: ["*app.js", "*server.js", "*app.ts", "*server.ts", "*/routes/*.js", "*/routes/*.ts", "*/controllers/*.js", "*/controllers/*.ts", "*router*.js", "*router*.ts"]
|
|
10
|
+
entrypoint_markers: ["express()", "app.get(", "app.post(", "app.use(", "router.get(", "router.post(", ".get(", ".post(", "req.params", "req.query", "req.body"]
|
|
11
|
+
logic_layers: ["*/services/*.js", "*/services/*.ts", "*/models/*.js", "*/models/*.ts", "*/repositories/*.js", "*/repositories/*.ts", "*/dao/*.js", "*/dao/*.ts"]
|
|
12
|
+
---
|
|
13
|
+
# Express Review Notes
|
|
14
|
+
|
|
15
|
+
Works the same in JavaScript and TypeScript. See the JavaScript guide for the
|
|
16
|
+
runtime sinks.
|
|
17
|
+
|
|
18
|
+
## Entrypoints
|
|
19
|
+
- Routes are `app.get` / `app.post` / `router.*`, and a `Router` mounted with
|
|
20
|
+
`app.use("/prefix", router)`. The handler is `(req, res, next)`. Input is
|
|
21
|
+
`req.params`, `req.query`, `req.body`, `req.headers`, and `req.cookies`.
|
|
22
|
+
|
|
23
|
+
## Authorization / IDOR
|
|
24
|
+
- Auth is middleware, passed to `app.use` or per route. The flaw to hunt is a
|
|
25
|
+
route mounted before the auth middleware, or one that omits the middleware its
|
|
26
|
+
siblings have, so order and placement matter.
|
|
27
|
+
- IDOR: a record loaded by `req.params.id` with no owner or tenant scope.
|
|
28
|
+
|
|
29
|
+
## Common Sinks / Gotchas
|
|
30
|
+
- SQL and NoSQL: a query built by string concatenation, or a Mongo filter built
|
|
31
|
+
straight from `req.body`, the operator-injection sink.
|
|
32
|
+
- Command: `child_process.exec` from input. Code: `eval` from input.
|
|
33
|
+
- Path: `res.sendFile` or `path.join` on a path from input, the traversal sink.
|
|
34
|
+
- Open redirect via `res.redirect(req.query...)`, and prototype pollution from a
|
|
35
|
+
body merge.
|
|
36
|
+
- A body spread whole into a model or an ORM create is mass assignment.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: nestjs
|
|
3
|
+
title: NestJS
|
|
4
|
+
kind: framework
|
|
5
|
+
language: javascript
|
|
6
|
+
detect:
|
|
7
|
+
manifest: ["@nestjs/core", "@nestjs/common"]
|
|
8
|
+
imports: ["@nestjs/common", "@nestjs/core"]
|
|
9
|
+
entrypoint_files: ["*.controller.ts", "*.controller.js", "*/controllers/*.ts", "*.resolver.ts", "*.gateway.ts"]
|
|
10
|
+
entrypoint_markers: ["@Controller(", "@Get(", "@Post(", "@Put(", "@Delete(", "@Body(", "@Param(", "@Query(", "@UseGuards("]
|
|
11
|
+
logic_layers: ["*.service.ts", "*.service.js", "*/services/*.ts", "*.repository.ts", "*/repositories/*.ts", "*.entity.ts", "*/dao/*.ts"]
|
|
12
|
+
---
|
|
13
|
+
# NestJS Review Notes
|
|
14
|
+
|
|
15
|
+
Usually TypeScript on Node. See the JavaScript and TypeScript guides for the
|
|
16
|
+
runtime sinks and for why types do not sanitize input.
|
|
17
|
+
|
|
18
|
+
## Entrypoints
|
|
19
|
+
- A `@Controller` class with `@Get` / `@Post` methods. Input binds through
|
|
20
|
+
`@Param`, `@Query`, `@Body`, and `@Headers`. GraphQL resolvers and WebSocket
|
|
21
|
+
gateways are entrypoints too.
|
|
22
|
+
|
|
23
|
+
## Authorization / IDOR
|
|
24
|
+
- Access control is a guard applied with `@UseGuards`, at the controller or the
|
|
25
|
+
method, plus role decorators. The flaw to hunt is a route or controller missing
|
|
26
|
+
the guard its siblings declare, and a guard that authenticates but does not
|
|
27
|
+
authorize the specific resource.
|
|
28
|
+
- IDOR: a handler that loads by `@Param("id")` with no owner or tenant check.
|
|
29
|
+
|
|
30
|
+
## Common Sinks / Gotchas
|
|
31
|
+
- Mass assignment: a `@Body` DTO with no `ValidationPipe` and `whitelist: true`
|
|
32
|
+
binds any field the client sends. Confirm the pipe is global or applied.
|
|
33
|
+
- SQL: a TypeORM or Prisma raw query built from input.
|
|
34
|
+
- SSRF: a server-side `fetch` or `axios` to a URL from input.
|
|
35
|
+
- A custom guard that returns true on an unhandled path, or reads the user from a
|
|
36
|
+
header the client controls.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: celery
|
|
3
|
+
title: Celery
|
|
4
|
+
kind: framework
|
|
5
|
+
language: python
|
|
6
|
+
detect:
|
|
7
|
+
imports: ["celery", "shared_task"]
|
|
8
|
+
entrypoint_files: ["*tasks.py", "*/tasks/*.py"]
|
|
9
|
+
entrypoint_markers: ["@shared_task", "@app.task", "@celery_app.task", "@periodic_task", ".delay(", ".apply_async(", "crontab("]
|
|
10
|
+
---
|
|
11
|
+
# Celery Review Notes
|
|
12
|
+
|
|
13
|
+
A task is an entrypoint, not just glue. Its arguments are attacker-influenced
|
|
14
|
+
whenever the enqueue site passes request input through, so review a task the same
|
|
15
|
+
way as an HTTP handler. The web view that calls `.delay()` or `.apply_async()` is
|
|
16
|
+
the producer, and the task body is where the value lands.
|
|
17
|
+
|
|
18
|
+
## Entrypoints
|
|
19
|
+
- Task definitions in `tasks.py` or a `tasks/` package, marked by `@shared_task`,
|
|
20
|
+
`@app.task`, or `@celery_app.task`. Periodic tasks wired by `crontab()` or a
|
|
21
|
+
beat schedule run with no caller, so their inputs are config or stored state.
|
|
22
|
+
- Trace each task back to its `.delay(...)` and `.apply_async(...)` callers to see
|
|
23
|
+
which arguments are user-controlled.
|
|
24
|
+
|
|
25
|
+
## What to Hunt
|
|
26
|
+
- A task that fetches a URL, runs a command, opens a file path, or renders a
|
|
27
|
+
template from an argument, the same sink classes as a web handler, now reached
|
|
28
|
+
off the request cycle.
|
|
29
|
+
- Authorization re-check. A producer that checked the caller does not carry that
|
|
30
|
+
identity into the task, so a task that acts on a resource by an id in its
|
|
31
|
+
arguments needs its own owner or tenant check.
|
|
32
|
+
- Secret and token exposure. A task that logs full request headers, a response
|
|
33
|
+
body, or a fetched credential leaks it into worker logs. See the
|
|
34
|
+
information-exposure vulnerability class.
|
|
35
|
+
- Replayable or duplicate enqueue. A task with a side effect that is enqueued from
|
|
36
|
+
an unauthenticated or replayable producer runs more than once.
|
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
id: django
|
|
3
3
|
title: Django
|
|
4
4
|
kind: framework
|
|
5
|
+
language: python
|
|
5
6
|
detect:
|
|
6
7
|
files: ["*urls.py", "manage.py", "*settings.py"]
|
|
7
8
|
manifest: ["django"]
|
|
8
9
|
imports: ["from django", "import django"]
|
|
9
|
-
entrypoint_files: ["*urls.py"]
|
|
10
|
+
entrypoint_files: ["*urls.py", "*views.py", "*viewsets.py", "*/views/*.py", "*serializers.py", "*api.py", "*consumers.py"]
|
|
11
|
+
entrypoint_markers: ["APIView", "ViewSet", "@api_view", "@action", "router.register", "path(", "re_path(", "as_view("]
|
|
12
|
+
logic_layers: ["*/controllers/*.py", "*controllers.py", "*/managers/*.py", "*managers.py", "*/dao/*.py", "*dao.py", "*/services/*.py", "*services.py", "*/models/*.py", "*models.py"]
|
|
10
13
|
---
|
|
11
|
-
# Django
|
|
14
|
+
# Django Review Notes
|
|
12
15
|
|
|
13
16
|
## Entrypoints
|
|
14
17
|
- Routes live in `urls.py`: `path()` / `re_path()` map a URL to a view.
|
|
@@ -18,14 +21,14 @@ entrypoint_files: ["*urls.py"]
|
|
|
18
21
|
signals, and middleware.
|
|
19
22
|
|
|
20
23
|
## Authorization / IDOR
|
|
21
|
-
- Auth is enforced by decorators
|
|
24
|
+
- Auth is enforced by decorators such as `@login_required`, DRF permission classes, or
|
|
22
25
|
middleware. Note where it is and where it is missing.
|
|
23
|
-
- Classic IDOR shape: `Model.objects.get(pk=<user input>)`
|
|
26
|
+
- Classic IDOR shape: `Model.objects.get(pk=<user input>)` or `filter(id=...)`
|
|
24
27
|
with no owner/tenant scoping, then returned to the caller. Inspect every object
|
|
25
28
|
fetch keyed by a user-supplied id.
|
|
26
29
|
|
|
27
|
-
## Common
|
|
30
|
+
## Common Sinks / Gotchas
|
|
28
31
|
- SQL: `.raw()`, `.extra()`, `RawSQL`, or string-built SQL via `connection.cursor()`.
|
|
29
32
|
- Templates: `mark_safe`, `|safe`, `format_html` on unescaped user input, autoescape off.
|
|
30
|
-
- `
|
|
31
|
-
a
|
|
33
|
+
- Settings: `DEBUG=True` leaks internals, a hardcoded `SECRET_KEY`. Untrusted
|
|
34
|
+
deserialization is a language-level sink, see the Python guide.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: fastapi
|
|
3
|
+
title: FastAPI
|
|
4
|
+
kind: framework
|
|
5
|
+
language: python
|
|
6
|
+
detect:
|
|
7
|
+
manifest: ["fastapi"]
|
|
8
|
+
imports: ["from fastapi", "import fastapi"]
|
|
9
|
+
entrypoint_files: ["*main.py", "*/routers/*.py", "*/api/*.py", "*api.py", "*routes.py", "*/endpoints/*.py"]
|
|
10
|
+
entrypoint_markers: ["FastAPI(", "APIRouter(", "@app.get", "@app.post", "@router.get", "@router.post", "Depends("]
|
|
11
|
+
logic_layers: ["*/services/*.py", "*services.py", "*/models/*.py", "*models.py", "*/repositories/*.py", "*/crud/*.py", "*/dao/*.py"]
|
|
12
|
+
---
|
|
13
|
+
# FastAPI Review Notes
|
|
14
|
+
|
|
15
|
+
## Entrypoints
|
|
16
|
+
- Path operations decorated with `@app.get` / `@app.post` or `@router.*` on an
|
|
17
|
+
`APIRouter`. Inputs arrive as path and query parameters, and as a request body
|
|
18
|
+
validated by a Pydantic model.
|
|
19
|
+
- A Pydantic model bounds the body's shape, but an over-wide model still binds
|
|
20
|
+
privileged fields, the mass-assignment shape.
|
|
21
|
+
|
|
22
|
+
## Authorization / IDOR
|
|
23
|
+
- Auth and access control run through `Depends`, for example a dependency that
|
|
24
|
+
resolves the current user or checks a scope. Note an endpoint that omits the
|
|
25
|
+
dependency its siblings use, or a dependency that authenticates but does not
|
|
26
|
+
authorize the specific resource.
|
|
27
|
+
- IDOR: an endpoint that loads a record by an id parameter with no owner or tenant
|
|
28
|
+
check.
|
|
29
|
+
|
|
30
|
+
## Common Sinks / Gotchas
|
|
31
|
+
- SQL: a raw query or an ORM `text()` built from a parameter.
|
|
32
|
+
- SSRF: `httpx` or `requests` to a URL from input, common in webhook and fetch
|
|
33
|
+
endpoints.
|
|
34
|
+
- Path: `FileResponse` on a path from input.
|
|
35
|
+
- `CORSMiddleware` with `allow_origins=["*"]` together with credentials, and an
|
|
36
|
+
OAuth2 bearer dependency that decodes a token without verifying signature,
|
|
37
|
+
audience, and expiry.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: flask
|
|
3
|
+
title: Flask
|
|
4
|
+
kind: framework
|
|
5
|
+
language: python
|
|
6
|
+
detect:
|
|
7
|
+
manifest: ["flask"]
|
|
8
|
+
imports: ["from flask", "import flask"]
|
|
9
|
+
entrypoint_files: ["*app.py", "*views.py", "*routes.py", "*/views/*.py", "*/blueprints/*.py", "*api.py"]
|
|
10
|
+
entrypoint_markers: ["@app.route", ".route(", "Blueprint(", "add_url_rule(", "MethodView", "@app.before_request"]
|
|
11
|
+
logic_layers: ["*/services/*.py", "*services.py", "*/models/*.py", "*models.py", "*/repositories/*.py", "*/dao/*.py"]
|
|
12
|
+
---
|
|
13
|
+
# Flask Review Notes
|
|
14
|
+
|
|
15
|
+
## Entrypoints
|
|
16
|
+
- Routes are functions decorated with `@app.route` or `@bp.route`, or registered
|
|
17
|
+
with `add_url_rule`. Blueprints mount a group under a URL prefix. Class views
|
|
18
|
+
subclass `MethodView`.
|
|
19
|
+
- Read input from `request.args`, `request.form`, `request.values`,
|
|
20
|
+
`request.json`, `request.files`, `request.headers`, and `request.cookies`, all
|
|
21
|
+
attacker-controlled.
|
|
22
|
+
|
|
23
|
+
## Authorization / IDOR
|
|
24
|
+
- Auth is enforced by a `@login_required` style decorator, a `before_request`
|
|
25
|
+
hook, or an explicit check in the view. Note where it is and where a route
|
|
26
|
+
lacks it.
|
|
27
|
+
- IDOR: a model fetched by an id from the request with no owner or tenant scope,
|
|
28
|
+
then returned.
|
|
29
|
+
|
|
30
|
+
## Common Sinks / Gotchas
|
|
31
|
+
- SSTI: `render_template_string` on input, or `Markup` and `|safe` on unescaped
|
|
32
|
+
input.
|
|
33
|
+
- SQL: raw `cursor.execute` or an ORM `text()` built from input.
|
|
34
|
+
- Path: `send_file` or `send_from_directory` with a path from input, the traversal
|
|
35
|
+
sink.
|
|
36
|
+
- A hardcoded `SECRET_KEY`, `debug=True` in production, and an open redirect via
|
|
37
|
+
`redirect(request.args[...])`.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: go
|
|
3
|
+
title: Go
|
|
4
|
+
kind: language
|
|
5
|
+
detect:
|
|
6
|
+
files: ["*.go", "go.mod"]
|
|
7
|
+
entrypoint_files: ["*main.go", "*/handlers/*.go", "*/handler/*.go", "*/api/*.go", "*/routes/*.go"]
|
|
8
|
+
entrypoint_markers: ["http.HandleFunc", "http.ListenAndServe", "ServeMux", "http.Handler", "func(w http.ResponseWriter"]
|
|
9
|
+
logic_layers: ["*/service/*.go", "*/services/*.go", "*/usecase/*.go", "*/repository/*.go", "*/repo/*.go", "*/store/*.go", "*/dao/*.go", "*/model/*.go", "*/models/*.go"]
|
|
10
|
+
---
|
|
11
|
+
# Go Review Notes
|
|
12
|
+
|
|
13
|
+
Where untrusted input enters beyond web routes, which the framework guides cover.
|
|
14
|
+
The standard `net/http` server is itself an entrypoint: a handler that takes an
|
|
15
|
+
`http.ResponseWriter` and an `*http.Request`, registered with `http.HandleFunc`
|
|
16
|
+
or a `ServeMux`. Read the request through `r.URL.Query`, `r.FormValue`, `r.PathValue`,
|
|
17
|
+
`r.Header`, and the decoded body, all attacker-controlled.
|
|
18
|
+
|
|
19
|
+
## Common Sinks
|
|
20
|
+
- SQL: a query built with `fmt.Sprintf` or string concatenation passed to
|
|
21
|
+
`db.Query` or `db.Exec`. Use placeholders, never build SQL from input.
|
|
22
|
+
- Command: `exec.Command` with a shell or with arguments built from input,
|
|
23
|
+
`os/exec` reaching `sh -c`.
|
|
24
|
+
- Path: `filepath.Join` or `os.Open` on a path from input with no `filepath.Clean`
|
|
25
|
+
and containment check, the traversal sink.
|
|
26
|
+
- SSRF: `http.Get`, `http.NewRequest`, or a client `Do` on a URL from input.
|
|
27
|
+
- Deserialization and templates: `encoding/gob`, `text/template` rendering input,
|
|
28
|
+
and `html/template` used with the wrong escaping context.
|
|
29
|
+
|
|
30
|
+
## Gotchas
|
|
31
|
+
- Errors ignored with `_` can skip a security check whose failure is never seen.
|
|
32
|
+
- A type assertion or `interface{}` body decoded with `json.Unmarshal` into a
|
|
33
|
+
wide struct is mass assignment if privileged fields are bound.
|
|
34
|
+
- Goroutines and shared state without a lock are a race, relevant to one-time
|
|
35
|
+
tokens and balances.
|