@xenos1996/usat 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +335 -0
- package/USAT.md +596 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +438 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +72 -0
- package/dist/config.js.map +1 -0
- package/dist/detect/index.d.ts +58 -0
- package/dist/detect/index.d.ts.map +1 -0
- package/dist/detect/index.js +329 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/engine/audit.d.ts +21 -0
- package/dist/engine/audit.d.ts.map +1 -0
- package/dist/engine/audit.js +295 -0
- package/dist/engine/audit.js.map +1 -0
- package/dist/engine/diff.d.ts +24 -0
- package/dist/engine/diff.d.ts.map +1 -0
- package/dist/engine/diff.js +136 -0
- package/dist/engine/diff.js.map +1 -0
- package/dist/engine/evaluate.d.ts +19 -0
- package/dist/engine/evaluate.d.ts.map +1 -0
- package/dist/engine/evaluate.js +377 -0
- package/dist/engine/evaluate.js.map +1 -0
- package/dist/engine/gate.d.ts +19 -0
- package/dist/engine/gate.d.ts.map +1 -0
- package/dist/engine/gate.js +47 -0
- package/dist/engine/gate.js.map +1 -0
- package/dist/engine/loader.d.ts +22 -0
- package/dist/engine/loader.d.ts.map +1 -0
- package/dist/engine/loader.js +360 -0
- package/dist/engine/loader.js.map +1 -0
- package/dist/engine/maturity.d.ts +20 -0
- package/dist/engine/maturity.d.ts.map +1 -0
- package/dist/engine/maturity.js +157 -0
- package/dist/engine/maturity.js.map +1 -0
- package/dist/engine/score.d.ts +19 -0
- package/dist/engine/score.d.ts.map +1 -0
- package/dist/engine/score.js +141 -0
- package/dist/engine/score.js.map +1 -0
- package/dist/engine/sections.d.ts +14 -0
- package/dist/engine/sections.d.ts.map +1 -0
- package/dist/engine/sections.js +50 -0
- package/dist/engine/sections.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/report/markdown.d.ts +16 -0
- package/dist/report/markdown.d.ts.map +1 -0
- package/dist/report/markdown.js +488 -0
- package/dist/report/markdown.js.map +1 -0
- package/dist/types.d.ts +282 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/util/glob.d.ts +11 -0
- package/dist/util/glob.d.ts.map +1 -0
- package/dist/util/glob.js +86 -0
- package/dist/util/glob.js.map +1 -0
- package/dist/util/project.d.ts +72 -0
- package/dist/util/project.d.ts.map +1 -0
- package/dist/util/project.js +586 -0
- package/dist/util/project.js.map +1 -0
- package/dist/util/yaml.d.ts +28 -0
- package/dist/util/yaml.d.ts.map +1 -0
- package/dist/util/yaml.js +48 -0
- package/dist/util/yaml.js.map +1 -0
- package/docs/ARCHITECTURE.md +119 -0
- package/docs/README.md +27 -0
- package/docs/adr/0001-record-architecture-decisions.md +35 -0
- package/docs/adr/0002-typescript-engine-over-python.md +49 -0
- package/docs/adr/0003-rules-are-data-not-code.md +50 -0
- package/docs/adr/0004-markdown-only-output.md +41 -0
- package/docs/adr/0005-maturity-dampens-severity.md +56 -0
- package/docs/adr/0006-severity-status-two-axes.md +48 -0
- package/docs/adr/0007-suppressions-are-visible-and-expiring.md +46 -0
- package/docs/adr/0008-report-trailer-and-diff.md +48 -0
- package/docs/adr/0009-fail-closed-on-malformed-input.md +56 -0
- package/docs/adr/0010-detector-design.md +54 -0
- package/docs/adr/0011-coexist-with-deep-scanners.md +52 -0
- package/docs/adr/README.md +32 -0
- package/docs/agent-integration.md +129 -0
- package/docs/ci-integration.md +163 -0
- package/docs/concepts.md +196 -0
- package/docs/configuration.md +105 -0
- package/docs/detectors.md +186 -0
- package/docs/getting-started.md +99 -0
- package/docs/maturity-profiles.md +156 -0
- package/docs/reference/api.md +193 -0
- package/docs/reference/cli.md +412 -0
- package/docs/rule-packs.md +278 -0
- package/docs/standards-mapping.md +171 -0
- package/package.json +96 -0
- package/rules/core/architecture.yaml +190 -0
- package/rules/core/cicd.yaml +212 -0
- package/rules/core/code-quality.yaml +261 -0
- package/rules/core/dependencies.yaml +132 -0
- package/rules/core/documentation.yaml +119 -0
- package/rules/core/future-readiness.yaml +91 -0
- package/rules/core/release.yaml +131 -0
- package/rules/core/repo.yaml +303 -0
- package/rules/core/security.yaml +494 -0
- package/rules/core/supply-chain.yaml +357 -0
- package/rules/core/testing.yaml +260 -0
- package/rules/detectors.yaml +2255 -0
- package/rules/index.yaml +41 -0
- package/rules/profiles/maturity.yaml +135 -0
- package/rules/stacks/ai-era.yaml +193 -0
- package/rules/stacks/api-backend.yaml +121 -0
- package/rules/stacks/cli.yaml +105 -0
- package/rules/stacks/compliance.yaml +157 -0
- package/rules/stacks/containers.yaml +124 -0
- package/rules/stacks/data.yaml +165 -0
- package/rules/stacks/go.yaml +134 -0
- package/rules/stacks/iac.yaml +128 -0
- package/rules/stacks/jvm.yaml +150 -0
- package/rules/stacks/ml-ai.yaml +140 -0
- package/rules/stacks/mobile.yaml +121 -0
- package/rules/stacks/node-typescript.yaml +166 -0
- package/rules/stacks/python.yaml +175 -0
- package/rules/stacks/rust.yaml +129 -0
- package/rules/stacks/solidity.yaml +139 -0
- package/rules/stacks/web-frontend.yaml +159 -0
- package/templates/AGENTS.audit.md +135 -0
- package/templates/AUDIT_REPORT.md +155 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# Writing rule packs
|
|
2
|
+
|
|
3
|
+
A rule pack is one YAML file. Register it in `rules/index.yaml`, and USAT decides at
|
|
4
|
+
audit time whether it applies.
|
|
5
|
+
|
|
6
|
+
```yaml
|
|
7
|
+
id: stacks/mobile
|
|
8
|
+
title: Mobile (iOS / Android / Cross-platform)
|
|
9
|
+
section: S15
|
|
10
|
+
section_title: Platform-Specific
|
|
11
|
+
description: 'Activated when iOS, Android, React Native, Expo, or Flutter is detected.'
|
|
12
|
+
version: '1.0'
|
|
13
|
+
skip_when: # skip the WHOLE pack when true
|
|
14
|
+
all:
|
|
15
|
+
- { fact: 'platform:mobile', op: 'absent' }
|
|
16
|
+
- { fact: 'platform:ios', op: 'absent' }
|
|
17
|
+
- { fact: 'platform:android', op: 'absent' }
|
|
18
|
+
provides: ['platform:mobile'] # facts this pack asserts
|
|
19
|
+
rules:
|
|
20
|
+
- id: MOB-001
|
|
21
|
+
title: Crash reporting is integrated
|
|
22
|
+
section: S15
|
|
23
|
+
section_title: Platform-Specific
|
|
24
|
+
severity: HIGH
|
|
25
|
+
class: operations
|
|
26
|
+
applies_when: { fact: 'maturity:beta' } # optional per-rule gating
|
|
27
|
+
depths: [standard, deep] # optional
|
|
28
|
+
check:
|
|
29
|
+
kind: grep_present
|
|
30
|
+
pattern: '(Crashlytics|Sentry|BugSnag|Instabug)'
|
|
31
|
+
include: ['**/*.{ts,tsx,js,json,plist,xml,gradle,swift,kt}']
|
|
32
|
+
exclude: ['**/node_modules/**', '**/Pods/**']
|
|
33
|
+
flags: i
|
|
34
|
+
why: "On mobile you cannot watch the user's screen."
|
|
35
|
+
evidence: 'Where tokens/PII live: Keychain/Keystore, not AsyncStorage.'
|
|
36
|
+
remediation: 'Add Crashlytics or Sentry with dSYM upload.'
|
|
37
|
+
references: ['OWASP-MASVS-STORAGE-2']
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Pack fields
|
|
41
|
+
|
|
42
|
+
| Field | Required | Notes |
|
|
43
|
+
| --------------- | -------- | ----------------------------------------------------- |
|
|
44
|
+
| `id` | ✅ | Convention: `core/<name>` or `stacks/<name>` |
|
|
45
|
+
| `title` | ✅ | |
|
|
46
|
+
| `section` | | Default section for rules that omit one |
|
|
47
|
+
| `section_title` | | |
|
|
48
|
+
| `description` | | Shown by `usat rules` |
|
|
49
|
+
| `skip_when` | | Predicate; pack is skipped when **true** |
|
|
50
|
+
| `provides` | | Facts to add when the pack applies — lets packs chain |
|
|
51
|
+
| `rules` | ✅ | |
|
|
52
|
+
|
|
53
|
+
## Rule fields
|
|
54
|
+
|
|
55
|
+
| Field | Required | Notes |
|
|
56
|
+
| -------------- | -------- | -------------------------------------------------------- |
|
|
57
|
+
| `id` | ✅ | Convention: `<PREFIX>-<NNN>`, e.g. `SEC-007` |
|
|
58
|
+
| `title` | ✅ | Imperative and specific: "Tokens and sessions expire" |
|
|
59
|
+
| `section` | ✅ | `S1`…`S16` |
|
|
60
|
+
| `severity` | ✅ | `CRITICAL` \| `HIGH` \| `MEDIUM` \| `LOW` \| `FUTURE` |
|
|
61
|
+
| `class` | ✅ | See below |
|
|
62
|
+
| `check` | ✅ | See below |
|
|
63
|
+
| `weight` | | Overrides the severity default |
|
|
64
|
+
| `applies_when` | | Predicate over detected facts |
|
|
65
|
+
| `depths` | | `[quick]` / `[standard]` / `[deep]`; omit for all |
|
|
66
|
+
| `why` | | Shown in the report and the judgement queue |
|
|
67
|
+
| `evidence` | | **Required for `manual` checks** — what proof looks like |
|
|
68
|
+
| `remediation` | | The fix |
|
|
69
|
+
| `references` | | Standard IDs: `CWE-89`, `ASVS-5.3.4`, `OWASP-LLM01:2026` |
|
|
70
|
+
| `tags` | | Free-form |
|
|
71
|
+
|
|
72
|
+
### `class` drives dampening
|
|
73
|
+
|
|
74
|
+
`security` · `supply-chain` · `correctness` · `maintainability` · `operations` ·
|
|
75
|
+
`performance` · `compliance` · `documentation` · `style`
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Check kinds
|
|
80
|
+
|
|
81
|
+
### `manual` — needs a human or an agent
|
|
82
|
+
|
|
83
|
+
```yaml
|
|
84
|
+
check: { kind: manual }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Produces ❓ NEEDS REVIEW and lands in the judgement queue. Always pair with
|
|
88
|
+
`evidence:` — it is the prompt the reviewer works from.
|
|
89
|
+
|
|
90
|
+
### `file_exists` / `file_absent`
|
|
91
|
+
|
|
92
|
+
```yaml
|
|
93
|
+
check: { kind: file_exists, files: ['.gitignore'] }
|
|
94
|
+
check: { kind: file_absent, files: ['.env', '*.pem'] }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`file_absent` fails with locations when something is found.
|
|
98
|
+
|
|
99
|
+
### `any_file`
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
check:
|
|
103
|
+
kind: any_file
|
|
104
|
+
patterns: ['README.md', 'readme.md', 'README.rst']
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### `grep_present` / `grep_absent`
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
check:
|
|
111
|
+
kind: grep_present # PASS when found
|
|
112
|
+
pattern: '(zod|joi|pydantic|class-validator)'
|
|
113
|
+
include: ['**/*.{ts,tsx,js,jsx,py,go}']
|
|
114
|
+
exclude: ['**/*.test.*', '**/node_modules/**']
|
|
115
|
+
flags: i # i = case-insensitive
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`grep_absent` inverts it: any hit is a FAIL **with file:line locations** — this is
|
|
119
|
+
the workhorse for "no hardcoded secrets", "no `shell=True`", "no `http://`".
|
|
120
|
+
|
|
121
|
+
### `grep_wrong` / `grep_deprecated`
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
check:
|
|
125
|
+
kind: grep_wrong # hits → ⚠️ WRONG
|
|
126
|
+
pattern: 'catch\s*\(\s*\w*\s*\)\s*\{\s*\}'
|
|
127
|
+
|
|
128
|
+
check:
|
|
129
|
+
kind: grep_deprecated # hits → 💀 DEPRECATED
|
|
130
|
+
pattern: 'new Buffer\s*\('
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Use `grep_wrong` for "present but done incorrectly" — the status auditors most often
|
|
134
|
+
miss (Rule 9).
|
|
135
|
+
|
|
136
|
+
### `tracked_present` / `tracked_absent`
|
|
137
|
+
|
|
138
|
+
Asks **git** what is tracked, not what is on disk. Use for committed build output,
|
|
139
|
+
committed `.env`, committed model weights — anything whose presence in the working
|
|
140
|
+
tree is normal but whose presence in git is a bug.
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
check:
|
|
144
|
+
kind: tracked_absent
|
|
145
|
+
patterns: ['dist/**', 'node_modules/**', '.env', '**/*.pt']
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `count_min`
|
|
149
|
+
|
|
150
|
+
```yaml
|
|
151
|
+
check:
|
|
152
|
+
kind: count_min
|
|
153
|
+
patterns: ['**/*.test.{ts,tsx}', '**/test_*.py']
|
|
154
|
+
min: 5
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### `file_lines_max`
|
|
158
|
+
|
|
159
|
+
```yaml
|
|
160
|
+
check:
|
|
161
|
+
kind: file_lines_max
|
|
162
|
+
patterns: ['src/**/*.ts']
|
|
163
|
+
max_lines: 800
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Any hit is ⚠️ WRONG with the line count. A cheap proxy for god objects.
|
|
167
|
+
|
|
168
|
+
### `json_path`
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
check:
|
|
172
|
+
kind: json_path
|
|
173
|
+
file: 'package.json'
|
|
174
|
+
path: 'engines.node'
|
|
175
|
+
equals: '>=20'
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`equals` omitted ⇒ PASS when the key is merely set. Works on JSON (JSONC tolerated).
|
|
179
|
+
|
|
180
|
+
### `command`
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
check:
|
|
184
|
+
kind: command
|
|
185
|
+
run: '! npm audit --production --audit-level=high | grep -qiE "critical|high"'
|
|
186
|
+
expect_exit: 0
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Skipped unless `--allow-commands`** — reported as ❓ NEEDS REVIEW otherwise.
|
|
190
|
+
USAT never shells out without being asked.
|
|
191
|
+
|
|
192
|
+
### `info`
|
|
193
|
+
|
|
194
|
+
Context only, never scored. Useful for explaining a section to a reader.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Predicates
|
|
199
|
+
|
|
200
|
+
```yaml
|
|
201
|
+
applies_when: { fact: 'has:database' }
|
|
202
|
+
|
|
203
|
+
applies_when:
|
|
204
|
+
any:
|
|
205
|
+
- { fact: 'lang:typescript' }
|
|
206
|
+
- { fact: 'lang:javascript' }
|
|
207
|
+
|
|
208
|
+
applies_when:
|
|
209
|
+
all:
|
|
210
|
+
- { fact: 'maturity:production' }
|
|
211
|
+
- { not: { fact: 'project:library' } }
|
|
212
|
+
|
|
213
|
+
# Numeric facts use metric:
|
|
214
|
+
applies_when: { fact: 'metric:contributors', op: 'gt', value: 2 }
|
|
215
|
+
applies_when: { fact: 'metric:tags', op: 'exists' }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Operators: `exists` (default) · `absent` · `eq` · `neq` · `in` · `includes` · `gt` · `lt` · `matches`
|
|
219
|
+
|
|
220
|
+
Combinators: `all` · `any` · `not`
|
|
221
|
+
|
|
222
|
+
### Fail-closed contracts (the engine does not guess)
|
|
223
|
+
|
|
224
|
+
Malformed input warns at load time and evaluates conservatively — see
|
|
225
|
+
ADR-0009. What to know as an author:
|
|
226
|
+
|
|
227
|
+
- `in` / `includes` compare **metric** values against the list. On flag
|
|
228
|
+
facts they are always false: presence alone never satisfies a value
|
|
229
|
+
comparison.
|
|
230
|
+
- `matches` compiles `value` as a regex; an invalid regex warns and the
|
|
231
|
+
predicate is false. Unknown operators and unknown predicate keys behave
|
|
232
|
+
the same way (rule skipped, warning on stderr).
|
|
233
|
+
- An empty grep `pattern` drops the rule with a warning — `new RegExp('')`
|
|
234
|
+
matches every line, so a missing pattern would otherwise FAIL (or PASS)
|
|
235
|
+
the whole repo.
|
|
236
|
+
- Duplicate rule IDs across packs: first definition wins, later ones warn.
|
|
237
|
+
- Override `severity` must be on the ladder and `weight` a finite number
|
|
238
|
+
≥ 0, or the override is ignored with a warning. Run `node
|
|
239
|
+
scripts/check-docs.mjs`-adjacent `usat rules` after editing: the shipped
|
|
240
|
+
packs must load with **zero warnings** (enforced by `tests/e2e.test.ts`).
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Available facts
|
|
245
|
+
|
|
246
|
+
Run `usat detect .` on any project to see them. Namespaces:
|
|
247
|
+
|
|
248
|
+
`lang:*` `pm:*` `fw:*` `project:*` `platform:*` `db:*` `orm:*` `auth:*` `test:*`
|
|
249
|
+
`ci:*` `infra:*` `api:*` `obs:*` `ai:*` `has:*` `doc:*` `practice:*` `maturity:*`
|
|
250
|
+
|
|
251
|
+
Metrics (use `metric:<name>`): `commits`, `contributors`, `tags`, `branches`,
|
|
252
|
+
`files`, `daysSinceLastCommit`.
|
|
253
|
+
|
|
254
|
+
Full catalogue: [detectors.md](detectors.md).
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Style guide for rule authors
|
|
259
|
+
|
|
260
|
+
1. **Title = the desired state**, not the defect. "Tokens and sessions expire", not "Missing token expiry".
|
|
261
|
+
2. **`why` earns the rule its place.** If you cannot say why in one sentence, cut the rule.
|
|
262
|
+
3. **`remediation` must be actionable.** "Improve security" is not a fix. "Set `SameSite=Lax` and require a CSRF token" is.
|
|
263
|
+
4. **`evidence` is the deliverable for manual checks.** It tells the reviewer exactly what to produce.
|
|
264
|
+
5. **Exclude tests and docs from security greps.** A rule that fires on its own documentation is a rule people will disable.
|
|
265
|
+
6. **Prefer `grep_wrong` over `grep_absent`** when the _pattern_ is fine but a specific usage is not.
|
|
266
|
+
7. **Cite the standard.** `CWE-89`, `ASVS-5.3.4`, `SLSA-Build-L2`, `OWASP-LLM01:2026`.
|
|
267
|
+
8. **Severity = worst realistic outcome**, not typical. Dampening handles context; the rule should not.
|
|
268
|
+
|
|
269
|
+
## Testing your pack
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
usat rules --section S15 # did it load?
|
|
273
|
+
usat explain MOB-001 # did it parse as intended?
|
|
274
|
+
usat audit . --include stacks/mobile --depth deep
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
A pack with a YAML syntax error is skipped with a warning on stderr — the audit never
|
|
278
|
+
crashes because of a bad rule file.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Standards mapping — how USAT compares to the state of the art
|
|
2
|
+
|
|
3
|
+
> _USAT did not invent most of these checks. It reorganised them so one tool can
|
|
4
|
+
> apply them to any project, at any stage, without a certification budget._
|
|
5
|
+
|
|
6
|
+
## The short version
|
|
7
|
+
|
|
8
|
+
| Framework | What it is | What USAT takes | What USAT adds |
|
|
9
|
+
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
10
|
+
| **OWASP ASVS 5.0** | ~350 verification requirements across 17 chapters, levels L1–L3 [1](https://quality.arc42.org/standards/owasp-asvs) | The requirement set behind most `SEC-*` rules; ASVS IDs in `references` | Executable versions of the mechanically-checkable subset; level selection replaced by maturity profiles |
|
|
11
|
+
| **OpenSSF Scorecard** | 18 automated checks, 0–10, run against public repos [1](https://rywalker.com/research/openssf-scorecard) | The shape of S3 and S8; score-per-check | Runs on private repos and monorepos; mixes in code-level checks; adds the other 15 sections |
|
|
12
|
+
| **NIST SSDF (SP 800-218)** | Secure-development practice outcomes | Practice-level outcomes: protect, produce well-secured software, respond to vulnerabilities | Concrete evidence requirements per outcome |
|
|
13
|
+
| **SLSA v1.2** | Build L0–L3 plus an approved Source track (Nov 2025) [1](https://rywalker.com/research/slsa) | Provenance, attestation, and source-integrity requirements | Progressive rules (SBOM now, attestation at production) rather than a level you claim |
|
|
14
|
+
| **OWASP LLM Top 10 (2026)** | LLM01–LLM10 for LLM applications [1](https://www.cybersaint.io/cybersecurity-frameworks-and-standards/glossary/what-is-the-owasp-top-10-for-llm-and-agentic-ai) | The entire S14 section | Executable detection of AI stacks so the section self-activates |
|
|
15
|
+
| **OWASP Agentic AI Top 10 (ASI, 2026)** | ASI01–ASI10 for agent systems [2](https://www.trydeepteam.com/docs/frameworks-owasp-top-10-for-agentic-applications) | Excessive agency, tool misuse, memory poisoning, inter-agent trust | Rules for `AGENTS.md`/`CLAUDE.md` as executable-ish instructions |
|
|
16
|
+
| **CII Best Practices** | Open-source project maturity badge | README/LICENSE/SECURITY/CONTRIBUTING baseline | Automated, no self-assessment questionnaire |
|
|
17
|
+
| **ISO/IEC 5055** | Automated code-quality measurement (security, reliability, performance, maintainability) | The four quality characteristics behind S4/S5 | Free, YAML, and diffable |
|
|
18
|
+
| **WCAG 2.2 AA** | Accessibility success criteria | S13 checks | Same criteria, expressed as things a reviewer can verify in ten minutes |
|
|
19
|
+
| **EU CRA** | Cyber-resilience obligations for products with digital elements | SBOM, vulnerability handling, provenance expectations | A roadmap toward the obligations, not an audit |
|
|
20
|
+
| **OWASP SAMM** | Organisational assurance programme | Maturity-by-dimension thinking | Applies to a repository, not an org |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Where USAT differs from the field
|
|
25
|
+
|
|
26
|
+
### 1 · It is stage-aware; they are not
|
|
27
|
+
|
|
28
|
+
ASVS asks you to pick L1/L2/L3 _before_ you start [2](https://www.securecodinghub.com/blog/owasp-asvs-developers-complete-guide).
|
|
29
|
+
Scorecard gives an absolute 0–10. Neither asks "how old is this project, and does
|
|
30
|
+
that matter?"
|
|
31
|
+
|
|
32
|
+
USAT detects the stage and dampens severity accordingly — while holding a hard floor
|
|
33
|
+
on CRITICAL. [maturity-profiles.md](maturity-profiles.md)
|
|
34
|
+
|
|
35
|
+
### 2 · It is agent-executable, not just human-readable
|
|
36
|
+
|
|
37
|
+
Every framework above is a document a human interprets. USAT ships:
|
|
38
|
+
|
|
39
|
+
- `rules/` — machine-readable versions of the same checks
|
|
40
|
+
- a deterministic engine that settles ~70% of them
|
|
41
|
+
- a **judgement queue** that tells an agent or reviewer exactly what evidence to produce
|
|
42
|
+
|
|
43
|
+
That split is the whole design. An LLM should not be asked to grep for `eval(`; it
|
|
44
|
+
should be asked whether authorisation is enforced per resource.
|
|
45
|
+
|
|
46
|
+
### 3 · It separates "absent" from "wrong"
|
|
47
|
+
|
|
48
|
+
Every framework above has a checkbox. None distinguishes 🚫 MISSING from ⚠️ WRONG —
|
|
49
|
+
yet wrong is worse, because it looks finished. USAT gives WRONG its own status, its
|
|
50
|
+
own check kind (`grep_wrong`), and a score of 0.15 rather than 0.00.
|
|
51
|
+
|
|
52
|
+
### 4 · It reports confidence alongside score
|
|
53
|
+
|
|
54
|
+
A 90/100 where only 40% of applicable rules could be verified is not a 90/100. USAT
|
|
55
|
+
prints confidence next to every dimension and marks unverifiable sections
|
|
56
|
+
_"— not verified"_ instead of silently awarding 10/10.
|
|
57
|
+
|
|
58
|
+
### 5 · It is diffable
|
|
59
|
+
|
|
60
|
+
Every report embeds a machine-readable trailer so `usat diff` turns the next audit
|
|
61
|
+
into a progress report: fixed, regressed, newly applicable, net movement. None of the
|
|
62
|
+
frameworks above give you a first-class way to show you improved.
|
|
63
|
+
|
|
64
|
+
### 6 · It covers the AI era as a first-class section
|
|
65
|
+
|
|
66
|
+
S14 is mapped to the OWASP LLM Top 10 (2026) and the OWASP Agentic AI Top 10 (ASI, 2026) — including risks that did not exist when the other frameworks were written:
|
|
67
|
+
excessive agency, unbounded consumption, RAG tenant leakage, memory/context poisoning,
|
|
68
|
+
and the fact that `AGENTS.md` is executable-ish instruction that commits like code.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Detailed mapping
|
|
73
|
+
|
|
74
|
+
### USAT section → standards
|
|
75
|
+
|
|
76
|
+
| USAT | ASVS 5.0 | SSDF | SLSA | Scorecard | Other |
|
|
77
|
+
| --------------------- | --------------------- | --------------- | ------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
78
|
+
| S1 Repository | — | PO.3, PS.1 | Source L1–L2 | Binary-Artifacts, License, Security-Policy | CII |
|
|
79
|
+
| S2 Security | V2–V14 (all chapters) | PW.1–PW.8, RV.1 | — | — | CWE, OWASP Top 10 |
|
|
80
|
+
| S3 Supply Chain | V14.1, V14.2 | PS.3, PO.3 | Build L1–L3, Source | Pinned-Dependencies, Vulnerabilities, Dangerous-Workflow, Token-Permissions, Signed-Releases, Branch-Protection | CRA Annex I |
|
|
81
|
+
| S4 Architecture | V1, V4 | PW.1 | — | — | ISO 5055 Maintainability |
|
|
82
|
+
| S5 Code Quality | V5, V7 | PW.7, PW.8 | — | — | ISO 5055 Reliability |
|
|
83
|
+
| S6 Data | V8, V5.3 | PW.4 | — | — | GDPR Art. 32 |
|
|
84
|
+
| S7 Testing | V1.1, V4.2 | RV.1.1, PW.8 | — | CI-Tests, Fuzzing | — |
|
|
85
|
+
| S8 CI/CD & Infra | V14.1 | PO.5, RV.3 | Build L2 | CI-Tests, Branch-Protection | DORA |
|
|
86
|
+
| S9 Release | V1.14 | PO.5, RV.2 | Build L2, Source L2 | Signed-Releases | SemVer |
|
|
87
|
+
| S10 Dependencies | V14.2 | PW.4, RV.1.1 | — | Vulnerabilities, Dependency-Update-Tool, Maintained | SPDX, Criticality Score |
|
|
88
|
+
| S11 Performance | V13 | — | — | — | ISO 5055 Performance |
|
|
89
|
+
| S12 Documentation | — | PS.1, PW.1 | — | — | CII |
|
|
90
|
+
| S13 A11y & Compliance | V14.4 (partly) | — | — | — | WCAG 2.2 AA, GDPR, CCPA, PCI-DSS 4.0 |
|
|
91
|
+
| S14 AI / LLM | — | — | — | — | OWASP LLM Top 10 (2026), OWASP ASI Top 10 (2026), NIST AI RMF, EU AI Act |
|
|
92
|
+
| S15 Platform | V-per-stack | — | — | — | MASVS, CIS Docker/K8s, SCWE |
|
|
93
|
+
| S16 Future | — | — | — | — | endoflife.date, FinOps |
|
|
94
|
+
|
|
95
|
+
### Representative rule → control
|
|
96
|
+
|
|
97
|
+
| Rule | Control |
|
|
98
|
+
| ------------------------------------------- | ------------------------------------------------------- |
|
|
99
|
+
| `SEC-001` No hardcoded credentials | ASVS 2.10.4 · CWE-798 · OWASP A02:2021 |
|
|
100
|
+
| `SEC-005` SQL not built by concatenation | ASVS 5.3.4 · CWE-89 · OWASP A03:2021 |
|
|
101
|
+
| `SEC-011` Modern adaptive password hash | ASVS 2.4.1 · CWE-916 |
|
|
102
|
+
| `SEC-025` Adaptive hash present where auth | ASVS 2.4.1 · CWE-916 |
|
|
103
|
+
| `SEC-015` Authorization per request | ASVS 4.2.1 · CWE-639 · OWASP A01:2021 |
|
|
104
|
+
| `SEC-013` No `alg:none` | ASVS 3.2.3 · CWE-347 |
|
|
105
|
+
| `SUP-001` Lockfile committed | OpenSSF Pinned-Dependencies · SSDF PS.3.2 · SLSA Source |
|
|
106
|
+
| `SUP-005` Dependency scanning in CI | OpenSSF Vulnerabilities · SSDF RV.1.1 |
|
|
107
|
+
| `SUP-008` No workflow script injection | OpenSSF Dangerous-Workflow · CWE-94 |
|
|
108
|
+
| `SUP-009` Least-privilege token permissions | OpenSSF Token-Permissions · SLSA Build L2 |
|
|
109
|
+
| `SUP-012` Default branch protected | OpenSSF Branch-Protection · SLSA Source L2 · SSDF PO.2 |
|
|
110
|
+
| `SUP-014` SBOM published | SLSA · SSDF PS.3.2 · EU CRA Annex I |
|
|
111
|
+
| `SUP-015` Provenance attestation | SLSA Build L2 (v1.2) |
|
|
112
|
+
| `TEST-002` Tests run in CI on PRs | OpenSSF CI-Tests · SSDF RV.1.1 |
|
|
113
|
+
| `CICD-004` Rollback rehearsed | DORA time-to-restore · SSDF RV.3 |
|
|
114
|
+
| `CICD-010` Backups **and** tested restores | SSDF RV.3 · CIS Control 11 |
|
|
115
|
+
| `CTNR-001` Container not running as root | CIS Docker 4.1 · CWE-250 |
|
|
116
|
+
| `IAC-001` No public buckets / `0.0.0.0/0` | CIS AWS 2.1.5 · CWE-284 |
|
|
117
|
+
| `SOLID-001` Reentrancy protection | SWC-107 · Consensys best practices |
|
|
118
|
+
| `AI-001` Prompt injection | OWASP LLM01:2026 · ASI01:2026 |
|
|
119
|
+
| `AI-003` Least-privilege agents | OWASP LLM03:2026 · ASI02/ASI03:2026 |
|
|
120
|
+
| `AI-005` Bounded consumption | OWASP LLM06:2026 · ASI08:2026 |
|
|
121
|
+
| `AI-007` RAG tenant isolation | OWASP LLM09:2026 · ASI06:2026 |
|
|
122
|
+
| `COMP-001` Keyboard accessibility | WCAG 2.1.1 · EN 301 549 |
|
|
123
|
+
| `COMP-007` Data subject rights | GDPR Art. 15/17 · CCPA |
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Deliberate gaps
|
|
128
|
+
|
|
129
|
+
Things USAT intentionally does **not** do. An audit tool that oversells is worse than
|
|
130
|
+
none.
|
|
131
|
+
|
|
132
|
+
| Not done | Why | Do this instead |
|
|
133
|
+
| ---------------------------- | -------------------------------------------------- | -------------------------------------------------------------- |
|
|
134
|
+
| **Penetration testing** | No dynamic analysis, no fuzzing, no exploit chains | OWASP ASVS L2/L3 assessment, a pentest |
|
|
135
|
+
| **Deep SAST** | Requires whole-program analysis | CodeQL, Semgrep, Snyk Code — USAT checks they are _configured_ |
|
|
136
|
+
| **CVE lookup** | Needs network + advisory databases | `npm audit`, `osv-scanner`, `trivy`, Dependabot |
|
|
137
|
+
| **Compliance certification** | Only an accredited auditor certifies | Use USAT as the evidence checklist, then certify |
|
|
138
|
+
| **Runtime/DAST** | Nothing is executed | OWASP ZAP, Burp, your staging environment |
|
|
139
|
+
| **Formal verification** | Out of scope for a checklist | Certora, Halmos, Kani |
|
|
140
|
+
| **Org-level maturity** | USAT audits repositories | OWASP SAMM for programmes |
|
|
141
|
+
|
|
142
|
+
### On Scorecard specifically
|
|
143
|
+
|
|
144
|
+
Scorecard is excellent and USAT's S3/S8 borrow its shape. Two honest caveats, both
|
|
145
|
+
documented by its own users: it measures **process hygiene, not code quality**, and
|
|
146
|
+
peer-reviewed research found **no clean correlation** between high scores and fewer
|
|
147
|
+
vulnerabilities [1](https://rywalker.com/research/openssf-scorecard). Scorecard also
|
|
148
|
+
needs a public repo and network access. USAT is the offline, code-level,
|
|
149
|
+
private-repo complement — run both.
|
|
150
|
+
|
|
151
|
+
### On SARIF
|
|
152
|
+
|
|
153
|
+
SARIF 2.1.0 is the right interchange format for static-analysis _results_, and most
|
|
154
|
+
SAST tools emit it. USAT reports are prose-oriented — a scored, prioritised document
|
|
155
|
+
for humans and agents, not a machine-ingestible findings stream. If you need to feed
|
|
156
|
+
results into a dashboard, that is a small renderer away
|
|
157
|
+
(`src/report/`); the internal model already carries file, line, severity, and rule
|
|
158
|
+
identity for every finding. Contributions welcome.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Sources
|
|
163
|
+
|
|
164
|
+
- [1](https://quality.arc42.org/standards/owasp-asvs) OWASP ASVS — version history, 17 chapters, cumulative L1–L3
|
|
165
|
+
- [2](https://www.securecodinghub.com/blog/owasp-asvs-developers-complete-guide) OWASP ASVS 5.0 — choosing a verification level
|
|
166
|
+
- [1](https://rywalker.com/research/openssf-scorecard) OpenSSF Scorecard — 18 checks, v5.5.0 (April 2026), and the caveats on what scores mean
|
|
167
|
+
- [1](https://rywalker.com/research/slsa) SLSA — spec v1.2 (Nov 2025), Build L0–L3, Source track approved
|
|
168
|
+
- [1](https://www.cybersaint.io/cybersecurity-frameworks-and-standards/glossary/what-is-the-owasp-top-10-for-llm-and-agentic-ai) OWASP Top 10 for LLM Applications, 2026 (LLM01–LLM10)
|
|
169
|
+
- [3](https://blog.ogwilliam.com/post/owasp-top-10-llm-applications-2026-whats-new) OWASP LLM Top 10 — 2025 vs 2026 changes
|
|
170
|
+
- [2](https://www.trydeepteam.com/docs/frameworks-owasp-top-10-for-agentic-applications) OWASP Top 10 for Agents, 2026 (ASI01–ASI10)
|
|
171
|
+
- [1](https://github.com/addyosmani/agent-skills/blob/main/CLAUDE.md) Agent Skills convention — `SKILL.md` + `references/`
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xenos1996/usat",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Universal Software Audit Template — an open-source, self-adapting audit framework for any project, any stack, any stage",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"usat": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./rules": "./rules/index.yaml"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"rules",
|
|
22
|
+
"templates",
|
|
23
|
+
"schema",
|
|
24
|
+
"docs",
|
|
25
|
+
"USAT.md",
|
|
26
|
+
"AGENTS.md",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"keywords": [
|
|
31
|
+
"audit",
|
|
32
|
+
"software-audit",
|
|
33
|
+
"security-audit",
|
|
34
|
+
"code-audit",
|
|
35
|
+
"code-review",
|
|
36
|
+
"openssf",
|
|
37
|
+
"owasp-asvs",
|
|
38
|
+
"slsa",
|
|
39
|
+
"sast",
|
|
40
|
+
"agent",
|
|
41
|
+
"llm",
|
|
42
|
+
"template",
|
|
43
|
+
"tech-debt",
|
|
44
|
+
"quality-gate"
|
|
45
|
+
],
|
|
46
|
+
"author": "",
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/Er-Sajan-PLG/software-auditing-template.git"
|
|
50
|
+
},
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/Er-Sajan-PLG/software-auditing-template/issues"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/Er-Sajan-PLG/software-auditing-template#readme",
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=20.0.0"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsc -p tsconfig.json",
|
|
60
|
+
"usat": "node --experimental-strip-types src/cli.ts",
|
|
61
|
+
"lint": "eslint .",
|
|
62
|
+
"lint:fix": "eslint . --fix",
|
|
63
|
+
"format": "prettier --write .",
|
|
64
|
+
"format:check": "prettier --check .",
|
|
65
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
66
|
+
"test": "vitest run",
|
|
67
|
+
"test:watch": "vitest",
|
|
68
|
+
"test:cov": "vitest run --coverage",
|
|
69
|
+
"self-audit": "npm run build && node dist/cli.js audit . --out AUDIT.md",
|
|
70
|
+
"prepublishOnly": "npm run build"
|
|
71
|
+
},
|
|
72
|
+
"lint-staged": {
|
|
73
|
+
"*.{js,ts,mjs,cjs}": [
|
|
74
|
+
"eslint --fix",
|
|
75
|
+
"prettier --write"
|
|
76
|
+
],
|
|
77
|
+
"*.{json,md,yaml,yml}": [
|
|
78
|
+
"prettier --write"
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
"dependencies": {
|
|
82
|
+
"yaml": "^2.6.1"
|
|
83
|
+
},
|
|
84
|
+
"devDependencies": {
|
|
85
|
+
"@eslint/js": "^10.0.1",
|
|
86
|
+
"@types/node": "^26.4.1",
|
|
87
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
88
|
+
"eslint": "^10.10.0",
|
|
89
|
+
"husky": "^9.1.7",
|
|
90
|
+
"lint-staged": "^17.5.0",
|
|
91
|
+
"prettier": "^3.4.2",
|
|
92
|
+
"typescript": "^5.7.3",
|
|
93
|
+
"typescript-eslint": "^8.20.0",
|
|
94
|
+
"vitest": "^5.0.0"
|
|
95
|
+
}
|
|
96
|
+
}
|