Skip to content

Commit ebc1d35

Browse files
Merge pull request #108 from dreadnode/cap-1168-add-ast-grep-to-web-security-runtime-and-integrate-with-jxscout-static-analysis-skills
feat(web-security): add ast-grep to runtime for AST-based JS static a…
2 parents 92f44f3 + db45319 commit ebc1d35

5 files changed

Lines changed: 137 additions & 10 deletions

File tree

‎capabilities/web-security/capability.yaml‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
schema: 1
22
name: web-security
3-
version: "1.3.0"
3+
version: "1.4.0"
44
description: >
55
Web application penetration testing with 70+ attack technique playbooks
66
covering request smuggling, cache poisoning, SSRF, SSTI, DOM
77
vulnerabilities, authentication bypasses, parser differentials,
88
AEM/Sling exploitation, GraphQL, OAuth, and client-side attacks.
99
Includes HTTP client tooling with OOB callbacks via interactsh, Caido
1010
and Burp proxy integration via MCP, browser automation via
11-
agent-browser, JS static analysis via jxscout, protobuf inspection via
11+
agent-browser, JS static analysis via jxscout, AST-based code pattern
12+
search via ast-grep, protobuf inspection via
1213
protoscope, credential management, DNS rebinding, blind SQLi
1314
extraction, bug bounty scope lookup via bbscope, HackerOne program
1415
recon and report submission, SecurityContext vulnerability context
@@ -160,6 +161,8 @@ checks:
160161
command: 'test -f "$HOME/git/archivealchemist/archive-alchemist.py"'
161162
- name: exiftool
162163
command: command -v exiftool
164+
- name: ast-grep
165+
command: command -v ast-grep
163166
- name: jxscout
164167
command: command -v jxscout-pro-v2
165168

@@ -208,6 +211,7 @@ keywords:
208211
- browser-automation
209212
- burp-suite
210213
- jxscout
214+
- ast-grep
211215
- interactsh
212216
- oob-callbacks
213217
- securitycontext

‎capabilities/web-security/docker/Dockerfile.runtime‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
# - kiterunner (API-aware content discovery)
2323
# - surf (SSRF target identification)
2424
# - pacu (AWS exploitation framework)
25+
# - ast-grep (AST-based code pattern search via tree-sitter)
2526
#
2627
# Tools with bundled SDK/MCP integration (require a running instance
2728
# reachable by network — the client library and MCP server are included):
@@ -119,7 +120,8 @@ RUN pip install --no-cache-dir \
119120
"fastmcp>=2.0" \
120121
"httpx>=0.28" \
121122
"caido-sdk-client" \
122-
"pacu"
123+
"pacu" \
124+
"ast-grep-cli"
123125

124126
# ── fireprox (AWS API Gateway IP rotation) ──────────────────────────
125127
# Installed to a predictable path; requires AWS credentials at runtime.

‎capabilities/web-security/scripts/install_tools.sh‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ fi
119119
npm install -g agent-browser
120120
agent-browser install || true
121121

122+
# -- ast-grep (AST-based code pattern search) ---------------------------------
123+
# Tree-sitter based structural code matching for JS/TS/HTML. Lightweight
124+
# alternative to semgrep for pattern matching (no taint analysis).
125+
pip install --break-system-packages ast-grep-cli
126+
122127
# -- waymore (Wayback Machine recon) -----------------------------------------
123128
pip install --break-system-packages waymore
124129

‎capabilities/web-security/skills/dom-vulnerability-static-analysis/SKILL.md‎

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,45 @@ For DOMPurify: check version and config -- see `dompurify-mxss-bypass` skill.
6363

6464
## 4. AST-based analysis (large codebases)
6565

66-
- **Semgrep**: `semgrep --config p/javascript` for DOM XSS rules
67-
- **CodeQL**: `javascript/ql/src/Security/CWE-079` for taint tracking
66+
`rg` patterns are fragile for code constructs — they miss variations in whitespace, nesting, and comments. Use AST-based tools for structural matching.
67+
68+
### ast-grep (installed in runtime)
69+
70+
ast-grep uses tree-sitter for structural code matching. Patterns use real code syntax with `$VAR` wildcards — far more accurate than regex for function calls, assignments, and nested expressions.
71+
72+
```bash
73+
# innerHTML / outerHTML sinks — catches any receiver expression
74+
ast-grep -p '$EL.innerHTML = $VAR' -l js src/
75+
ast-grep -p '$EL.outerHTML = $VAR' -l js src/
76+
77+
# insertAdjacentHTML
78+
ast-grep -p '$EL.insertAdjacentHTML($POS, $CONTENT)' -l js src/
79+
80+
# eval-family sinks
81+
ast-grep -p 'eval($INPUT)' -l js src/
82+
ast-grep -p 'new Function($BODY)' -l js src/
83+
84+
# URL assignment sinks
85+
ast-grep -p 'location.href = $VAR' -l js src/
86+
ast-grep -p 'location.assign($URL)' -l js src/
87+
ast-grep -p 'window.open($TARGET)' -l js src/
88+
89+
# postMessage handlers (multi-line aware)
90+
ast-grep -p 'window.addEventListener("message", $HANDLER)' -l js src/
91+
92+
# React dangerouslySetInnerHTML
93+
ast-grep -p 'dangerouslySetInnerHTML={{$VAR}}' -l tsx src/
94+
95+
# jQuery .html() sink
96+
ast-grep -p '$EL.html($CONTENT)' -l js src/
97+
```
98+
99+
Add `--json` to any command for structured output with file paths, line/column positions, and captured metavariable values. This is useful for programmatic triage or feeding results into jxscout custom analyzers.
100+
101+
### Additional AST tools (if operator-installed)
102+
103+
- **Semgrep**: `semgrep --config p/javascript` for DOM XSS rules (includes taint tracking in Pro)
104+
- **CodeQL**: `javascript/ql/src/Security/CWE-079` for data-flow taint analysis
68105
- **ESLint**: `no-unsanitized/property`, `no-unsanitized/method`
69106

70107
## 5. Report findings

‎capabilities/web-security/skills/jxscout-custom-analyzers/SKILL.md‎

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ The `JXSCOUT_PROJECT_NAME` environment variable must be set. The project setting
2020

2121
## Choosing the right analyzer type
2222

23-
For JS/TS code pattern matching (function calls, assignments, data flow, control structures), **prefer AST-based analysis via script analyzers** (e.g. semgrep) over regex. Regex works for simple literal patterns -- hardcoded URLs, API keys, specific strings -- but is fragile for code constructs because it misses variations in whitespace, formatting, nesting, and comments.
23+
For JS/TS code pattern matching (function calls, assignments, data flow, control structures), **prefer AST-based analysis via script analyzers** over regex. Regex works for simple literal patterns -- hardcoded URLs, API keys, specific strings -- but is fragile for code constructs because it misses variations in whitespace, formatting, nesting, and comments.
2424

2525
Rule of thumb:
2626
- **Regex**: simple string patterns that don't depend on code structure
2727
- **Derived**: narrowing down an existing match kind by value
28-
- **Script (semgrep)**: anything involving code semantics -- function calls, assignments, data flow, missing checks
28+
- **Script (ast-grep)**: anything involving code semantics -- function calls, assignments, data flow, missing checks. Installed in the runtime, use this by default.
29+
- **Script (semgrep)**: same use case as ast-grep, with additional taint tracking in semgrep Pro. Only available if operator-installed.
2930

3031
## Analyzer types
3132

@@ -113,9 +114,87 @@ The script receives file paths on stdin (one per line) and must output a JSON ar
113114

114115
`$JXSCOUT_PROJECT_DIR` and `$JXSCOUT_PROJECT_NAME` are available as environment variables in all scripts.
115116

116-
## Using semgrep for JS analysis
117+
## Using ast-grep for JS analysis (installed in runtime)
117118

118-
When semgrep is available and you need to find JS/TS code patterns, prefer it over regex. Semgrep uses AST-based matching which is far more accurate for code patterns (function calls, assignments, data flow) than regular expressions.
119+
ast-grep uses tree-sitter for AST-based structural code matching. Patterns use real code syntax with `$VAR` wildcards -- far more accurate than regex for function calls, assignments, and nested expressions. Prefer ast-grep over regex for script analyzers.
120+
121+
### 1. Create the wrapper script
122+
123+
Create `scripts/ast_grep_to_jxscout.sh` in your project directory. This script converts ast-grep JSON output to the jxscout match format:
124+
125+
```bash
126+
#!/usr/bin/env bash
127+
set -euo pipefail
128+
129+
PATTERN=""
130+
KIND=""
131+
LANG="javascript"
132+
133+
while [[ $# -gt 0 ]]; do
134+
case $1 in
135+
-p|--pattern) PATTERN="$2"; shift 2 ;;
136+
-k|--kind) KIND="$2"; shift 2 ;;
137+
-l|--lang) LANG="$2"; shift 2 ;;
138+
*) echo "Usage: $0 -p|--pattern <pattern> -k|--kind <kind> [-l|--lang <lang>] (file paths on stdin)" >&2; exit 1 ;;
139+
esac
140+
done
141+
142+
[[ -n "$PATTERN" ]] || { echo "Missing -p|--pattern <pattern>" >&2; exit 1; }
143+
[[ -n "$KIND" ]] || { echo "Missing -k|--kind <kind>" >&2; exit 1; }
144+
145+
FILES=()
146+
while IFS= read -r line || [[ -n "$line" ]]; do
147+
[[ -n "$line" ]] && FILES+=("$line")
148+
done
149+
150+
[[ ${#FILES[@]} -gt 0 ]] || { echo "No file paths on stdin" >&2; exit 1; }
151+
152+
output=""
153+
for f in "${FILES[@]}"; do
154+
AG_JSON=$(ast-grep -p "$PATTERN" -l "$LANG" --json "$f" 2>/dev/null || echo "[]")
155+
while IFS= read -r result; do
156+
one=$(echo "$result" | jq -c \
157+
--arg kind "$KIND" \
158+
'{kind: $kind, value: .text, start: {line: (.range.start.line + 1), column: .range.start.column}, end: {line: (.range.end.line + 1), column: .range.end.column}}')
159+
output="${output}${one}"$'\n'
160+
done < <(echo "$AG_JSON" | jq -c '.[]? // empty')
161+
done
162+
163+
if [[ -z "$output" ]]; then
164+
echo "[]"
165+
else
166+
echo "$output" | jq -cs 'if . == null then [] else . end'
167+
fi
168+
```
169+
170+
Make it executable: `chmod +x scripts/ast_grep_to_jxscout.sh`
171+
172+
**Note:** ast-grep uses 0-based line numbers; the script adds 1 to align with jxscout's 1-based convention.
173+
174+
### 2. Add to project settings
175+
176+
```json
177+
{
178+
"analyzer": {
179+
"custom_analyzers": {
180+
"innerHTML_sink": {
181+
"enabled": true,
182+
"type": "script",
183+
"file_types": ["js", "reversed_source"],
184+
"script": "$JXSCOUT_PROJECT_DIR/scripts/ast_grep_to_jxscout.sh --pattern '$EL.innerHTML = $VAR' --kind innerHTML_sink"
185+
}
186+
}
187+
}
188+
}
189+
```
190+
191+
### 3. Multiple patterns
192+
193+
For analyzers that need several patterns (e.g. all eval-family sinks), create one analyzer per pattern with a shared match kind, or write a wrapper that runs ast-grep multiple times and merges the output.
194+
195+
## Using semgrep for JS analysis (if operator-installed)
196+
197+
When semgrep is available and you need taint tracking or data-flow analysis beyond structural matching, use it as a script analyzer. Semgrep is not installed in the runtime by default.
119198

120199
### 1. Create a semgrep rule
121200

@@ -304,7 +383,7 @@ jxscout auto-reloads when `settings.jsonc` changes, so the view updates immediat
304383

305384
## Workflow for adding a custom analyzer
306385

307-
1. Decide the analyzer type: regex for simple literal patterns, derived for filtering existing match kinds, script for code-semantic analysis (prefer semgrep for JS/TS when available)
386+
1. Decide the analyzer type: regex for simple literal patterns, derived for filtering existing match kinds, script for code-semantic analysis (prefer ast-grep for JS/TS structural matching; use semgrep if operator-installed and taint tracking is needed)
308387
2. Add the configuration to `settings.jsonc` under `analyzer > custom_analyzers`
309388
3. Test with `analyze` on a file that should match (create a temp test file if needed, then delete it)
310389
4. **Always** add the new match kind to the VS Code matches view -- **first ensure the full `vscode_extension` block is in `settings.jsonc`** (get it from `print-full-project-settings` if missing), then append your entry

0 commit comments

Comments
 (0)