@clear-capabilities/agentic-security-scanner 0.143.0 → 0.145.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/CHANGELOG.md +555 -0
- package/bin/agentic-security.js +770 -49
- package/dist/1.index.js +223 -0
- package/dist/113.index.js +117 -18
- package/dist/144.index.js +163 -0
- package/dist/178.index.js +24 -6
- package/dist/238.index.js +3 -2
- package/dist/265.index.js +191 -0
- package/dist/271.index.js +165 -0
- package/dist/384.index.js +1 -1
- package/dist/435.index.js +187 -52
- package/dist/444.index.js +11 -2
- package/dist/449.index.js +76 -12
- package/dist/526.index.js +117 -18
- package/dist/552.index.js +97 -0
- package/dist/637.index.js +27 -5
- package/dist/730.index.js +311 -0
- package/dist/736.index.js +301 -0
- package/dist/824.index.js +7 -0
- package/dist/905.index.js +88 -22
- package/dist/920.index.js +491 -0
- package/dist/970.index.js +173 -0
- package/dist/agentic-security.mjs +13 -13
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/dist/calibration-seed.json +2 -0
- package/package.json +23 -9
- package/src/compare.js +6 -1
- package/src/dataflow/CLAUDE.md +1 -1
- package/src/dataflow/index.js +18 -0
- package/src/dataflow/privacy-catalog.js +290 -0
- package/src/dataflow/privacy-deep-walker.js +515 -0
- package/src/dataflow/privacy-governance.js +126 -0
- package/src/dataflow/privacy-inventory.js +154 -0
- package/src/dataflow/privacy-sink-policy.js +125 -0
- package/src/dataflow/privacy-taint.js +115 -54
- package/src/dataflow/privacy-taxonomy.js +233 -0
- package/src/discovery/disprove.js +7 -3
- package/src/discovery/hunter.js +9 -5
- package/src/discovery/index.js +2 -2
- package/src/discovery/llm-invoke.js +69 -13
- package/src/egress/audit.js +147 -0
- package/src/egress/policy.js +313 -0
- package/src/egress/redact.js +180 -0
- package/src/engine.js +1048 -302
- package/src/fix/apply-fix-service.js +404 -0
- package/src/fix/approver-registry.js +157 -0
- package/src/history-scan.js +22 -5
- package/src/ir/CLAUDE.md +1 -1
- package/src/llm-validator/index.js +86 -9
- package/src/llm-validator/model-status.js +66 -0
- package/src/lsp/server.js +49 -2
- package/src/mcp/tools.js +177 -50
- package/src/pipeline/analyzer-supervisor.js +93 -0
- package/src/pipeline/analyzer-worker.js +26 -0
- package/src/pipeline/annotator-runner.js +33 -0
- package/src/pipeline/assurance-mode.js +154 -0
- package/src/pipeline/cascade-worker-pool.js +172 -0
- package/src/pipeline/cascade-worker.js +43 -0
- package/src/pipeline/coverage-ledger.js +0 -0
- package/src/pipeline/detector-runner.js +51 -0
- package/src/pipeline/enrichment-completion.js +58 -0
- package/src/pipeline/evidence-provenance.js +91 -0
- package/src/pipeline/finding-schema.js +108 -0
- package/src/pipeline/legacy-compat.js +101 -0
- package/src/pipeline/producer-collector.js +48 -0
- package/src/pipeline/producer-registry.js +112 -0
- package/src/pipeline/scan-health.js +144 -0
- package/src/posture/CLAUDE.md +123 -0
- package/src/posture/accuracy-scorecard.js +156 -1
- package/src/posture/adversary-agent.js +15 -3
- package/src/posture/artifact-registry.js +241 -0
- package/src/posture/auditor-walkthrough.js +186 -21
- package/src/posture/calibration-feedback.js +201 -0
- package/src/posture/calibration-seed.json +2 -0
- package/src/posture/calibration.js +25 -0
- package/src/posture/compliance-evidence-signing.js +131 -0
- package/src/posture/compliance-policy.js +324 -17
- package/src/posture/cross-repo-memory.js +7 -2
- package/src/posture/custom-rules.js +36 -0
- package/src/posture/deterministic.js +8 -1
- package/src/posture/encryption-provider.js +205 -0
- package/src/posture/evidence-grade-wording.js +71 -0
- package/src/posture/fix-history.js +137 -20
- package/src/posture/fix-honesty-gate.js +47 -6
- package/src/posture/fix-verify.js +65 -8
- package/src/posture/fleet.js +0 -0
- package/src/posture/flow-narration.js +7 -2
- package/src/posture/git-history.js +13 -5
- package/src/posture/legal-hold.js +140 -0
- package/src/posture/llm-redteam.js +10 -1
- package/src/posture/material-change.js +111 -2
- package/src/posture/mttr.js +75 -12
- package/src/posture/policy-bundle.js +274 -0
- package/src/posture/pre-incident-archaeology.js +39 -7
- package/src/posture/privacy-framework.js +47 -6
- package/src/posture/production-feedback.js +179 -0
- package/src/posture/provenance/ai-authorship.js +68 -0
- package/src/posture/provenance/branch-entry.js +80 -0
- package/src/posture/provenance/cache.js +143 -0
- package/src/posture/provenance/confidence.js +36 -0
- package/src/posture/provenance/coordinator.js +786 -0
- package/src/posture/provenance/dag-walk.js +249 -0
- package/src/posture/provenance/evidence-attribution.js +59 -0
- package/src/posture/provenance/git-evidence.js +310 -0
- package/src/posture/provenance/lifecycle.js +208 -0
- package/src/posture/provenance/missing-control-resolver.js +137 -0
- package/src/posture/provenance/origin-resolver.js +342 -0
- package/src/posture/provenance/predicate-replay.js +133 -0
- package/src/posture/provenance/providers/config.js +39 -0
- package/src/posture/provenance/providers/github.js +62 -0
- package/src/posture/provenance/providers/gitlab.js +58 -0
- package/src/posture/provenance/repo-lineage.js +74 -0
- package/src/posture/provenance/sca-origin.js +139 -0
- package/src/posture/provenance/schema.js +255 -0
- package/src/posture/provenance/transitive-sca.js +147 -0
- package/src/posture/provenance/validate.js +30 -0
- package/src/posture/provenance-evidence-bundle.js +144 -0
- package/src/posture/retention-policy.js +132 -0
- package/src/posture/risk-dollars.js +216 -26
- package/src/posture/sbom-diff.js +15 -2
- package/src/posture/scan-checkpoint.js +176 -31
- package/src/posture/secret-history.js +10 -2
- package/src/posture/state-dir.js +64 -5
- package/src/posture/state-lifecycle-report.js +77 -0
- package/src/posture/suppressions.js +59 -3
- package/src/posture/vuln-archaeology.js +8 -2
- package/src/pr-delta.js +25 -4
- package/src/privacy/ir-adapter.js +380 -0
- package/src/report/index.js +248 -5
- package/src/report/oscal.js +7 -2
- package/src/runScan.js +34 -5
- package/src/sast/cpp.js +3 -14
- package/src/sast/rate-limit.js +33 -3
- package/src/sca/llm-function-extract.js +6 -0
- package/src/util/git-hardening.js +128 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Hardening for every `git` subprocess call this scanner makes against a
|
|
2
|
+
// SCANNED repository it does not control — i.e. any git invocation whose
|
|
3
|
+
// `cwd` (or `-C <dir>`) is a project the scanner was asked to scan, as
|
|
4
|
+
// opposed to this project's own trusted checkout.
|
|
5
|
+
//
|
|
6
|
+
// Verified RCE (second independent Finding Provenance PRD audit,
|
|
7
|
+
// FR-PROV-024 / PRD Section 8 "never run repository hooks or untrusted
|
|
8
|
+
// build scripts"): git-evidence.js's `_run` invoked `git` with no config
|
|
9
|
+
// hardening at all. A hostile repo's `.git/config` can set `core.fsmonitor`
|
|
10
|
+
// to point at an attacker script; git executes it on an ordinary READ-ONLY
|
|
11
|
+
// command like `git status --porcelain` — no clone, no checkout, no
|
|
12
|
+
// deliberate command needed, just `getRepoState()` reading repo state.
|
|
13
|
+
// Reproduced against this exact repro shape before this module existed:
|
|
14
|
+
// `getRepoState()` alone wrote a marker file outside the repo.
|
|
15
|
+
//
|
|
16
|
+
// Four independent hostile-config surfaces, each closed by a different
|
|
17
|
+
// flag/env var (do not assume one covers another — a same-class RCE
|
|
18
|
+
// survived the first round of this hardening precisely because
|
|
19
|
+
// `--no-textconv` was assumed to cover `git diff` the same way it covers
|
|
20
|
+
// `git show`/`git log -p`/`git blame`, and it does not):
|
|
21
|
+
// - `core.fsmonitor` -> fires on `git status` (and other porcelain
|
|
22
|
+
// commands that consult the index). Closed by
|
|
23
|
+
// `-c core.fsmonitor=` (empty value disables it).
|
|
24
|
+
// - `core.hooksPath` -> redirects git's hook lookup to an
|
|
25
|
+
// attacker-controlled directory (pre-commit,
|
|
26
|
+
// post-checkout, ...). None of THIS module's
|
|
27
|
+
// read-only operations should fire a hook, but a
|
|
28
|
+
// caller elsewhere in the tree that does invoke a
|
|
29
|
+
// hook-shaped command (checkout, commit) inherits
|
|
30
|
+
// the same exposure — hardened uniformly rather
|
|
31
|
+
// than relying on each call site to reason about
|
|
32
|
+
// whether its own command can trigger a hook.
|
|
33
|
+
// Closed by `-c core.hooksPath=/dev/null`
|
|
34
|
+
// (verified: git tries to stat
|
|
35
|
+
// `/dev/null/<hookname>`, which is not a
|
|
36
|
+
// directory, so hook lookup fails closed — this
|
|
37
|
+
// is NOT relying on /dev/null being an empty
|
|
38
|
+
// *file*, it works because it isn't a directory).
|
|
39
|
+
// - `.gitattributes` -> a `diff=<name>` attribute + a matching
|
|
40
|
+
// textconv driver `diff.<name>.textconv` config key points a text
|
|
41
|
+
// filter at an attacker script; fires on any
|
|
42
|
+
// command that renders blob/diff CONTENT (`git
|
|
43
|
+
// show`/`git diff`/`git log -p`/`git log -L`/
|
|
44
|
+
// `git blame`) unless `--no-textconv` is passed.
|
|
45
|
+
// Verified per-subcommand: `git show -s` (no
|
|
46
|
+
// content shown) and `git show <sha>:<path>`
|
|
47
|
+
// (blob cat, not a diff) were NOT exploitable in
|
|
48
|
+
// this git version, but `git show -U0`, `git log
|
|
49
|
+
// -L`, and `git blame` all were.
|
|
50
|
+
// - `.git/config` / an EXTERNAL diff driver — `.gitattributes`
|
|
51
|
+
// `.gitattributes` `diff=<name>` + `.git/config [diff "<name>"]
|
|
52
|
+
// external diff driver command=<script>`, or the repo-local/global
|
|
53
|
+
// `diff.external` config key — is a DIFFERENT
|
|
54
|
+
// mechanism from the textconv driver above and is
|
|
55
|
+
// NOT closed by `--no-textconv`. VERIFIED: `git
|
|
56
|
+
// -c core.fsmonitor= -c core.hooksPath=/dev/null
|
|
57
|
+
// diff --unified=0 --no-textconv <ref>...HEAD`
|
|
58
|
+
// still runs the attacker's `diff.evil.command`
|
|
59
|
+
// script — `--no-textconv` only suppresses the
|
|
60
|
+
// TEXTCONV driver, and `git diff` (unlike `git
|
|
61
|
+
// show`/`git log -p`/`git blame`, which were all
|
|
62
|
+
// verified safe with just `--no-textconv`) honours
|
|
63
|
+
// an external diff driver by default regardless.
|
|
64
|
+
// Closed by `--no-ext-diff`, which must be passed
|
|
65
|
+
// explicitly on every `git diff` invocation (same
|
|
66
|
+
// reason `--no-textconv` isn't a `-c` flag: it's a
|
|
67
|
+
// diff-machinery option, not repo config). This
|
|
68
|
+
// was the live RCE a second review found after the
|
|
69
|
+
// first round of this hardening shipped —
|
|
70
|
+
// material-change.js's `classifyGitDiff` (the real
|
|
71
|
+
// entry point for `/scan --diff`) had
|
|
72
|
+
// `--no-textconv` but not `--no-ext-diff` and was
|
|
73
|
+
// still exploitable end-to-end.
|
|
74
|
+
//
|
|
75
|
+
// A FIFTH surface is known but not exploitable through any call site in this
|
|
76
|
+
// codebase today, so it is documented rather than closed: a `clean` smudge
|
|
77
|
+
// filter (`.gitattributes` `filter=<name>` + `filter.<name>.clean`) fires on
|
|
78
|
+
// a WORKTREE diff (e.g. `git diff --name-only HEAD` with no `<ref>` on the
|
|
79
|
+
// other side) and has no git flag to disable it at all (unlike textconv/
|
|
80
|
+
// ext-diff). Every `git diff` call site in this codebase diffs two refs
|
|
81
|
+
// (`<ref>...HEAD`), never the worktree against HEAD, so nothing here hits
|
|
82
|
+
// it — but a future worktree-diff call site would silently reintroduce this
|
|
83
|
+
// exact vulnerability class and must not assume `hardenGitArgs` covers it.
|
|
84
|
+
//
|
|
85
|
+
// `GIT_CONFIG_NOSYSTEM=1` additionally blocks a SYSTEM-level git config
|
|
86
|
+
// (outside any repository, e.g. /etc/gitconfig) from re-introducing a
|
|
87
|
+
// hostile setting the `-c` flags above didn't anticipate; `GIT_TERMINAL_PROMPT=0`
|
|
88
|
+
// stops a git invocation from ever blocking on an interactive credential
|
|
89
|
+
// prompt (a hostile repo pointing `origin`/a submodule at a URL that
|
|
90
|
+
// prompts). Both are environment variables, not `-c` flags — git does not
|
|
91
|
+
// expose either as repo-local config.
|
|
92
|
+
//
|
|
93
|
+
// Every `git` subprocess call this scanner makes against a scan target's
|
|
94
|
+
// repository MUST route its args through `hardenGitArgs` and its env
|
|
95
|
+
// through `hardenGitEnv`. A `git show`/`git diff`/`git log -p`/`git log -L`/
|
|
96
|
+
// `git blame` invocation must ALSO pass `--no-textconv` explicitly (it is
|
|
97
|
+
// not a `-c` config value, so it isn't folded into `GIT_HARDENED_CONFIG_ARGS`
|
|
98
|
+
// — it must appear in the invocation's own args, after the config args), and
|
|
99
|
+
// a `git diff` invocation must ADDITIONALLY pass `--no-ext-diff` (a
|
|
100
|
+
// different flag for a different surface — see above; `--no-textconv` does
|
|
101
|
+
// not imply it).
|
|
102
|
+
|
|
103
|
+
export const GIT_HARDENED_CONFIG_ARGS = Object.freeze([
|
|
104
|
+
'-c', 'core.fsmonitor=',
|
|
105
|
+
'-c', 'core.hooksPath=/dev/null',
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
export const GIT_HARDENED_ENV = Object.freeze({
|
|
109
|
+
GIT_CONFIG_NOSYSTEM: '1',
|
|
110
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Prepend the hardening `-c` flags to a git argv. These are GLOBAL options
|
|
114
|
+
// and must appear before the subcommand, which is why this always prepends
|
|
115
|
+
// rather than appending — a `-c` after the subcommand name is parsed as a
|
|
116
|
+
// positional argument to that subcommand, not a global option.
|
|
117
|
+
export function hardenGitArgs(args) {
|
|
118
|
+
return [...GIT_HARDENED_CONFIG_ARGS, ...(Array.isArray(args) ? args : [])];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Build the `env` option for execFileSync/spawnSync. Node's `env` option
|
|
122
|
+
// REPLACES the child's environment rather than merging with it, so this
|
|
123
|
+
// always spreads `process.env` first — passing `hardenGitEnv()` with no
|
|
124
|
+
// argument must be behaviourally identical to inheriting the parent
|
|
125
|
+
// environment plus the two hardening vars, never a stripped-down one.
|
|
126
|
+
export function hardenGitEnv(extraEnv) {
|
|
127
|
+
return { ...process.env, ...GIT_HARDENED_ENV, ...(extraEnv || {}) };
|
|
128
|
+
}
|