@shriyanss/js-recon 1.3.1-alpha.1 → 1.3.1-alpha.3
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/.github/workflows/pr_checker.yml +9 -8
- package/CHANGELOG.md +47 -0
- package/CLAUDE.md +136 -0
- package/build/analyze/engine/astEngine.js +34 -6
- package/build/analyze/engine/astEngine.js.map +1 -1
- package/build/analyze/engine/index.js +2 -2
- package/build/analyze/engine/index.js.map +1 -1
- package/build/analyze/helpers/engineHelpers/taintFlow.js +218 -0
- package/build/analyze/helpers/engineHelpers/taintFlow.js.map +1 -0
- package/build/analyze/helpers/schemas.js +3 -1
- package/build/analyze/helpers/schemas.js.map +1 -1
- package/build/analyze/helpers/validate.js +49 -9
- package/build/analyze/helpers/validate.js.map +1 -1
- package/build/analyze/index.js +3 -2
- package/build/analyze/index.js.map +1 -1
- package/build/globalConfig.js +1 -1
- package/build/index.js +21 -1
- package/build/index.js.map +1 -1
- package/build/lazyLoad/downloadFilesUtil.js +3 -3
- package/build/lazyLoad/downloadFilesUtil.js.map +1 -1
- package/build/lazyLoad/downloadQueue.js +190 -0
- package/build/lazyLoad/downloadQueue.js.map +1 -0
- package/build/lazyLoad/index.js +57 -55
- package/build/lazyLoad/index.js.map +1 -1
- package/build/lazyLoad/next_js/NextJsCrawler.js +34 -11
- package/build/lazyLoad/next_js/NextJsCrawler.js.map +1 -1
- package/build/lazyLoad/next_js/next_GetJSScript.js +24 -3
- package/build/lazyLoad/next_js/next_GetJSScript.js.map +1 -1
- package/build/lazyLoad/next_js/next_SubsequentRequests.js +20 -2
- package/build/lazyLoad/next_js/next_SubsequentRequests.js.map +1 -1
- package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js +10 -1
- package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js.map +1 -1
- package/build/lazyLoad/techDetect/checkReact.js +13 -2
- package/build/lazyLoad/techDetect/checkReact.js.map +1 -1
- package/build/lazyLoad/techDetect/index.js +37 -24
- package/build/lazyLoad/techDetect/index.js.map +1 -1
- package/build/lazyLoad/vue/vue_discoverJsFiles.js +25 -11
- package/build/lazyLoad/vue/vue_discoverJsFiles.js.map +1 -1
- package/build/lazyLoad/vue/vue_getClientSidePaths.js +31 -4
- package/build/lazyLoad/vue/vue_getClientSidePaths.js.map +1 -1
- package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js +3 -3
- package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js.map +1 -1
- package/build/lazyLoad/vue/vue_stringJsFiles.js +142 -0
- package/build/lazyLoad/vue/vue_stringJsFiles.js.map +1 -0
- package/build/load/index.js +316 -0
- package/build/load/index.js.map +1 -0
- package/build/map/index.js +42 -5
- package/build/map/index.js.map +1 -1
- package/build/map/next_js/getExports.js +11 -5
- package/build/map/next_js/getExports.js.map +1 -1
- package/build/map/next_js/getFetchInstances.js +11 -5
- package/build/map/next_js/getFetchInstances.js.map +1 -1
- package/build/map/next_js/interactive.js +30 -0
- package/build/map/next_js/interactive.js.map +1 -1
- package/build/map/next_js/interactive_helpers/commandHandler.js +22 -0
- package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -1
- package/build/map/next_js/interactive_helpers/esqueryGen.js +370 -0
- package/build/map/next_js/interactive_helpers/esqueryGen.js.map +1 -0
- package/build/map/next_js/interactive_helpers/helpMenu.js +1 -0
- package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -1
- package/build/map/next_js/interactive_helpers/inputPatch.js +207 -0
- package/build/map/next_js/interactive_helpers/inputPatch.js.map +1 -0
- package/build/map/next_js/interactive_helpers/ui.js +0 -1
- package/build/map/next_js/interactive_helpers/ui.js.map +1 -1
- package/build/map/next_js/resolveAxios.js +24 -5
- package/build/map/next_js/resolveAxios.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/astNodeToJsonString.js +2 -2
- package/build/map/next_js/resolveAxiosHelpers/astNodeToJsonString.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js +11 -5
- package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/interceptorHeaders.js +206 -0
- package/build/map/next_js/resolveAxiosHelpers/interceptorHeaders.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js +25 -8
- package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js +14 -6
- package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js +22 -10
- package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/traceBody.js +913 -0
- package/build/map/next_js/resolveAxiosHelpers/traceBody.js.map +1 -0
- package/build/map/next_js/resolveFetch.js +115 -3
- package/build/map/next_js/resolveFetch.js.map +1 -1
- package/build/map/next_js/resolveNewRequest.js +749 -0
- package/build/map/next_js/resolveNewRequest.js.map +1 -0
- package/build/map/next_js/utils.js +397 -49
- package/build/map/next_js/utils.js.map +1 -1
- package/build/map/vue_js/getViteConnections.js +27 -3
- package/build/map/vue_js/getViteConnections.js.map +1 -1
- package/build/map/vue_js/interactive.js +28 -0
- package/build/map/vue_js/interactive.js.map +1 -1
- package/build/map/vue_js/interactive_helpers/commandHandler.js +22 -0
- package/build/map/vue_js/interactive_helpers/commandHandler.js.map +1 -1
- package/build/map/vue_js/interactive_helpers/helpMenu.js +1 -0
- package/build/map/vue_js/interactive_helpers/helpMenu.js.map +1 -1
- package/build/map/vue_js/vue_resolveFetch.js +722 -0
- package/build/map/vue_js/vue_resolveFetch.js.map +1 -0
- package/build/report/utility/populateDb/populateAnalysisFindings.js +1 -1
- package/build/report/utility/populateDb/populateAnalysisFindings.js.map +1 -1
- package/build/run/index.js +27 -5
- package/build/run/index.js.map +1 -1
- package/build/strings/index.js +5 -1
- package/build/strings/index.js.map +1 -1
- package/build/utility/globals.js +9 -0
- package/build/utility/globals.js.map +1 -1
- package/build/utility/makeReq.js +90 -11
- package/build/utility/makeReq.js.map +1 -1
- package/build/utility/openapiGenerator.js +60 -4
- package/build/utility/openapiGenerator.js.map +1 -1
- package/build/utility/postmanGenerator.js +167 -0
- package/build/utility/postmanGenerator.js.map +1 -0
- package/package.json +2 -2
|
@@ -8,16 +8,17 @@ on:
|
|
|
8
8
|
jobs:
|
|
9
9
|
check-branch:
|
|
10
10
|
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
pull-requests: write
|
|
11
13
|
steps:
|
|
12
|
-
- uses: actions/checkout@
|
|
13
|
-
- name:
|
|
14
|
-
if: github.head_ref != 'dev'
|
|
14
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
15
|
+
- name: Redirect PR to dev
|
|
16
|
+
if: github.head_ref != 'dev' || github.event.pull_request.head.repo.full_name != 'shriyanss/js-recon'
|
|
15
17
|
env:
|
|
16
18
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
17
|
-
|
|
19
|
+
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
18
20
|
BRANCH_NAME: ${{ github.head_ref }}
|
|
21
|
+
SOURCE_REPO: ${{ github.event.pull_request.head.repo.full_name }}
|
|
19
22
|
run: |
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
gh pr comment $PR_URL --body "This merge is not possible. Create a PR for $BRANCH_NAME -> dev"
|
|
23
|
-
gh pr close $PR_URL
|
|
23
|
+
gh pr edit $PR_NUMBER --base dev
|
|
24
|
+
gh pr comment $PR_NUMBER --body "This PR was targeting \`main\`, but only the \`dev\` branch of \`shriyanss/js-recon\` can merge directly into \`main\`. The target branch has been changed to \`dev\` (source: \`$SOURCE_REPO:$BRANCH_NAME\`)."
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 1.3.1-alpha.3 - 2026-05-20
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Add version for rule templates
|
|
8
|
+
- Add Vue js support for analyze module
|
|
9
|
+
- `esquery` interactive command + headless `-c/--command` runner for `map` and `run`, with `&&` chaining (`map`)
|
|
10
|
+
- Line-editor behavior in interactive mode: cursor movement (left/right/home/end/ctrl-a/ctrl-e), word-wise motion/delete (ctrl-w, ctrl-left/right), kill-to-start/end (ctrl-u/ctrl-k), delete-at-cursor, mid-string insertion so paste lands at the cursor, and horizontal scroll for long inputs (`map -i`)
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Removed `mouse: true` from the interactive output pane so terminal-native text selection/copy works in the output area (`map -i`)
|
|
15
|
+
- Vue.js fetch resolver now walks back to the enclosing wrapper function's caller(s) so `URLSearchParams(param.subprop)` expands to real `?k1={k1}&k2={k2}` query strings and spread-header / member-value placeholders get substituted from the caller's object literal — including transitive resolution when the caller passes its own param through (`map`)
|
|
16
|
+
- Vue.js fetch resolver recognises destructured fetch wrappers (e.g. `const { wrapperKey: x } = factory({ ... })`) and resolves their callsites as fetch calls, with positional-first-arg filtering to avoid mis-identifying object-shaped wrappers that construct the URL from a property of their input (`map`)
|
|
17
|
+
- Distinct callsites for the same `(path, method)` are preserved in both the OpenAPI spec (path key gets a `#N` suffix) and the Postman collection (request name gets a `#N` suffix) instead of being collapsed to a single entry (`map`)
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Spread elements in request bodies and option objects are no longer silently dropped when the spread argument is unresolvable — the output surfaces a sentinel key (e.g. `"...arg": "<spread>"`, `"...call()": "<spread>"`) so downstream readers know more fields exist at runtime (`map`)
|
|
22
|
+
|
|
23
|
+
## 1.3.1-alpha.2 - 2026-05-18
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- Added taint analysis in the `analyze` engine for Next.js
|
|
28
|
+
- Download JS files as soon as they are discovered (`lazyload`)
|
|
29
|
+
- Recursively resolve HTTP requests in Next.js (`map`)
|
|
30
|
+
- Stream JS file downloads during Vue.js discovery — downloads start as soon as each discovery step finds files instead of waiting for the full pipeline (`lazyload`)
|
|
31
|
+
- Resolve `UnaryExpression` nodes (`!x`, `void 0`, `-x`, `typeof x`) so request bodies surface real boolean/null values instead of `[unsupported node type: UnaryExpression]` (`map`)
|
|
32
|
+
- Resolve `ArrayExpression` nodes recursively so array body fields render their element shape instead of `[unsupported node type: ArrayExpression]` (`map`)
|
|
33
|
+
- Resolve `JSON.stringify(variable)` calls by tracing the argument, replacing the opaque `[call:JSON.stringify()]` placeholder (`map`)
|
|
34
|
+
- Resolve `new URLSearchParams({...})` to a real query string, using `{key}` placeholders for values that can't be statically resolved (`map`)
|
|
35
|
+
- Partial-concatenation fallback for binary `+` expressions so resolvable fragments are preserved when one side is unresolved (`map`)
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Nested `JSON.stringify(expr)` inside a body object now resolves `expr` instead of emitting `[call to object...]` (`map`)
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- Invalidate request cache if the memory is full
|
|
44
|
+
- Progress bars no longer hide the terminal cursor permanently when they exit without a clean `stop()` — all bars now use `hideCursor: false` (`lazyload`)
|
|
45
|
+
- Removed the concurrent download progress bar in the Vue.js section that was causing display corruption — discovery `console.log` calls no longer collide with the bar's render line (`lazyload`)
|
|
46
|
+
- API spec / Postman collection URLs no longer get `{{baseUrl}}` prepended to already-absolute URLs — full URLs are now reduced to their pathname (`map`)
|
|
47
|
+
- Spread elements that can't be resolved are now skipped instead of being emitted as fake `"...spread": "[spread:e]"` body fields (`map`)
|
|
48
|
+
- Request bodies that reduce to an empty `{}` after resolution are now omitted from the Postman collection (`map`)
|
|
49
|
+
|
|
3
50
|
## 1.3.1-alpha.1 - 2026.05.13
|
|
4
51
|
|
|
5
52
|
### Added
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# js-recon
|
|
2
|
+
|
|
3
|
+
Static analysis tool that maps API endpoints and detects client-side security issues by analyzing Next.js (webpack/turbopack) and Vue.js bundles. Written in TypeScript, compiled to `build/` before running.
|
|
4
|
+
|
|
5
|
+
## Build & run
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run cleanup # rm -rf build/ + tsc (full rebuild)
|
|
9
|
+
npm run start -- <subcommand> [options]
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`cleanup` must be run before testing any TypeScript change when using the `run` command.
|
|
13
|
+
|
|
14
|
+
## Subcommands
|
|
15
|
+
|
|
16
|
+
| Command | Purpose |
|
|
17
|
+
| ------------- | --------------------------------------------------------------- |
|
|
18
|
+
| `lazyload` | Download JS chunks from a target URL |
|
|
19
|
+
| `strings` | Extract strings/paths/secrets from JS files |
|
|
20
|
+
| `map` | Parse webpack/turbopack bundles into a structured `mapped.json` |
|
|
21
|
+
| `endpoints` | Extract client-side routes |
|
|
22
|
+
| `analyze` | Run YAML rules against `mapped.json` / OpenAPI spec |
|
|
23
|
+
| `report` | Generate HTML/SQLite report |
|
|
24
|
+
| `run` | Run all of the above in sequence (primary interface) |
|
|
25
|
+
| `api-gateway` | Manage AWS API Gateway for IP rotation |
|
|
26
|
+
| `mcp` | Interactive AI-powered CLI |
|
|
27
|
+
|
|
28
|
+
## Key source files
|
|
29
|
+
|
|
30
|
+
- `src/index.ts` — CLI entry point; all subcommand definitions and option declarations live here
|
|
31
|
+
- `src/run/index.ts` — orchestrates the full pipeline (`run` subcommand); two tech-specific flows (Next.js 8-step, Vue 4-step)
|
|
32
|
+
- `src/analyze/index.ts` — loads/validates rules, runs AST and request engines
|
|
33
|
+
- `src/analyze/helpers/initRules.ts` — downloads/caches rules from GitHub to `~/.js-recon/rules`
|
|
34
|
+
- `src/analyze/helpers/validate.ts` — validates rules and checks `js_recon_version` compatibility
|
|
35
|
+
- `src/analyze/helpers/schemas.ts` — Zod schema for rule YAML files
|
|
36
|
+
- `src/map/next_js/resolveFetch.ts` — resolves `fetch()` calls, detects Next.js framework chunks
|
|
37
|
+
- `src/map/next_js/utils.ts` — `resolveNodeValue`, `resolveVariableInChunk`, `substituteVariablesInString`
|
|
38
|
+
- `src/map/next_js/getWebpackConnections.ts` — extracts chunk code from webpack bundles
|
|
39
|
+
- `src/map/next_js/interactive_helpers/esqueryGen.ts` — `esquery` interactive command: minifies a pasted snippet, matches it against each chunk's minified AST nodes, prints loose/strict selectors. Vue's command handler imports the same module — keep it framework-agnostic.
|
|
40
|
+
- `src/map/next_js/interactive.ts` / `src/map/vue_js/interactive.ts` — export both the blessed-backed `interactive()` entry and a headless `runCommands(chunks, mapFile, commands)` that pipes `outputBox.log` to stdout for `-c/--command` execution.
|
|
41
|
+
- `src/map/next_js/interactive_helpers/inputPatch.ts` — `enableCursorInput(inputBox)` patches a blessed textbox instance to support cursor movement, mid-string insertion, and paste-at-cursor. It overrides `_listener`/`setValue`/`_updateCursor`/`clearValue` on the instance. **Don't try to remove blessed's listener after the fact** — blessed re-binds `this._listener` on every focus, so overriding `_listener` on the instance is the only race-free approach. Shared by Next.js and Vue interactive entries.
|
|
42
|
+
- `src/globalConfig.ts` — current version string and tool-wide constants
|
|
43
|
+
- `src/utility/globals.ts` — mutable global state (tech detection result, AI config, OpenAPI flag, etc.)
|
|
44
|
+
|
|
45
|
+
## `run` pipeline in detail
|
|
46
|
+
|
|
47
|
+
`run` is the primary subcommand. It calls `processUrl` for each target, which dispatches to one of two pipelines based on the detected front-end framework (`globalsUtil.getTech()`).
|
|
48
|
+
|
|
49
|
+
### Next.js pipeline (8 steps)
|
|
50
|
+
|
|
51
|
+
1. **Lazyload** — downloads initial JS chunks via Puppeteer; detects framework; sets `globalsUtil.getTech()` to `"next"`
|
|
52
|
+
2. **Strings** — scans downloaded JS for strings, extracts URL paths → `extracted_urls.json`
|
|
53
|
+
3. **Lazyload (subsequent requests)** — re-crawls using the extracted paths to fetch dynamically loaded chunks; also fetches `buildId`
|
|
54
|
+
4. **Strings (pass 2)** — re-runs strings on the expanded chunk set; generates `extracted_urls.txt` (permuted) and `extracted_urls-openapi.json`; optionally scans secrets (`--secrets`)
|
|
55
|
+
5. **Lazyload re-pass (step 4.5)** — a second subsequent-requests crawl to pick up chunks for dynamic routes discovered in pass 2
|
|
56
|
+
6. **Strings re-pass (step 4.6)** — strings pass over the re-pass chunks
|
|
57
|
+
7. **Map** — parses webpack/turbopack bundles; resolves `fetch()` calls and axios usage; generates `mapped.json` and `mapped-openapi.json`; CDN-aware: if JS was served from a different host, `getCdnDir` finds the CDN output dir and passes that to map instead of `outputDir/host`
|
|
58
|
+
8. **Endpoints** — extracts client-side route paths; uses `___subsequent_requests` directory presence to decide whether to pass a JS directory
|
|
59
|
+
9. **Analyze** — loads YAML rules (from `-r/--rules` if provided, otherwise default rules cache); runs AST engine and request engine; writes `analyze.json`
|
|
60
|
+
10. **Report** — populates SQLite DB (`js-recon.db`) and generates HTML report
|
|
61
|
+
|
|
62
|
+
### Vue.js pipeline (4 steps)
|
|
63
|
+
|
|
64
|
+
1. **Lazyload** — same as Next.js step 1; sets `globalsUtil.getTech()` to `"vue"`
|
|
65
|
+
2. **Map** — scans the entire `outputDir` (Vue chunks spread across asset hosts)
|
|
66
|
+
3. **Analyze** — same rule loading as Next.js; `-r/--rules` is forwarded here too
|
|
67
|
+
4. **Report** — same as Next.js; if `endpoints.json` doesn't exist it is written as `[]` since Vue endpoints extraction isn't implemented yet
|
|
68
|
+
|
|
69
|
+
### Tech detection flow
|
|
70
|
+
|
|
71
|
+
`lazyLoad` sets the global tech string. If it remains `""` after lazyload, `run` exits (single URL) or skips (batch). Techs other than `"next"` and `"vue"` only get lazyload; the rest of the pipeline is skipped with a warning.
|
|
72
|
+
|
|
73
|
+
### Batch mode
|
|
74
|
+
|
|
75
|
+
When `-u` points to a file of URLs, each line is processed sequentially. For each URL:
|
|
76
|
+
|
|
77
|
+
- A subdirectory `output/<host>/` is created
|
|
78
|
+
- `clearJsUrls()` / `clearJsonUrls()` reset the URL sets so previous targets don't bleed over
|
|
79
|
+
- All output paths are prefixed with `workingDir/`
|
|
80
|
+
|
|
81
|
+
## Adding a new flag to `run`
|
|
82
|
+
|
|
83
|
+
1. Declare the option in `src/index.ts` on the `run` command (`.option(...)`)
|
|
84
|
+
2. If it configures a global, call the setter in the `action` handler before `await run(cmd)`
|
|
85
|
+
3. If it needs to reach a downstream module (like `analyze`), thread it through `cmd` — `processUrl` receives the full `cmd` object and passes it to submodule calls
|
|
86
|
+
|
|
87
|
+
**Example — `-r/--rules` flag (added in this codebase):**
|
|
88
|
+
|
|
89
|
+
- Declared in `src/index.ts`: `.option("-r, --rules <file/dir>", "Rules file or directory (passed to analyze module)")`
|
|
90
|
+
- In `src/run/index.ts` the `analyze` calls use `cmd.rules || ""` — empty string tells `analyze` to use the default rules cache
|
|
91
|
+
|
|
92
|
+
## Interactive-mode commands
|
|
93
|
+
|
|
94
|
+
The `map -i` blessed UI dispatches user input through `interactive_helpers/commandHandler.ts`. The same handler runs headlessly when commands are supplied via `-c/--command`:
|
|
95
|
+
|
|
96
|
+
- The `-c` option's commander coerce function splits each value on `&&` (with optional whitespace) and concatenates into a single command array. So `-c "list fetch && esquery * fetch"` is two commands; passing `-c` twice has the same effect.
|
|
97
|
+
- `map`'s entry point checks `commands.length > 0` first — if non-empty, it calls `nextRunCommands` / `vueRunCommands` and skips the blessed UI even when `-i` is also set.
|
|
98
|
+
- New commands should be added to **both** `next_js/interactive_helpers/commandHandler.ts` and `vue_js/interactive_helpers/commandHandler.ts`, plus the corresponding `helpMenu.ts` entry. When the implementation is framework-agnostic (e.g. `esquery`), put it under `next_js/interactive_helpers/` and import it from the Vue handler — don't duplicate.
|
|
99
|
+
|
|
100
|
+
## Rules
|
|
101
|
+
|
|
102
|
+
Rules are YAML files (`.yml`/`.yaml`) in two places:
|
|
103
|
+
|
|
104
|
+
- **Workspace:** `../js-recon-rules/` (relative to this repo)
|
|
105
|
+
- **Installed cache:** `~/.js-recon/rules`
|
|
106
|
+
|
|
107
|
+
`initRules` downloads rules from GitHub when missing or when the cached version doesn't match the latest release. `js_recon_version` (required) must be declared in every rule (e.g. `js_recon_version: ">=X.Y.Z"`); `initRules` uses it to validate compatibility and skips incompatible rules with a warning. The version check strips prerelease suffixes (e.g. `1.3.1-alpha.3` → `[1,3,1]`).
|
|
108
|
+
|
|
109
|
+
Rule categories:
|
|
110
|
+
|
|
111
|
+
- `ast/` — AST-based pattern matching against chunk code (uses `@babel/parser` + `esquery`)
|
|
112
|
+
- `request/` — OpenAPI/request-level checks against the resolved endpoint list
|
|
113
|
+
|
|
114
|
+
When `-r` points to a single file, only that rule is loaded. When it points to a directory, all `.yml`/`.yaml` files are loaded recursively.
|
|
115
|
+
|
|
116
|
+
## Testing a change
|
|
117
|
+
|
|
118
|
+
**Testing is mandatory for every change.** Before reporting a task complete:
|
|
119
|
+
|
|
120
|
+
1. Run `npm run cleanup` to rebuild TypeScript.
|
|
121
|
+
2. Run the `run` subcommand against the target the user provides. Do not use `analyze` or other individual subcommands as a substitute — the `run` subcommand must be used to validate end-to-end behavior.
|
|
122
|
+
3. If the user has not provided a target, ask for one before proceeding.
|
|
123
|
+
|
|
124
|
+
Typical test invocation:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
npm run cleanup && npm run start -- run -u <target-url> -y -k
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Security / confidentiality
|
|
131
|
+
|
|
132
|
+
When a change is informed by behavior observed on a real target (URLs, endpoint names, response shapes, finding details, etc.):
|
|
133
|
+
|
|
134
|
+
- **Do not include any target information in code comments, commit messages, docstrings, variable names, or any other artifact.**
|
|
135
|
+
- This applies to hostnames, paths, parameter names, response content, or any other detail that could identify the target.
|
|
136
|
+
- If context from the target is needed to describe a change, describe it in abstract terms only (e.g. "URL parameter passed to fetch" not "https://example.com/api/docs passes `file` param to fetch").
|
|
@@ -16,6 +16,7 @@ import { highlight } from "cli-highlight";
|
|
|
16
16
|
import { resolveFunctionIdentifier } from "../helpers/engineHelpers/resolveFunctionIdentifier.js";
|
|
17
17
|
import { findMemberExpressionAssignment } from "../helpers/engineHelpers/findMemberExpressionAssignment.js";
|
|
18
18
|
import { findDirectAssignment } from "../helpers/engineHelpers/findDirectAssignment.js";
|
|
19
|
+
import { computeTaint, sinkConsumesTaint } from "../helpers/engineHelpers/taintFlow.js";
|
|
19
20
|
/**
|
|
20
21
|
* ESQuery-based AST analysis engine for detecting code patterns using custom rules.
|
|
21
22
|
*
|
|
@@ -32,13 +33,22 @@ const esqueryEngine = (rule, mappedJsonData) => __awaiter(void 0, void 0, void 0
|
|
|
32
33
|
let findings = [];
|
|
33
34
|
for (const chunk of Object.values(mappedJsonData)) {
|
|
34
35
|
// first of all, load the code in ast
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
let ast;
|
|
37
|
+
try {
|
|
38
|
+
ast = parser.parse(chunk.code, {
|
|
39
|
+
sourceType: "unambiguous",
|
|
40
|
+
plugins: ["jsx", "typescript"],
|
|
41
|
+
errorRecovery: true,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (_c) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
40
47
|
let matchList = {};
|
|
41
48
|
const completedSteps = new Set();
|
|
49
|
+
// Cache taint info per "source step name" so we don't recompute when several
|
|
50
|
+
// sink steps share the same source step.
|
|
51
|
+
const taintCache = {};
|
|
42
52
|
// iterate through the steps in the rule
|
|
43
53
|
for (const step of rule.steps) {
|
|
44
54
|
// honor `requires`: skip the step if any of its required steps did not complete
|
|
@@ -64,7 +74,25 @@ const esqueryEngine = (rule, mappedJsonData) => __awaiter(void 0, void 0, void 0
|
|
|
64
74
|
searchRoot = scopeMatch.node;
|
|
65
75
|
}
|
|
66
76
|
// match the query against what is there in the user defined config file
|
|
67
|
-
|
|
77
|
+
let matches = esquery(searchRoot, selector);
|
|
78
|
+
// Optional data-flow filter: only keep matches whose value-side actually
|
|
79
|
+
// consumes a value tainted by the named source step's matches. This is
|
|
80
|
+
// what distinguishes a real source→sink finding from accidental
|
|
81
|
+
// source-and-sink-in-the-same-bundle co-occurrence.
|
|
82
|
+
if (matches.length > 0 && step.esquery.taintFrom) {
|
|
83
|
+
const sourceStepName = step.esquery.taintFrom;
|
|
84
|
+
const sourceMatch = matchList[sourceStepName];
|
|
85
|
+
if (!sourceMatch) {
|
|
86
|
+
// No source matched — nothing can be tainted from it.
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (!taintCache[sourceStepName]) {
|
|
90
|
+
const sourceNodes = sourceMatch.allNodes || [sourceMatch.node];
|
|
91
|
+
taintCache[sourceStepName] = computeTaint(ast, sourceNodes);
|
|
92
|
+
}
|
|
93
|
+
const taint = taintCache[sourceStepName];
|
|
94
|
+
matches = matches.filter((m) => sinkConsumesTaint(ast, m, taint));
|
|
95
|
+
}
|
|
68
96
|
if (matches.length > 0) {
|
|
69
97
|
// store the first match as the "primary" node so later steps can reference it,
|
|
70
98
|
// and keep the full match list available for tooling that wants it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"astEngine.js","sourceRoot":"","sources":["../../../src/analyze/engine/astEngine.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,MAAM,MAAM,eAAe,CAAC;AAEnC,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAC1C,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC;AACrC,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,yBAAyB,EAAE,MAAM,uDAAuD,CAAC;AAClG,OAAO,EAAE,8BAA8B,EAAE,MAAM,4DAA4D,CAAC;AAC5G,OAAO,EAAE,oBAAoB,EAAE,MAAM,kDAAkD,CAAC;
|
|
1
|
+
{"version":3,"file":"astEngine.js","sourceRoot":"","sources":["../../../src/analyze/engine/astEngine.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,7 +35,7 @@ export const engine = (rule, mappedJsonData, openapiData, tech) => __awaiter(voi
|
|
|
35
35
|
techValid = false;
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
if (techValid || tech === "all") {
|
|
38
|
+
if (techValid || tech === "all" || rule.tech.includes("all")) {
|
|
39
39
|
findings.push(...(yield requestEngine(rule, openapiData)));
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -49,7 +49,7 @@ export const engine = (rule, mappedJsonData, openapiData, tech) => __awaiter(voi
|
|
|
49
49
|
techValid = false;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
if (techValid || tech === "all") {
|
|
52
|
+
if (techValid || tech === "all" || rule.tech.includes("all")) {
|
|
53
53
|
findings.push(...(yield astEngine(rule, mappedJsonData)));
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyze/engine/index.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAC/C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AAGvC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAClB,IAAU,EACV,cAAkC,EAClC,WAAoC,EACpC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyze/engine/index.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAC/C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AAGvC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAClB,IAAU,EACV,cAAkC,EAClC,WAAoC,EACpC,IAA4B,EACO,EAAE;IACrC,yGAAyG;IAEzG,IAAI,QAAQ,GAAmB,EAAE,CAAC;IAElC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,OAAO;QACX,CAAC;QAED,IAAI,SAAS,GAAG,IAAI,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,SAAS,GAAG,KAAK,CAAC;YACtB,CAAC;QACL,CAAC;QAED,IAAI,SAAS,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC;IACL,CAAC;SAAM,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,cAAc,EAAE,CAAC;YAClB,OAAO;QACX,CAAC;QAED,IAAI,SAAS,GAAG,IAAI,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,SAAS,GAAG,KAAK,CAAC;YACtB,CAAC;QACL,CAAC;QAED,IAAI,SAAS,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAA,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import _traverse from "@babel/traverse";
|
|
2
|
+
const traverse = _traverse.default;
|
|
3
|
+
const memberChainString = (node) => {
|
|
4
|
+
if (node.type === "Identifier")
|
|
5
|
+
return node.name;
|
|
6
|
+
if (node.type === "ThisExpression")
|
|
7
|
+
return "this";
|
|
8
|
+
if (node.type === "MemberExpression") {
|
|
9
|
+
if (node.computed)
|
|
10
|
+
return null;
|
|
11
|
+
if (node.property.type !== "Identifier")
|
|
12
|
+
return null;
|
|
13
|
+
const obj = memberChainString(node.object);
|
|
14
|
+
if (!obj)
|
|
15
|
+
return null;
|
|
16
|
+
return `${obj}.${node.property.name}`;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
};
|
|
20
|
+
const collectIdsFromPattern = (node) => {
|
|
21
|
+
if (!node)
|
|
22
|
+
return [];
|
|
23
|
+
if (node.type === "Identifier")
|
|
24
|
+
return [node.name];
|
|
25
|
+
if (node.type === "ObjectPattern") {
|
|
26
|
+
return node.properties.flatMap((p) => {
|
|
27
|
+
if (p.type === "ObjectProperty")
|
|
28
|
+
return collectIdsFromPattern(p.value);
|
|
29
|
+
if (p.type === "RestElement")
|
|
30
|
+
return collectIdsFromPattern(p.argument);
|
|
31
|
+
return [];
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (node.type === "ArrayPattern") {
|
|
35
|
+
return node.elements.flatMap((e) => (e ? collectIdsFromPattern(e) : []));
|
|
36
|
+
}
|
|
37
|
+
if (node.type === "AssignmentPattern")
|
|
38
|
+
return collectIdsFromPattern(node.left);
|
|
39
|
+
if (node.type === "RestElement")
|
|
40
|
+
return collectIdsFromPattern(node.argument);
|
|
41
|
+
return [];
|
|
42
|
+
};
|
|
43
|
+
const expressionIsTainted = (path, taint) => {
|
|
44
|
+
if (taint.sourceNodes.has(path.node))
|
|
45
|
+
return true;
|
|
46
|
+
let tainted = false;
|
|
47
|
+
const visit = (p) => {
|
|
48
|
+
if (tainted)
|
|
49
|
+
return;
|
|
50
|
+
if (taint.sourceNodes.has(p.node)) {
|
|
51
|
+
tainted = true;
|
|
52
|
+
p.stop();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (p.node.type === "Identifier") {
|
|
56
|
+
// skip identifiers that are property keys / declarations themselves
|
|
57
|
+
const parent = p.parent;
|
|
58
|
+
if (parent &&
|
|
59
|
+
((parent.type === "MemberExpression" && parent.property === p.node && !parent.computed) ||
|
|
60
|
+
(parent.type === "ObjectProperty" && parent.key === p.node && !parent.computed) ||
|
|
61
|
+
(parent.type === "VariableDeclarator" && parent.id === p.node) ||
|
|
62
|
+
(parent.type === "FunctionDeclaration" && parent.id === p.node) ||
|
|
63
|
+
(parent.type === "ClassDeclaration" && parent.id === p.node))) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const binding = p.scope.getBinding(p.node.name);
|
|
67
|
+
if (binding && taint.bindings.has(binding.path)) {
|
|
68
|
+
tainted = true;
|
|
69
|
+
p.stop();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (p.node.type === "MemberExpression") {
|
|
74
|
+
const chain = memberChainString(p.node);
|
|
75
|
+
if (chain && taint.memberChains.has(chain)) {
|
|
76
|
+
tainted = true;
|
|
77
|
+
p.stop();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
visit(path);
|
|
83
|
+
if (!tainted) {
|
|
84
|
+
path.traverse({
|
|
85
|
+
enter(p) {
|
|
86
|
+
visit(p);
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return tainted;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Compute the taint info for a chunk AST given the source nodes (URL-derived reads).
|
|
94
|
+
*
|
|
95
|
+
* Performs scope-aware iterative propagation:
|
|
96
|
+
* - Variable declarators / assignment expressions whose right-hand side
|
|
97
|
+
* contains a tainted source node or references a tainted binding/member
|
|
98
|
+
* chain are themselves tainted.
|
|
99
|
+
* - Tainted bindings are tracked by their declaration NodePath; tainted
|
|
100
|
+
* member chains (e.g. `R.current`) are tracked as strings.
|
|
101
|
+
*/
|
|
102
|
+
export const computeTaint = (ast, sourceNodes) => {
|
|
103
|
+
const taint = {
|
|
104
|
+
bindings: new Set(),
|
|
105
|
+
memberChains: new Set(),
|
|
106
|
+
sourceNodes: new Set(sourceNodes),
|
|
107
|
+
};
|
|
108
|
+
// Bound iteration count to avoid pathological cases
|
|
109
|
+
const maxRounds = 8;
|
|
110
|
+
for (let round = 0; round < maxRounds; round++) {
|
|
111
|
+
let changed = false;
|
|
112
|
+
traverse(ast, {
|
|
113
|
+
VariableDeclarator(path) {
|
|
114
|
+
if (!path.node.init)
|
|
115
|
+
return;
|
|
116
|
+
const initPath = path.get("init");
|
|
117
|
+
if (!expressionIsTainted(initPath, taint))
|
|
118
|
+
return;
|
|
119
|
+
const names = collectIdsFromPattern(path.node.id);
|
|
120
|
+
for (const name of names) {
|
|
121
|
+
const binding = path.scope.getBinding(name);
|
|
122
|
+
if (binding && !taint.bindings.has(binding.path)) {
|
|
123
|
+
taint.bindings.add(binding.path);
|
|
124
|
+
changed = true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
AssignmentExpression(path) {
|
|
129
|
+
const rightPath = path.get("right");
|
|
130
|
+
if (!expressionIsTainted(rightPath, taint))
|
|
131
|
+
return;
|
|
132
|
+
const left = path.node.left;
|
|
133
|
+
if (left.type === "Identifier") {
|
|
134
|
+
const binding = path.scope.getBinding(left.name);
|
|
135
|
+
if (binding && !taint.bindings.has(binding.path)) {
|
|
136
|
+
taint.bindings.add(binding.path);
|
|
137
|
+
changed = true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else if (left.type === "MemberExpression") {
|
|
141
|
+
const chain = memberChainString(left);
|
|
142
|
+
if (chain && !taint.memberChains.has(chain)) {
|
|
143
|
+
taint.memberChains.add(chain);
|
|
144
|
+
changed = true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else if (left.type === "ObjectPattern" || left.type === "ArrayPattern") {
|
|
148
|
+
const names = collectIdsFromPattern(left);
|
|
149
|
+
for (const name of names) {
|
|
150
|
+
const binding = path.scope.getBinding(name);
|
|
151
|
+
if (binding && !taint.bindings.has(binding.path)) {
|
|
152
|
+
taint.bindings.add(binding.path);
|
|
153
|
+
changed = true;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
if (!changed)
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
return taint;
|
|
163
|
+
};
|
|
164
|
+
const getSinkValueNodes = (sink) => {
|
|
165
|
+
switch (sink.type) {
|
|
166
|
+
case "AssignmentExpression":
|
|
167
|
+
return [sink.right];
|
|
168
|
+
case "CallExpression":
|
|
169
|
+
case "NewExpression": {
|
|
170
|
+
const args = sink.arguments;
|
|
171
|
+
return args.filter((a) => a && a.type !== "SpreadElement");
|
|
172
|
+
}
|
|
173
|
+
case "ObjectProperty": {
|
|
174
|
+
const v = sink.value;
|
|
175
|
+
return v ? [v] : [];
|
|
176
|
+
}
|
|
177
|
+
case "JSXAttribute": {
|
|
178
|
+
// Boolean JSX attributes (e.g. `<div hidden />`) have no value node.
|
|
179
|
+
const v = sink.value;
|
|
180
|
+
return v ? [v] : [];
|
|
181
|
+
}
|
|
182
|
+
default:
|
|
183
|
+
return [sink];
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Returns true when `sinkNode` consumes a value tainted by the URL source(s) used
|
|
188
|
+
* to compute `taint`. Walks the sink's value-side subtree (RHS for assignments,
|
|
189
|
+
* arguments for calls/new, value for object/JSX properties) and looks for:
|
|
190
|
+
* - direct references to a tainted source subtree,
|
|
191
|
+
* - identifiers whose binding is in `taint.bindings`,
|
|
192
|
+
* - member-expression chains in `taint.memberChains`.
|
|
193
|
+
*
|
|
194
|
+
* To resolve scope-aware bindings, we re-traverse the AST and pick up paths
|
|
195
|
+
* whose nodes match one of the value-side subtrees.
|
|
196
|
+
*/
|
|
197
|
+
export const sinkConsumesTaint = (ast, sinkNode, taint) => {
|
|
198
|
+
const valueRoots = new Set(getSinkValueNodes(sinkNode));
|
|
199
|
+
if (valueRoots.size === 0)
|
|
200
|
+
return false;
|
|
201
|
+
let consumed = false;
|
|
202
|
+
traverse(ast, {
|
|
203
|
+
enter(path) {
|
|
204
|
+
if (consumed) {
|
|
205
|
+
path.stop();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (!valueRoots.has(path.node))
|
|
209
|
+
return;
|
|
210
|
+
if (expressionIsTainted(path, taint)) {
|
|
211
|
+
consumed = true;
|
|
212
|
+
path.stop();
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
return consumed;
|
|
217
|
+
};
|
|
218
|
+
//# sourceMappingURL=taintFlow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taintFlow.js","sourceRoot":"","sources":["../../../../src/analyze/helpers/engineHelpers/taintFlow.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,7 @@ const esqueryStepSchema = z.object({
|
|
|
20
20
|
type: z.literal("esquery"),
|
|
21
21
|
query: z.string(),
|
|
22
22
|
inScopeOf: z.string().optional(),
|
|
23
|
+
taintFrom: z.string().optional(),
|
|
23
24
|
});
|
|
24
25
|
const PostMessageFuncResolverStepSchema = z.object({
|
|
25
26
|
name: z.string(),
|
|
@@ -43,7 +44,8 @@ export const ruleSchema = z.object({
|
|
|
43
44
|
name: z.string(),
|
|
44
45
|
author: z.string(),
|
|
45
46
|
description: z.string(),
|
|
46
|
-
|
|
47
|
+
js_recon_version: z.string(),
|
|
48
|
+
tech: z.array(z.enum(["next", "vue", "all"])),
|
|
47
49
|
severity: z.enum(["info", "low", "medium", "high"]),
|
|
48
50
|
type: z.enum(["request", "ast"]),
|
|
49
51
|
steps: z.array(stepSchema),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../src/analyze/helpers/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC;IAC9B,CAAC,CAAC,MAAM,CAAC;QACL,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;QAC1B,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;KACnB,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACL,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;QACtB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;KACnB,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACL,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QACzB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACnC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;KACnB,CAAC;CACL,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAEH,MAAM,iCAAiC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;CACnB,CAAC,CAAC;AAEH,MAAM,8BAA8B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC3C,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACxC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACrC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACrC,sBAAsB,EAAE,iCAAiC,CAAC,QAAQ,EAAE;IACpE,oBAAoB,EAAE,8BAA8B,CAAC,QAAQ,EAAE;CAClE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../src/analyze/helpers/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC;IAC9B,CAAC,CAAC,MAAM,CAAC;QACL,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;QAC1B,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;KACnB,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACL,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;QACtB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;KACnB,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACL,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QACzB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACnC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;KACnB,CAAC;CACL,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAEH,MAAM,iCAAiC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;CACnB,CAAC,CAAC;AAEH,MAAM,8BAA8B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC3C,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACxC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACrC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACrC,sBAAsB,EAAE,iCAAiC,CAAC,QAAQ,EAAE;IACpE,oBAAoB,EAAE,8BAA8B,CAAC,QAAQ,EAAE;CAClE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAC7C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACnD,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAChC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;CAC7B,CAAC,CAAC"}
|