@clear-capabilities/agentic-security-scanner 0.195.10 → 0.195.11
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 +16 -0
- package/dist/{312ef9976a988b322ade.json → 13e6d1463f0aec440afa.json} +3 -3
- package/dist/agentic-security.mjs +4 -4
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/package.json +3 -3
- package/src/engine.js +6 -1
- package/src/language/CLAUDE.md +6 -3
- package/src/language/haskell-fix.js +108 -2
- package/src/language/haskell-ir.js +135 -8
- package/src/language/haskell-models.js +9 -2
- package/src/language/haskell-security-rules.js +82 -7
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,22 @@
|
|
|
9
9
|
> make the history less accurate, not more.
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
## 0.195.11 - Haskell taint: the project that is the framework, mutable cells, instance dispatch, record-held functions, request text into helpers; a scotty body-limit fixer; Haskell comments blanked for the generic detectors
|
|
13
|
+
|
|
14
|
+
**Measured, 0.195.10:** `TIMINGS preflight=3s push=6s pr=2s checks=338s merge=5s verify=6s tag=2s release=223s npm=237s total=822s release-clock=236s`, shipped in 24 min 47 s. The release clock (merge to published release) was 236 s; the run was long because the push stopped three times before the merge, each a host or capture artefact, never the engine (a transient `npm pack` retry, a warm gate run under GHC 9.4.8's package environment, a captured example whose compiler message lacked the error code the hosted GHC prints). The 0.195.9 line was not kept.
|
|
15
|
+
|
|
16
|
+
Why: the fresh real-code set recorded four true positives the engine had lost, all in IHP's own development tools (a request parameter reaching `Process.system` through a helper, two request-indexed `!!`), and the cause was one mechanism: when a framework repository scans itself, its own definition of a modelled request accessor shadowed the registry's model. The rest of the taint work came from two self-written probes of Haskell data-carrying idioms run against the engine (57 shapes; the 26 intra-module idioms of the first probe were all followed already, the second found four gaps). Nothing was read from a frozen split; the shapes are pinned both ways in `scanner/test/haskell/haskell-taint-shapes.test.js`.
|
|
17
|
+
|
|
18
|
+
- **A project definition of a modelled name keeps the registry's meaning** (`haskell-ir.js` `applyVar`, `lowerVarValue`): a resolution to a project `def` whose module-qualified name the registry models is lowered as the library call, and the definition is still referenced (never an uncalled entry point). On the real IHP clone this was not enough: the IHP preludes re-export `module CorePrelude` (not in the tree) before `module IHP.Controller.Param`, and `exportedLookup` returned the first possibility, an uncertain external name, so every `param` was `CorePrelude.param`. A wildcard re-export of a module the project does not contain is now the FALLBACK of the export-list search, and in the caller's resolution such a possibility goes to the wildcard list rather than competing with a definite hit (before that second change, `openEditor`, imported by name from a project module, read as ambiguous).
|
|
19
|
+
- **Mutable cells, instance dispatch, functions in record fields.** `writeIORef ref v` / `putMVar` / `writeTVar` (under `atomically` or not) / `modifyIORef ref f` assign a local cell and `readIORef` / `takeMVar` / `readMVar` / `readTVarIO` read it, also `STRef` (`CELL_OPS`; a cell shared across functions is not followed, disclosed in the guide). A class method applied to a constructor of a type with exactly one visible instance resolves to that instance's method; instance functions are named `Mod.$inst.Class.Type.method` so two instances resolve to different functions by name (the dataflow engine resolves callees by name; one test pin changed for it). `exec ops x`, with `ops` a top-level constant record literal, applies the held lambda or named function. The cell and STM names are in `HS_RULE_APIS` so wildcard imports qualify them.
|
|
20
|
+
- **Request text handed to a project helper is caller text in the helper** (`haskell-security-rules.js` `requestTextParams`: a pre-pass over the resolved call edges, partial applications and the edges of inlined helpers, which now carry their lowered arguments; one hop per round, four rounds). `list !! tableId` with a caller-supplied INDEX is reported like a caller-supplied list, a relational test on the index covers it, and the partial-function emits carry `inlineCtx` so an inlined call-site copy is dropped when the helper reports it. On the fresh set this restores the two Enums sites and finds a third request-indexed `!!` in the schema designer, labelled a true positive on sight.
|
|
21
|
+
- **`hs-scotty-body-limit` (CWE-770), a MITIGATION.** scotty's `body` has no per-read bound; the library's bound is `setMaxRequestBodySize :: Kilobytes -> ScottyM ()` (scotty 0.12 and later, a 413 before any handler runs), so the fixer adds it as the first statement of the ScottyM block that contains the read or names the handler, with `agenticRequestBodyLimitKb = 1024` (a declared default) and a qualified import; refused when the block is in another file, when a cabal bound excludes every version with the call (`parseCabalFile`, `versionSatisfies`), or when a name is taken. The rule learned the same thing: a limit in the same function or in a ScottyM function that references the handler is certain (`controls` kind `scotty-body-limit`, verified), a limit elsewhere keeps the finding at low with the reach stated as unverified. The effective check requires exactly one added call at the planned line and unchanged body reads; the test type-checks the patch under GHC against a declared stub of the scotty API. One real example (`basic.hs`) was blocked at first because the import was placed after an `import` inside a commented-out block; the fixer now reads the last import of the comment-stripped code.
|
|
22
|
+
- **The language-neutral detectors see Haskell comments blanked** (`engine.js` `_commentLangFor`, `_blankCached`, via `haskell-comments.js`). Under the C-family view, `crypto.createHash('md5')` and a JWT verify with `none` quoted in a Haskell doc comment were reported as calls (two findings and a cipher entry on a comment-only file); pinned both ways in `haskell-generic-detectors.test.js`, with the JavaScript code still firing.
|
|
23
|
+
|
|
24
|
+
**Measured on real code** (`bench/dag/dev-haskell`, re-recorded with `bench:haskell-precision:update`; every new site was read and labelled after the scan found it, `LABEL-CHANGES.md`, and none fed back into a rule): the fresh set flags 31 labelled sites, 21 true positives (67.7%, Wilson 50.1% to 81.4%) against 26 and 17 (65.4%); true positives not flagged 4 to 1 (the multi-sink chain at the restored command-injection line). The development censuses grew where the preludes now resolve (xmonad-contrib 1 to 5 flagged, hackage-server 1 to 2, IHP 20 to 25): the five development additions are false positives by the sets' policy (paths from the user's own configuration, the operator's machine, the server's own temporary file; one `last` of a list with a literal prepended) and are labelled so. The remediation ledger over the labelled true positives: 8 of 26 to **11 of 27** (`fix-real.mjs`): the three scotty `body` reads verify; the restored command injection builds a `Text` command for `Process.system`, which the argv rewrite refuses by class. The sealed independent set, measured once and logged: 77 flagged (73), 1 true positive of 35 decided, 2.9%, unchanged. The frozen unseen-v6 split, measured once and logged: identical to 0.195.9, F1 72.5%, taint families 66.7%; the shapes above are not the ones it exercises, and that is the recorded reading. The support registry was re-measured under GHC 9.4.8: Haskell 9/9, Nix 8/10 (the two `nix`-blocked rows), numbers unchanged.
|
|
25
|
+
|
|
26
|
+
Gates, from the runs recorded for this entry: `test:haskell` 450/450 (two new suites, `haskell-taint-shapes` and `haskell-remediation-scotty-body`, wired into the script and checked for a glued name; two tests added to `haskell-generic-detectors`), `test:nix` 305/305, `test:language` 257/257, `test:lineage` 1554/1554, `bench:mutation:check` 460/460, `bench:layer-recall:check` unchanged, `bench:language-support:check` current, `bench:haskell-precision:check` PASS after the deliberate re-record, generated language docs current.
|
|
27
|
+
|
|
12
28
|
## 0.195.10 - Haskell remediation measured on real code: a password-hash migration fixer, an HTML-from-text fixer, and the registry's GHC check
|
|
13
29
|
|
|
14
30
|
Why: the fix preview was run over every labelled real-code true positive of `bench/dag/dev-haskell` (26 sites in gitit, scotty, dhall, hackage-server and IHP; `fix-real.mjs <project> --all`) and 3 of them got a verified patch (one cookie, two wai request bodies). The rest were refusals: five scotty `html $ mconcat ["<h1>", v, "</h1>"]` sites, which the blaze rewrite cannot touch; three scotty `body` reads; two dhall path operations spread over several functions; three generators in files that import no entropy package; an OpenSSL `VerifyNone`; an open redirect; two partial functions; and gitit's `hashPassword salt pass = showDigest $ sha512 $ ...`, refused by the CWE-916 class reason. Two of those classes had a sound rewrite that was never written. After this release 8 of the 26 sites get a verified patch, on the same 47 flagged sites (nothing moved in detection).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clear-capabilities/agentic-security-scanner",
|
|
3
|
-
"version": "0.195.
|
|
3
|
+
"version": "0.195.11",
|
|
4
4
|
"description": "Scanner engine for the agentic-security Claude Code plugin: SAST, SCA with reachability and CISA KEV, secrets, IaC, Haskell and Nix/NixOS, prompt-injection, MCP/agent-tool audit, authZ analysis, SBOM, compliance attestation, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"node": ">=24.0.0"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@babel/core": "^8.0
|
|
43
|
+
"@babel/core": "^8.1.0",
|
|
44
44
|
"@babel/preset-react": "^8.0.1",
|
|
45
45
|
"@babel/preset-typescript": "^8.0.1",
|
|
46
46
|
"js-yaml": "^5.5.0",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"test:lineage": "node --test test/lineage/analysis-completion.test.js test/lineage/schema.test.js test/lineage/ids.test.js test/lineage/protection.test.js test/lineage/classification.test.js test/lineage/validate.test.js test/lineage/json-schema-parity.test.js test/lineage/flagship-fixture.test.js test/lineage/flagship-fixture-semantics.test.js test/lineage/field-identity.test.js test/lineage/engine-expr-resolver.test.js test/lineage/engine-walker.test.js test/lineage/engine-integration.test.js test/lineage/engine-receiver-identity.test.js test/lineage/summaries.test.js test/lineage/driver.test.js test/lineage/engine-provenance.test.js test/lineage/engine-provenance-interprocedural.test.js test/lineage/path-store.test.js test/lineage/path-query.test.js test/lineage/flow-grade.test.js test/lineage/source-registry.test.js test/lineage/sink-registry.test.js test/lineage/transform-catalog.test.js test/lineage/handling-analyzer.test.js test/lineage/registry-real-code.test.js test/lineage/source-seeding.test.js test/lineage/graph-builder.test.js test/lineage/coverage.test.js test/lineage/resolve-destination.test.js test/lineage/queue-detail.test.js test/lineage/index.test.js test/lineage/obligation-mapping.test.js test/lineage/obligation-predicates.test.js test/lineage/obligation-predicates-walkthrough.test.js test/lineage/transit-protection.test.js test/lineage/at-rest-protection.test.js test/lineage/protection-summary.test.js test/lineage/ac01-multi-sink.test.js test/lineage/policy-verdict.test.js test/lineage/governance-refs.test.js test/lineage/export-privacy.test.js test/lineage/export-json.test.js test/lineage/export-csv.test.js test/lineage/decision-story.test.js test/lineage/export-briefing.test.js test/lineage/graph-snapshot.test.js test/lineage/graph-diff.test.js test/lineage/drift-policy.test.js test/lineage/recipient-profile.test.js test/lineage/recipient-registry.test.js test/lineage/recipient-wiring.test.js test/lineage/redact-graph.test.js test/lineage-scan-wiring.test.js test/lineage-artifact-write.test.js test/bench-data-lineage-runner.test.js test/bundle-frontend.test.js test/bundle-frontend-golden.test.js test/generate-html-report.test.js test/export-image.test.js test/lineage/scenario.test.js test/lineage/scenario-engine.test.js test/lineage/scenario-diff.test.js test/lineage/scenario-no-obligation-wiring.test.js test/lineage/impact-assessment.test.js test/lineage/impact-engine.test.js test/lineage/impact-no-obligation-wiring.test.js test/lineage/governance-edit.test.js test/lineage/remediation.test.js test/lineage/runtime-observation.test.js test/lineage/observation-correlation.test.js test/lineage/observation-adapters.test.js test/lineage/observation-store.test.js test/lineage/runtime-corroboration-wiring.test.js test/lineage/cross-repo-link.test.js test/lineage/federation-loader.test.js test/lineage/cross-repo-link-wiring.test.js test/lineage/runtime-assurance.test.js test/lineage/runtime-edge-states.test.js test/lineage/runtime-explorer-view.test.js test/cli/runtime-explorer-cli.test.js test/cli/runtime-identity-cli.test.js test/cli/runtime-twin-cli.test.js test/lineage/cut-planner.test.js test/lineage/scc.test.js test/lineage/scc-solver.test.js test/graph/graph-views.test.js test/lineage/dag07-completion.test.js test/lineage/owned-build.test.js test/dataflow/boundary-propagation.test.js test/lineage/boundary-contract.test.js test/lineage/correlation-v2.test.js test/lineage/path-control-evidence.test.js test/lineage/smt-z3-backend.test.js test/cli/dag-commands.test.js",
|
|
94
94
|
"test:bench-modules": "node --test test/phase4-harness.test.js test/pipeline.test.js test/proof-corpus-lib.test.js test/proof-corpus-runner.test.js",
|
|
95
95
|
"test:server": "node --test test/server/graph-loader.test.js test/server/security.test.js test/server/routes.test.js test/server/http-server.test.js test/server/cmd-explore.test.js test/server/cmd-dataflow-export.test.js test/server/static-assets.test.js test/server/dataflow-scenario-cli.test.js test/server/dataflow-impact-cli.test.js",
|
|
96
|
-
"test:haskell": "node --test test/haskell/haskell-reachability.test.js test/haskell/haskell-real-code-shapes.test.js test/haskell/haskell-unseen-v5-shapes.test.js test/haskell/haskell-unseen-v4-shapes.test.js test/haskell/haskell-alias-taint.test.js test/haskell/haskell-weak-hash-names.test.js test/haskell/haskell-models-extended.test.js test/haskell/haskell-rules-extended.test.js test/haskell/haskell-injection.test.js test/haskell/haskell-ir.test.js test/haskell/haskell-manifests.test.js test/haskell/haskell-parser.test.js test/haskell/haskell-remediation.test.js test/haskell/haskell-remediation-0190.test.js test/haskell/haskell-remediation-kdf.test.js test/haskell/haskell-remediation-html-text.test.js test/haskell/haskell-resolved-graph.test.js test/haskell/haskell-sca.test.js test/haskell/haskell-sca-severity.test.js test/haskell/haskell-web-guards.test.js test/haskell/haskell-advisory-feed.test.js test/haskell/haskell-security-rules.test.js test/haskell/haskell-taint.test.js test/haskell/haskell-boundaries.test.js test/haskell/haskell-live-feed-scan.test.js test/haskell/haskell-supply-bounds.test.js test/haskell/haskell-ir-scaling.test.js test/haskell/haskell-boundary-propagation.test.js test/haskell/haskell-generalization.test.js test/haskell/haskell-trust-boundary.test.js test/haskell/haskell-comment-invariance.test.js test/haskell/haskell-remediation-classes.test.js test/haskell/haskell-trust-boundary-frameworks.test.js test/haskell/haskell-generic-detectors.test.js",
|
|
96
|
+
"test:haskell": "node --test test/haskell/haskell-reachability.test.js test/haskell/haskell-real-code-shapes.test.js test/haskell/haskell-unseen-v5-shapes.test.js test/haskell/haskell-unseen-v4-shapes.test.js test/haskell/haskell-alias-taint.test.js test/haskell/haskell-weak-hash-names.test.js test/haskell/haskell-models-extended.test.js test/haskell/haskell-rules-extended.test.js test/haskell/haskell-injection.test.js test/haskell/haskell-ir.test.js test/haskell/haskell-manifests.test.js test/haskell/haskell-parser.test.js test/haskell/haskell-remediation.test.js test/haskell/haskell-remediation-0190.test.js test/haskell/haskell-remediation-kdf.test.js test/haskell/haskell-remediation-html-text.test.js test/haskell/haskell-remediation-scotty-body.test.js test/haskell/haskell-taint-shapes.test.js test/haskell/haskell-resolved-graph.test.js test/haskell/haskell-sca.test.js test/haskell/haskell-sca-severity.test.js test/haskell/haskell-web-guards.test.js test/haskell/haskell-advisory-feed.test.js test/haskell/haskell-security-rules.test.js test/haskell/haskell-taint.test.js test/haskell/haskell-boundaries.test.js test/haskell/haskell-live-feed-scan.test.js test/haskell/haskell-supply-bounds.test.js test/haskell/haskell-ir-scaling.test.js test/haskell/haskell-boundary-propagation.test.js test/haskell/haskell-generalization.test.js test/haskell/haskell-trust-boundary.test.js test/haskell/haskell-comment-invariance.test.js test/haskell/haskell-remediation-classes.test.js test/haskell/haskell-trust-boundary-frameworks.test.js test/haskell/haskell-generic-detectors.test.js",
|
|
97
97
|
"test:nix": "node --test test/nix/nix-option-types.test.js test/nix/nix-development-shapes.test.js test/nix/nixos-hardening-daemon.test.js test/nix/nixos-hardening-extended.test.js test/nix/nix-build-trust.test.js test/nix/nix-eval-isolation.test.js test/nix/nix-input-inventory.test.js test/nix/nix-parser-ir.test.js test/nix/nix-remediation.test.js test/nix/nix-resolved-closure.test.js test/nix/nix-sca-patches.test.js test/nix/nix-sca-severity.test.js test/nix/nix-haskell-closure-names.test.js test/nix/nix-script-taint.test.js test/nix/nix-secrets-store.test.js test/nix/nixos-hardening.test.js test/nix/nixos-module-resolution.test.js test/nix/nix-fix-multifile.test.js test/nix/nixos-evaluator-forms.test.js test/nix/nix-advisory-feed.test.js test/nix/nix-fix-prewrite.test.js test/nix/nix-boundary-scope.test.js",
|
|
98
98
|
"test:language": "node --test test/bench-haskell-precision.test.js test/bench-independent-haskell-panel.test.js test/language/capability-ledger.test.js test/language/language-accuracy-regression.test.js test/language/language-aibom.test.js test/language/language-assurance.test.js test/language/language-bom.test.js test/language/language-compliance.test.js test/language/language-contracts.test.js test/language/language-corpora-integrity.test.js test/language/language-discovery.test.js test/language/language-doc-coverage.test.js test/language/language-evidence-posture.test.js test/language/language-explorer.test.js test/language/frozen-splits.test.js test/language/language-gap-fixes.test.js test/language/language-gap-fixes-2.test.js test/language/language-governance.test.js test/language/language-integrations.test.js test/language/language-llm-agent.test.js test/language/language-local-ai.test.js test/language/language-parity-haskell.test.js test/language/language-polyglot-bridges.test.js test/language/language-privacy-lineage.test.js test/language/language-proof-remediation.test.js test/language/language-report-formats.test.js test/language/language-secrets.test.js test/language/language-trust-boundary.test.js",
|
|
99
99
|
"test:language-stress": "node --test --test-concurrency=1 test/language/language-stress-offline.test.js",
|